diff --git a/.gitattributes b/.gitattributes index b89b92b39..32d68b41c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,3 @@ dist/ merge=ours application/language/**/*.php merge=ours text=auto -application/config/config.php ident -application/views/partial/footer.php ident diff --git a/.gitignore b/.gitignore index 1e0a2a352..8e3914196 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ node_modules tmp +database/database.sql +database/migrate_phppos_dist.sql application/config/email.php application/sessions/* application/logs/* diff --git a/.htaccess b/.htaccess index 4d3aa7a80..55eeab755 100755 --- a/.htaccess +++ b/.htaccess @@ -2,7 +2,8 @@ RewriteEngine On RewriteCond %{REQUEST_URI} !^public$ - RewriteRule ^(.*)$ %{REQUEST_URI}public/ [R=301,L] + RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge [NC] + RewriteRule "^(.*)$" "/public/" [R=301,L] # disable directory browsing diff --git a/.travis.yml b/.travis.yml index 602bc3d0f..71fd06881 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,19 +17,15 @@ script: - docker run --rm -v $(pwd):/app composer/composer install - docker run --rm -v $(pwd):/app -w /app lucor/php7-cli php bin/install.php translations develop + - sed -i "s/'\(dev\)'/'$rev'/g" application/config/config.php - docker run --rm -it -v $(pwd):/app -w /app digitallyseamless/nodejs-bower-grunt sh -c "npm install && bower install && grunt package" - docker-compose build env: - TAG=$(echo ${TRAVIS_BRANCH} | sed s/feature\\///) after_success: '[ -n ${DOCKER_USERNAME} ] && docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" - && docker tag opensourcepos_php "jekkos/opensourcepos:$TAG" && docker tag opensourcepos_sqlscript - jekkos/opensourcepos:sqlscript && docker push "jekkos/opensourcepos:$TAG" && docker - push jekkos/opensourcepos:sqlscript' + && docker tag opensourcepos_php "jekkos/opensourcepos:$TAG" && docker push "jekkos/opensourcepos:$TAG"' deploy: - edge: - source: travis-ci/dpl - branch: master file: deployment.json provider: bintray skip_cleanup: true diff --git a/Dockerfile b/Dockerfile index 5696ad2e9..1cf7a4f7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.0.29-apache +FROM php:7.2.13-apache MAINTAINER jekkos RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ libicu-dev \ diff --git a/INSTALL.md b/INSTALL.md index a2c7a100c..73c2e0b90 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,7 +1,7 @@ Server Requirements ------------------- -* PHP version 5.6 to 7.2 is recommended. Please note that PHP needs to have `php-gd`, `php-bcmath`, `php-intl`, `php-openssl`, `php-mbstring` and `php-curl` installed and enabled. +* PHP version 5.6 to 7.2 are supported. Please note that PHP needs to have `php-gd`, `php-bcmath`, `php-intl`, `php-openssl`, `php-mbstring` and `php-curl` installed and enabled. * MySQL 5.5, 5.6 and 5.7 are supported, also MariaDB replacement is supported and apparently offering better performance. @@ -48,7 +48,7 @@ From now on ospos can be deployed using Docker on Linux, Mac or Windows. This se ``` docker run --rm -v $(pwd):/app composer/composer install docker run --rm -v $(pwd):/app -w /app lucor/php7-cli php bin/install.php translations develop - docker run --rm -it -v $(pwd):/app -w /app digitallyseamless/nodejs-bower-grunt "sh -c npm install && bower install" + docker run --rm -it -v $(pwd):/app -w /app digitallyseamless/nodejs-bower-grunt sh -c "npm install && bower install" docker-compose build docker-compose up ``` @@ -56,32 +56,4 @@ From now on ospos can be deployed using Docker on Linux, Mac or Windows. This se Cloud install ------------- -A quick option would be to install directly to [Digitalocean](https://m.do.co/c/ac38c262507b) using their preconfigured LAMP stack. -Create a DO account first, add a droplet with preconfigured LAMP and follow the instructions for Local Install below. You will be running a provisioned VPS within minutes. - - -Cloud install using Docker --------------------------- -This installation is NOT Recommended anymore and will soon be replaced by a one click DO installation procedure. -Existing setups will keep working until the 21th of May but will need to be migrated in time in order to ensure user's safety. - - -If you want to run a quick demo of ospos or run it permanently in the cloud, then we -suggest using Docker cloud together with the DigitalOcean hosting platform. This way all the -configuration is done automatically and the install will just work. - -If you choose *DigitalOcean* [through this link](https://m.do.co/c/ac38c262507b), you will get a *$10 credit* for a first -month of uptime on the platform. A full setup will only take about 2 minutes by following steps below. - -1. Create a [Digitalocean account](https://m.do.co/c/ac38c262507b) -2. Create a [docker cloud account](https://cloud.docker.com) -3. Login to docker cloud -4. Associate your docker cloud account with your previously created digital ocean account under settings -5. Create a new node on DigitalOcean through the `Infrastructure > Nodes` tab. Fill in a name (ospos) and choose a region near to you. We recommend to choose a node with minimum 1G RAM for the whole stack -6. Click [![Deploy to Docker Cloud](https://files.cloud.docker.com/images/deploy-to-dockercloud.svg)](https://cloud.docker.com/stack/deploy/?repo=https://github.com/opensourcepos/opensourcepos) -7. Othewise create a new stack under `Applications > Stacks` and paste the [contents of docker-cloud.yml](https://github.com/opensourcepos/opensourcepos/blob/master/docker-cloud.yml) from the source repository in the text field and hit `Create and deploy` -8. Find your website url under `Infrastructure > Nodes > > Endpoints > web` -9. Login with default username/password admin/pointofsale -10. DNS name for this server can be easily configured in the DigitalOcean control panel - -More info [on maintaining a docker](https://github.com/opensourcepos/opensourcepos/wiki/Docker-cloud-maintenance) install can be found on the wiki +If you choose *DigitalOcean* [through this link](https://m.do.co/c/ac38c262507b), you will get a *$10 credit* for a first month. [Check the wiki](https://github.com/opensourcepos/opensourcepos/wiki/DOCS-USERS-Getting-Started-installations#cloud-deploy-installation) for further instructions on how to install the necessary components. diff --git a/LICENSE b/LICENSE index 882aae407..e0c8fd7a9 100644 --- a/LICENSE +++ b/LICENSE @@ -18,6 +18,10 @@ Copyright (c) 2017 Deep Shah (aka deepshah) Copyright (c) 2017 Joshua Fernandez (aka joshua1234511) Copyright (c) 2017 odiea Copyright (c) 2017 asadjaved63 +Copyright (c) 2018 Erasto Marroquin (aka Erastus) +Copyright (c) 2018 WebShells/Shady Sh +Copyright (c) 2018 Nathan Sas (aka nathanzky) +Copyright (c) 2018 Emilio Silva (aka emi-silva) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 35781784e..26c23fe15 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ +[ ![Download](https://api.bintray.com/packages/jekkos/opensourcepos/opensourcepos/images/download.svg?version=3.2.3) ](https://bintray.com/jekkos/opensourcepos/opensourcepos/3.2.3/link) [![Build Status](https://travis-ci.org/opensourcepos/opensourcepos.svg?branch=master)](https://travis-ci.org/opensourcepos/opensourcepos) -[![Join the chat at https://gitter.im/jekkos/opensourcepos](https://badges.gitter.im/jekkos/opensourcepos.svg)](https://gitter.im/jekkos/opensourcepos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/opensourcepos](https://badges.gitter.im/jekkos/opensourcepos.svg)](https://gitter.im/opensourcepos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![devDependency Status](https://david-dm.org/jekkos/opensourcepos/dev-status.svg)](https://david-dm.org/jekkos/opensourcepos#info=dev) -[![Dependency Status](https://gemnasium.com/badges/github.com/jekkos/opensourcepos.svg)](https://gemnasium.com/github.com/jekkos/opensourcepos) [![GitHub version](https://badge.fury.io/gh/jekkos%2Fopensourcepos.svg)](https://badge.fury.io/gh/jekkos%2Fopensourcepos) [![Translation status](http://weblate.jpeelaer.net/widgets/ospos/-/svg-badge.svg)](http://weblate.jpeelaer.net/engage/ospos/?utm_source=widget) @@ -30,6 +30,7 @@ The main features are: * Selectable Boostrap (Bootswatch) based UI theme * Mailchimp integration * reCAPTCHA to protect login page from brute force attacks +* GDPR ready The software is written in PHP language, it uses MySQL (or MariaDB) as data storage back-end and has a simple but intuitive user interface. @@ -39,6 +40,15 @@ It also has improved functionality and security. Deployed to a Cloud it's a SaaS (Software as a Service) solution. +DEMO +---- + +A demo version of the latest master version can be found on our [Demo server](https://demo.opensourcepos.org). This is a containerized install which will be reinitialized when new functionality is added to the code repository. + +LOGIN using +* username: admin +* password: pointofsale + Installation ------------ @@ -108,7 +118,7 @@ Bug reports must follow this schema: 2. OS name and version running your Web Server (e.g. CentOS 6.9, Ubuntu 16.4, Windows 10) 3. Web Server name and version (e.g. Apache 2.2, Apache 2.4, Nginx 1.12, Nginx 1.13) 4. Database name and version (e.g. MySQL 5.5, MySQL 5.6, MySQL 5.7, MariaDB 10.0, MariaDB 10.1, MariaDB 10.2) -5. PHP version (e.g. 5.5, 5.6, 7.0, 7.1) +5. PHP version (e.g. 5.6, 7.0, 7.1, 7.2) 6. Language selected in OSPOS (e.g. English, Spanish) 7. Any configuration of OSPOS that you changed 8. Exact steps to reproduce the issue (test case) @@ -123,7 +133,7 @@ FAQ * If you are seeing the message **system folder missing**, then you have cloned the source using git and you need to run a build *first*. Check [INSTALL.md](https://github.com/opensourcepos/opensourcepos/blob/master/INSTALL.md) for instructions or download latest zip file from [bintray](https://bintray.com/jekkos/opensourcepos/opensourcepos/view/files?sort=updated&order=desc#files) instead. -* If at login time you read "The installation is not correct, check your php.ini file.", please check the error_log in public folder to understand what's wrong and make sure you read the [INSTALL.md](https://github.com/opensourcepos/opensourcepos/blob/master/INSTALL.md). +* If at login time you read "The installation is not correct, check your php.ini file.", please check the error_log in public folder to understand what's wrong and make sure you read the [INSTALL.md](https://github.com/opensourcepos/opensourcepos/blob/master/INSTALL.md). To know how to enable error_log, please read the comment in [issue 1770](https://github.com/opensourcepos/opensourcepos/issues/1770#issuecomment-355177943). * If you installed your OSPOS under a web server subdir, please edit public/.htaccess and go to the lines with comment `if in web root` and `if in subdir comment above line, uncomment below one and replace with your path` and follow the instruction on the second comment line. If you face more issues please read [issue #920](https://github.com/opensourcepos/opensourcepos/issues/920) for more help. @@ -134,3 +144,10 @@ FAQ * If you install ospos in docker behind a proxy that performs ssloffloading, you can enable the url generated to be https instead of http, by activating the environment variable FORCE_HTTPS = 1. * If you have suhosin installed and face an issue with CSRF, please make sure you read [issue #1492](https://github.com/opensourcepos/opensourcepos/issues/1492). + +Credits +------- +|JetBrains|Travis CI| +|:-:|:-:| +|![IntelliJ IDEA](https://raw.githubusercontent.com/wiki/j-easy/easy-batch/images/logo/intellijidea-logo.png)|[Travis CI](https://travis-ci.com/images/logos/TravisCI-Full-Color.png)| +|Many thanks to [JetBrains](https://www.jetbrains.com/) for providing a free license of [IntelliJ IDEA](https://www.jetbrains.com/idea/) to kindly support the development of OSPOS|Many thanks to [Travis CI](https://travis-ci.org) for providing a free continuous integration service for open source projects.| diff --git a/WHATS_NEW.txt b/WHATS_NEW.txt index f52190af3..511642444 100644 --- a/WHATS_NEW.txt +++ b/WHATS_NEW.txt @@ -1,3 +1,19 @@ +Version 3.2.3 +------------- ++ Further revert of CSRF change causing regression ++ Code Igniter 3.1.9 upgrade + +Version 3.2.2 +------------- ++ Revert CSRF change causing regression + +Version 3.2.1 +------------- ++ Support for GDPR ++ CSRF simplifications ++ Translation upgrades ++ Various bug fixes + Version 3.2.0 ------------- + Code Igniter 3.1.8 upgrade diff --git a/application/config/autoload.php b/application/config/autoload.php index 457dc17c4..c1883aade 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -132,4 +132,32 @@ $autoload['language'] = array(); | | $autoload['model'] = array('first_model' => 'first'); */ -$autoload['model'] = array('Appconfig', 'Person', 'Customer', 'Employee', 'Module', 'Item', 'Item_taxes', 'Sale', 'Supplier', 'Inventory', 'Receiving', 'Giftcard', 'Item_kit', 'Item_kit_items', 'Stock_location', 'Item_quantity', 'Dinner_table', 'Customer_rewards', 'Rewards', 'Tax', 'Expense_category', 'Expense' ); +$autoload['model'] = array( + 'Appconfig', + 'Person', + 'Customer', + 'Employee', + 'Module', + 'Item', + 'Item_taxes', + 'Sale', + 'Supplier', + 'Inventory', + 'Receiving', + 'Giftcard', + 'Item_kit', + 'Item_kit_items', + 'Stock_location', + 'Item_quantity', + 'Dinner_table', + 'Customer_rewards', + 'Rewards', + 'Expense_category', + 'Expense', + 'Cashup', + 'Attribute', + 'Tax', + 'Tax_category', + 'Tax_code', + 'Tax_jurisdiction' +); diff --git a/application/config/config.php b/application/config/config.php index ac34b1930..9cc7a91c2 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -8,7 +8,7 @@ | | */ -$config['application_version'] = '3.2.1'; +$config['application_version'] = '3.3.0'; /* |-------------------------------------------------------------------------- @@ -19,7 +19,7 @@ $config['application_version'] = '3.2.1'; | | */ -$config['commit_sha1'] = '$Id $'; +$config['commit_sha1'] = 'dev'; /* |-------------------------------------------------------------------------- @@ -65,7 +65,7 @@ $config['db_log_enabled'] = FALSE; | a PHP script and you can easily do that on your own. | */ -$config['base_url'] = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || isset($_ENV['FORCE_HTTPS'])) ? 'https' : 'http'; +$config['base_url'] = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_ENV['FORCE_HTTPS']) && $_ENV['FORCE_HTTPS'] == 'true')) ? 'https' : 'http'; $config['base_url'] .= '://' . $_SERVER['HTTP_HOST']; $config['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); @@ -487,7 +487,7 @@ $config['csrf_token_name'] = 'csrf_ospos_v3'; $config['csrf_cookie_name'] = 'csrf_cookie_ospos_v3'; $config['csrf_expire'] = 7200; $config['csrf_regenerate'] = TRUE; -$config['csrf_exclude_uris'] = array(); +$config['csrf_exclude_uris'] = array('login'); /* |-------------------------------------------------------------------------- diff --git a/application/config/routes.php b/application/config/routes.php index 223598214..70dfe3d41 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -60,10 +60,12 @@ $route['sales/index/([^/]+)/([^/]+)/([^/]+)'] = 'sales/manage/$1/$2/$3'; $route['reports/(summary_:any)/([^/]+)/([^/]+)'] = 'reports/$1/$2/$3/$4'; $route['reports/summary_expenses_categories'] = 'reports/date_input_only'; +$route['reports/summary_discounts'] = 'reports/summary_discounts_input'; $route['reports/summary_:any'] = 'reports/date_input'; $route['reports/(graphical_:any)/([^/]+)/([^/]+)'] = 'reports/$1/$2/$3/$4'; $route['reports/graphical_summary_expenses_categories'] = 'reports/date_input_only'; +$route['reports/graphical_summary_discounts'] = 'reports/summary_discounts_input'; $route['reports/graphical_:any'] = 'reports/date_input'; $route['reports/(inventory_:any)/([^/]+)'] = 'reports/$1/$2'; diff --git a/application/controllers/Attributes.php b/application/controllers/Attributes.php new file mode 100644 index 000000000..ee2fd3e90 --- /dev/null +++ b/application/controllers/Attributes.php @@ -0,0 +1,182 @@ +xss_clean(get_attribute_definition_manage_table_headers()); + + $this->load->view('attributes/manage', $data); + } + + /* + Returns customer table data rows. This will be called with AJAX. + */ + public function search() + { + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + + $attributes = $this->Attribute->search($search, $limit, $offset, $sort, $order); + $total_rows = $this->Attribute->get_found_rows($search); + + $data_rows = array(); + foreach($attributes->result() as $attribute) + { + $attribute->definition_flags = $this->_get_attributes($attribute->definition_flags); + $data_rows[] = get_attribute_definition_data_row($attribute, $this); + } + + $data_rows = $this->xss_clean($data_rows); + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function save_attribute_value($attribute_value) + { + $success = $this->Attribute->save_value(urldecode($attribute_value), $this->input->post('definition_id'), $this->input->post('item_id'), $this->input->post('attribute_id')); + + echo json_encode(array('success' => $success != 0)); + } + + public function delete_attribute_value($attribute_value) + { + $success = $this->Attribute->delete_value($attribute_value, $this->input->post('definition_id')); + + echo json_encode(array('success' => $success)); + } + + public function save_definition($definition_id = -1) + { + + $definition_flags = 0; + + $flags = (empty($this->input->post('definition_flags'))) ? array() : $this->input->post('definition_flags'); + + foreach($flags as $flag) + { + $definition_flags |= $flag; + } + + //Save definition data + $definition_data = array( + 'definition_name' => $this->input->post('definition_name'), + 'definition_flags' => $definition_flags, + 'definition_fk' => $this->input->post('definition_group') != '' ? $this->input->post('definition_group') : NULL + ); + + if ($this->input->post('definition_type') != null) + { + $definition_data['definition_type'] = DEFINITION_TYPES[$this->input->post('definition_type')]; + } + + $definition_name = $this->xss_clean($definition_data['definition_name']); + + if($this->Attribute->save_definition($definition_data, $definition_id)) + { + //New definition + if($definition_id == -1) + { + $definition_values = json_decode($this->input->post('definition_values')); + + foreach($definition_values as $definition_value) + { + $this->Attribute->save_value($definition_value, $definition_data['definition_id']); + } + + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_adding').' '. + $definition_name, 'id' => $definition_data['definition_id'])); + } + else //Existing definition + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_updating').' '. + $definition_name, 'id' => $definition_id)); + } + } + else//failure + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attribute_definitions_error_adding_updating').' '. + $definition_name, 'id' => -1)); + } + } + + public function suggest_attribute($definition_id) + { + $suggestions = $this->xss_clean($this->Attribute->get_suggestions($definition_id, $this->input->get('term'))); + + echo json_encode($suggestions); + } + + public function get_row($row_id) + { + $attribute_definition_info = $this->Attribute->get_info($row_id); + $attribute_definition_info->definition_flags = $this->_get_attributes($attribute_definition_info->definition_flags); + $data_row = $this->xss_clean(get_attribute_definition_data_row($attribute_definition_info)); + + echo json_encode($data_row); + } + + private function _get_attributes($definition_flags = 0) + { + $definition_flag_names = array(); + foreach (Attribute::get_definition_flags() as $id => $term) + { + if (empty($definition_flags) || ($id & $definition_flags)) + { + $definition_flag_names[$id] = $this->lang->line('attributes_' . strtolower($term) . '_visibility'); + } + } + return $definition_flag_names; + } + + public function view($definition_id = -1) + { + $info = $this->Attribute->get_info($definition_id); + foreach(get_object_vars($info) as $property => $value) + { + $info->$property = $this->xss_clean($value); + } + + $data['definition_id'] = $definition_id; + $data['definition_values'] = $this->Attribute->get_definition_values($definition_id); + $data['definition_group'] = $this->Attribute->get_definitions_by_type(GROUP, $definition_id); + $data['definition_group'][''] = $this->lang->line('common_none_selected_text'); + $data['definition_info'] = $info; + + $data['definition_flags'] = $this->_get_attributes(); + $data['selected_definition_flags'] = $this->_get_attributes($info->definition_flags); + + $this->load->view("attributes/form", $data); + } + + public function delete_value($attribute_id) + { + return $this->Attribute->delete_value($attribute_id); + } + + public function delete() + { + $attributes_to_delete = $this->input->post('ids'); + + if($this->Attribute->delete_definition_list($attributes_to_delete)) + { + $message = $this->lang->line('attributes_definition_successful_deleted') . ' ' . count($attributes_to_delete) . ' ' . $this->lang->line('attributes_definition_one_or_multiple'); + echo json_encode(array('success' => TRUE, 'message' => $message)); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attributes_definition_cannot_be_deleted'))); + } + } + +} \ No newline at end of file diff --git a/application/controllers/Cashups.php b/application/controllers/Cashups.php new file mode 100644 index 000000000..c8d137759 --- /dev/null +++ b/application/controllers/Cashups.php @@ -0,0 +1,243 @@ +xss_clean(get_cashups_manage_table_headers()); + + // filters that will be loaded in the multiselect dropdown + $data['filters'] = array('is_deleted' => $this->lang->line('cashups_is_deleted')); + + $this->load->view('cashups/manage', $data); + } + + public function search() + { + $cash_up = 0; + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + $filters = array( + 'start_date' => $this->input->get('start_date'), + 'end_date' => $this->input->get('end_date'), + 'is_deleted' => FALSE); + + // check if any filter is set in the multiselect dropdown + $filledup = array_fill_keys($this->input->get('filters'), TRUE); + $filters = array_merge($filters, $filledup); + $cash_ups = $this->Cashup->search($search, $filters, $limit, $offset, $sort, $order); + $total_rows = $this->Cashup->get_found_rows($search, $filters); + $data_rows = array(); + foreach($cash_ups->result() as $cash_up) + { + $data_rows[] = $this->xss_clean(get_cash_up_data_row($cash_up)); + } + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function view($cashup_id = -1) + { + $data = array(); + + $data['employees'] = array(); + foreach($this->Employee->get_all()->result() as $employee) + { + foreach(get_object_vars($employee) as $property => $value) + { + $employee->$property = $this->xss_clean($value); + } + + $data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name; + } + + $cash_ups_info = $this->Cashup->get_info($cashup_id); + + foreach(get_object_vars($cash_ups_info) as $property => $value) + { + $cash_ups_info->$property = $this->xss_clean($value); + } + + // open cashup + if(empty($cash_ups_info->cashup_id)) + { + $cash_ups_info->open_date = date('Y-m-d H:i:s'); + $cash_ups_info->close_date = $cash_ups_info->open_date; + $cash_ups_info->open_employee_id = $this->Employee->get_logged_in_employee_info()->person_id; + $cash_ups_info->close_employee_id = $this->Employee->get_logged_in_employee_info()->person_id; + } + // if all the amounts are null or 0 that means it's a close cashup + elseif(floatval($cash_ups_info->closed_amount_cash) == 0 && + floatval($cash_ups_info->closed_amount_due) == 0 && + floatval($cash_ups_info->closed_amount_card) == 0 && + floatval($cash_ups_info->closed_amount_check) == 0) + { + // set the close date and time to the actual as this is a close session + $cash_ups_info->close_date = date('Y-m-d H:i:s'); + + // the closed amount starts with the open amount -/+ any trasferred amount + $cash_ups_info->closed_amount_cash = $cash_ups_info->open_amount_cash + $cash_ups_info->transfer_amount_cash; + + // if it's date mode only and not date & time truncate the open and end date to date only + if(empty($this->config->item('date_or_time_format'))) + { + // search for all the payments given the time range + $inputs = array('start_date' => substr($cash_ups_info->open_date, 0, 10), 'end_date' => substr($cash_ups_info->close_date, 0, 10), 'sale_type' => 'complete', 'location_id' => 'all'); + } + else + { + // search for all the payments given the time range + $inputs = array('start_date' => $cash_ups_info->open_date, 'end_date' => $cash_ups_info->close_date, 'sale_type' => 'complete', 'location_id' => 'all'); + } + + // get all the transactions payment summaries + $this->load->model('reports/Summary_payments'); + $reports_data = $this->Summary_payments->getData($inputs); + + foreach($reports_data as $row) + { + if($row['payment_type'] == $this->lang->line('sales_cash')) + { + $cash_ups_info->closed_amount_cash += $this->xss_clean($row['payment_amount']); + } + elseif($row['payment_type'] == $this->lang->line('sales_due')) + { + $cash_ups_info->closed_amount_due += $this->xss_clean($row['payment_amount']); + } + elseif($row['payment_type'] == $this->lang->line('sales_debit') || + $row['payment_type'] == $this->lang->line('sales_credit')) + { + $cash_ups_info->closed_amount_card += $this->xss_clean($row['payment_amount']); + } + elseif($row['payment_type'] == $this->lang->line('sales_check')) + { + $cash_ups_info->closed_amount_check += $this->xss_clean($row['payment_amount']); + } + } + + // lookup expenses paid in cash + $filters = array( + 'only_cash' => TRUE, + 'only_due' => FALSE, + 'only_check' => FALSE, + 'only_credit' => FALSE, + 'only_debit' => FALSE, + 'is_deleted' => FALSE); + $payments = $this->Expense->get_payments_summary('', array_merge($inputs, $filters)); + + foreach($payments as $row) + { + $cash_ups_info->closed_amount_cash -= $this->xss_clean($row['amount']); + } + + $cash_ups_info->closed_amount_total = $this->_calculate_total($cash_ups_info->open_amount_cash, $cash_ups_info->transfer_amount_cash, $cash_ups_info->closed_amount_cash, $cash_ups_info->closed_amount_due, $cash_ups_info->closed_amount_card, $cash_ups_info->closed_amount_check); + } + + $data['cash_ups_info'] = $cash_ups_info; + + $this->load->view("cashups/form", $data); + } + + public function get_row($row_id) + { + $cash_ups_info = $this->Cashup->get_info($row_id); + $data_row = $this->xss_clean(get_cash_up_data_row($cash_ups_info)); + + echo json_encode($data_row); + } + + public function save($cashup_id = -1) + { + $open_date = $this->input->post('open_date'); + $open_date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $open_date); + + $close_date = $this->input->post('close_date'); + $close_date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $close_date); + + $cash_up_data = array( + 'open_date' => $open_date_formatter->format('Y-m-d H:i:s'), + 'close_date' => $close_date_formatter->format('Y-m-d H:i:s'), + 'open_amount_cash' => parse_decimals($this->input->post('open_amount_cash')), + 'transfer_amount_cash' => parse_decimals($this->input->post('transfer_amount_cash')), + 'closed_amount_cash' => parse_decimals($this->input->post('closed_amount_cash')), + 'closed_amount_due' => parse_decimals($this->input->post('closed_amount_due')), + 'closed_amount_card' => parse_decimals($this->input->post('closed_amount_card')), + 'closed_amount_check' => parse_decimals($this->input->post('closed_amount_check')), + 'closed_amount_total' => parse_decimals($this->input->post('closed_amount_total')), + 'note' => $this->input->post('note') != NULL, + 'description' => $this->input->post('description'), + 'open_employee_id' => $this->input->post('open_employee_id'), + 'close_employee_id' => $this->input->post('close_employee_id'), + 'deleted' => $this->input->post('deleted') != NULL + ); + + if($this->Cashup->save($cash_up_data, $cashup_id)) + { + $cash_up_data = $this->xss_clean($cash_up_data); + + //New cashup_id + if($cashup_id == -1) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('cashups_successful_adding'), 'id' => $cash_up_data['cashup_id'])); + } + else // Existing Cashup + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('cashups_successful_updating'), 'id' => $cashup_id)); + } + } + else//failure + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('cashups_error_adding_updating'), 'id' => -1)); + } + } + + public function delete() + { + $cash_ups_to_delete = $this->input->post('ids'); + + if($this->Cashup->delete_list($cash_ups_to_delete)) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('cashups_successful_deleted') . ' ' . count($cash_ups_to_delete) . ' ' . $this->lang->line('cashups_one_or_multiple'), 'ids' => $cash_ups_to_delete)); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('cashups_cannot_be_deleted'), 'ids' => $cash_ups_to_delete)); + } + } + + /* + AJAX call from cashup input form to calculate the total + */ + public function ajax_cashup_total() + { + $open_amount_cash = parse_decimals($this->input->post('open_amount_cash')); + $transfer_amount_cash = parse_decimals($this->input->post('transfer_amount_cash')); + $closed_amount_cash = parse_decimals($this->input->post('closed_amount_cash')); + $closed_amount_due = parse_decimals($this->input->post('closed_amount_due')); + $closed_amount_card = parse_decimals($this->input->post('closed_amount_card')); + $closed_amount_check = parse_decimals($this->input->post('closed_amount_check')); + + $total = $this->_calculate_total($open_amount_cash, $transfer_amount_cash, $closed_amount_due, $closed_amount_cash, $closed_amount_card, $closed_amount_check); + + echo json_encode(array('total' => to_currency_no_money($total))); + } + + /* + Calculate total + */ + private function _calculate_total($open_amount_cash, $transfer_amount_cash, $closed_amount_due, $closed_amount_cash, $closed_amount_card, $closed_amount_check) + { + return ($closed_amount_cash - $open_amount_cash - $transfer_amount_cash + $closed_amount_due + $closed_amount_card + $closed_amount_check); + } +} +?> diff --git a/application/controllers/Config.php b/application/controllers/Config.php index d7beefee9..4dd1f8cae 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -198,14 +198,16 @@ class Config extends Secure_Controller { $data['stock_locations'] = $this->Stock_location->get_all()->result_array(); $data['dinner_tables'] = $this->Dinner_table->get_all()->result_array(); - $data['tax_categories'] = $this->Tax->get_all_tax_categories()->result_array(); $data['customer_rewards'] = $this->Customer_rewards->get_all()->result_array(); $data['support_barcode'] = $this->barcode_lib->get_list_barcodes(); $data['logo_exists'] = $this->config->item('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_codes'] = $this->get_tax_code_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 = $this->xss_clean($data); @@ -233,19 +235,6 @@ class Config extends Secure_Controller $this->load->view("configs/manage", $data); } - public function get_tax_code_options() - { - $tax_codes = $this->Tax->get_all_tax_codes()->result_array(); - $tax_code_options = array(); - foreach($tax_codes as $tax_code) - { - $a = $tax_code['tax_code']; - $b = $tax_code['tax_code_name']; - $tax_code_options[$a] = $b; - } - return $tax_code_options; - } - public function save_info() { $upload_success = $this->_handle_logo_upload(); @@ -285,7 +274,10 @@ class Config extends Secure_Controller { $batch_save_data = array( 'theme' => $this->input->post('theme'), + 'default_sales_discount_type' => $this->input->post('default_sales_discount_type') != NULL, 'default_sales_discount' => $this->input->post('default_sales_discount'), + 'default_receivings_discount_type' => $this->input->post('default_receivings_discount_type') != NULL, + 'default_receivings_discount' => $this->input->post('default_receivings_discount'), 'enforce_privacy' => $this->input->post('enforce_privacy'), 'receiving_calculate_average_price' => $this->input->post('receiving_calculate_average_price') != NULL, 'lines_per_page' => $this->input->post('lines_per_page'), @@ -299,16 +291,8 @@ class Config extends Secure_Controller 'suggestions_third_column' => $this->input->post('suggestions_third_column'), 'giftcard_number' => $this->input->post('giftcard_number'), 'derive_sale_quantity' => $this->input->post('derive_sale_quantity') != NULL, - 'custom1_name' => $this->input->post('custom1_name'), - 'custom2_name' => $this->input->post('custom2_name'), - 'custom3_name' => $this->input->post('custom3_name'), - 'custom4_name' => $this->input->post('custom4_name'), - 'custom5_name' => $this->input->post('custom5_name'), - 'custom6_name' => $this->input->post('custom6_name'), - 'custom7_name' => $this->input->post('custom7_name'), - 'custom8_name' => $this->input->post('custom8_name'), - 'custom9_name' => $this->input->post('custom9_name'), - 'custom10_name' => $this->input->post('custom10_name') + 'multi_pack_enabled' => $this->input->post('multi_pack_enabled') != NULL, + 'include_hsn' => $this->input->post('include_hsn') != NULL ); $this->Module->set_show_office_group($this->input->post('show_office_group') != NULL); @@ -634,85 +618,26 @@ class Config extends Secure_Controller { $this->db->trans_start(); - $customer_sales_tax_support = $this->input->post('customer_sales_tax_support') != NULL; - $batch_save_data = array( 'default_tax_1_rate' => parse_decimals($this->input->post('default_tax_1_rate')), 'default_tax_1_name' => $this->input->post('default_tax_1_name'), 'default_tax_2_rate' => parse_decimals($this->input->post('default_tax_2_rate')), 'default_tax_2_name' => $this->input->post('default_tax_2_name'), 'tax_included' => $this->input->post('tax_included') != NULL, - 'customer_sales_tax_support' => $customer_sales_tax_support, - 'default_origin_tax_code' => $this->input->post('default_origin_tax_code') + 'use_destination_based_tax' => $this->input->post('use_destination_based_tax') != NULL, + 'default_tax_code' => $this->input->post('default_tax_code'), + 'default_tax_category' => $this->input->post('default_tax_category'), + 'default_tax_jurisdiction' => $this->input->post('default_tax_jurisdiction'), + 'tax_id' => $this->input->post('tax_id') ); $success = $this->Appconfig->batch_save($batch_save_data) ? TRUE : FALSE; - $delete_rejected = FALSE; - - if($customer_sales_tax_support) - { - $array_save = array(); - foreach($this->input->post() as $key => $value) - { - if(strstr($key, 'tax_category')) - { - $tax_category_id = preg_replace("/.*?_(\d+)$/", "$1", $key); - $array_save[$tax_category_id]['tax_category'] = $value; - } - elseif(strstr($key, 'tax_group_sequence')) - { - $tax_category_id = preg_replace("/.*?_(\d+)$/", "$1", $key); - $array_save[$tax_category_id]['tax_group_sequence'] = $value; - } - } - - $not_to_delete = array(); - if(!empty($array_save)) - { - foreach($array_save as $key => $value) - { - // save or update - $category_data = array('tax_category' => $value['tax_category'], 'tax_group_sequence' => $value['tax_group_sequence']); - $this->Tax->save_tax_category($category_data, $key); - $not_to_delete[] = $key; - } - } - - // all categories not available in post will be deleted now - $deleted_categories = $this->Tax->get_all_tax_categories()->result_array(); - - foreach($deleted_categories as $tax_category => $category) - { - if(!in_array($category['tax_category_id'], $not_to_delete)) - { - $usg1 = $this->Tax->get_tax_category_usage($category['tax_category_id']); - $usg2 = $this->Item->get_tax_category_usage($category['tax_category_id']); - if(($usg1 + $usg2) == 0) - { - $this->Tax->delete_tax_category($category['tax_category_id']); - } - else - { - $delete_rejected = TRUE; - } - } - } - } $this->db->trans_complete(); $success &= $this->db->trans_status(); - $message = ''; - if($success && $delete_rejected) - { - $message = $this->lang->line('config_tax_category_used'); - $success = FALSE; - } - else - { - $message = $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'); - } + $message = $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'); echo json_encode(array( 'success' => $success, @@ -813,6 +738,7 @@ class Config extends Secure_Controller $batch_save_data = array ( 'receipt_template' => $this->input->post('receipt_template'), 'receipt_font_size' => $this->input->post('receipt_font_size'), + 'print_delay_autoreturn' => $this->input->post('print_delay_autoreturn'), 'email_receipt_check_behaviour' => $this->input->post('email_receipt_check_behaviour'), 'print_receipt_check_behaviour' => $this->input->post('print_receipt_check_behaviour'), 'receipt_show_company_name' => $this->input->post('receipt_show_company_name') != NULL, @@ -849,12 +775,13 @@ class Config extends Secure_Controller 'invoice_default_comments' => $this->input->post('invoice_default_comments'), 'invoice_email_message' => $this->input->post('invoice_email_message'), 'line_sequence' => $this->input->post('line_sequence'), - 'last_used_invoice_number' =>$this->input->post('last_used_invoice_number'), - 'last_used_quote_number' =>$this->input->post('last_used_quote_number'), + 'last_used_invoice_number' => $this->input->post('last_used_invoice_number'), + 'last_used_quote_number' => $this->input->post('last_used_quote_number'), 'quote_default_comments' => $this->input->post('quote_default_comments'), 'work_order_enable' => $this->input->post('work_order_enable') != NULL, 'work_order_format' => $this->input->post('work_order_format'), - 'last_used_work_order_number' =>$this->input->post('last_used_work_order_number') + 'last_used_work_order_number' => $this->input->post('last_used_work_order_number'), + 'invoice_type' => $this->input->post('invoice_type') ); $result = $this->Appconfig->batch_save($batch_save_data); diff --git a/application/controllers/Customers.php b/application/controllers/Customers.php index 0022eaddb..8e8ebf1f4 100644 --- a/application/controllers/Customers.php +++ b/application/controllers/Customers.php @@ -109,8 +109,6 @@ class Customers extends Persons */ public function view($customer_id = -1) { - $customer_sales_tax_support = $this->config->item('customer_sales_tax_support'); - $info = $this->Customer->get_info($customer_id); foreach(get_object_vars($info) as $property => $value) { @@ -125,9 +123,20 @@ class Customers extends Persons } $employee_info = $this->Employee->get_info($info->employee_id); - $data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name; + $data['employee'] = $this->xss_clean($employee_info->first_name . ' ' . $employee_info->last_name); + + $tax_code_info = $this->Tax_code->get_info($info->sales_tax_code_id); + $tax_code_id = $tax_code_info->tax_code_id; + + if($tax_code_info->tax_code != NULL) + { + $data['sales_tax_code_label'] = $this->xss_clean($tax_code_info->tax_code . ' ' . $tax_code_info->tax_code_name); + } + else + { + $data['sales_tax_code_label'] = ''; + } - $data['sales_tax_code_label'] = $info->sales_tax_code . ' ' . $this->Tax->get_info($info->sales_tax_code)->tax_code_name; $packages = array('' => $this->lang->line('items_none')); foreach($this->Customer_rewards->get_all()->result_array() as $row) { @@ -136,13 +145,13 @@ class Customers extends Persons $data['packages'] = $packages; $data['selected_package'] = $info->package_id; - if($customer_sales_tax_support == '1') + if($this->config->item('use_destination_based_tax') == '1') { - $data['customer_sales_tax_enabled'] = TRUE; + $data['use_destination_based_tax'] = TRUE; } else { - $data['customer_sales_tax_enabled'] = FALSE; + $data['use_destination_based_tax'] = FALSE; } // retrieve the total amount the customer spent so far together with min, max and average values @@ -247,24 +256,17 @@ class Customers extends Persons $customer_data = array( 'consent' => $this->input->post('consent') != NULL, 'account_number' => $this->input->post('account_number') == '' ? NULL : $this->input->post('account_number'), + 'tax_id' => $this->input->post('tax_id'), 'company_name' => $this->input->post('company_name') == '' ? NULL : $this->input->post('company_name'), - 'discount_percent' => $this->input->post('discount_percent') == '' ? 0.00 : $this->input->post('discount_percent'), + 'discount' => $this->input->post('discount') == '' ? 0.00 : $this->input->post('discount'), + 'discount_type' => $this->input->post('discount_type') == NULL ? PERCENT : $this->input->post('discount_type'), 'package_id' => $this->input->post('package_id') == '' ? NULL : $this->input->post('package_id'), 'taxable' => $this->input->post('taxable') != NULL, 'date' => $date_formatter->format('Y-m-d H:i:s'), - 'employee_id' => $this->input->post('employee_id') + 'employee_id' => $this->input->post('employee_id'), + 'sales_tax_code_id' => $this->input->post('sales_tax_code_id') == '' ? NULL : $this->input->post('sales_tax_code_id') ); - $tax_code = $this->input->post('sales_tax_code'); - if(!isset($tax_code)) - { - $customer_data['sales_tax_code'] = ''; - } - else - { - $customer_data['sales_tax_code'] = $tax_code; - } - if($this->Customer->save_customer($person_data, $customer_data, $customer_id)) { // save customer to Mailchimp selected list @@ -380,14 +382,15 @@ class Customers extends Persons // XSS file data sanity check $data = $this->xss_clean($data); - if(sizeof($data) >= 16) + $consent = $data[3] == '' ? 0 : 1; + + if(sizeof($data) >= 16 && $consent) { $email = strtolower($data[4]); $person_data = array( 'first_name' => $data[0], 'last_name' => $data[1], 'gender' => $data[2], - 'consent' => $data[3] == '' ? 0 : 1, 'email' => $email, 'phone_number' => $data[5], 'address_1' => $data[6], @@ -400,9 +403,13 @@ class Customers extends Persons ); $customer_data = array( + 'consent' => $consent, 'company_name' => $data[13], - 'discount_percent' => $data[15], - 'taxable' => $data[16] == '' ? 0 : 1 + 'discount' => $data[15], + 'discount_type' => $data[16], + 'taxable' => $data[17] == '' ? 0 : 1, + 'date' => date('Y-m-d H:i:s'), + 'employee_id' => $this->Employee->get_logged_in_employee_info()->person_id ); $account_number = $data[14]; diff --git a/application/controllers/Employees.php b/application/controllers/Employees.php index 3267f5c13..a1448a9bc 100644 --- a/application/controllers/Employees.php +++ b/application/controllers/Employees.php @@ -69,7 +69,7 @@ class Employees extends Persons foreach($this->Module->get_all_subpermissions()->result() as $permission) { $permission->module_id = $this->xss_clean($permission->module_id); - $permission->permission_id = $this->xss_clean($permission->permission_id); + $permission->permission_id = str_replace(' ', '_', $this->xss_clean($permission->permission_id)); $permission->grant = $this->xss_clean($this->Employee->has_grant($permission->permission_id, $person_info->person_id)); $permissions[] = $permission; @@ -121,7 +121,7 @@ class Employees extends Persons } //Password has been changed OR first time password set - if($this->input->post('password') != '') + if($this->input->post('password') != '' && ENVIRONMENT != 'testing') { $exploded = explode(":", $this->input->post('language')); $employee_data = array( diff --git a/application/controllers/Expenses.php b/application/controllers/Expenses.php index 9f852dae5..f419bf622 100644 --- a/application/controllers/Expenses.php +++ b/application/controllers/Expenses.php @@ -80,7 +80,7 @@ class Expenses extends Secure_Controller $data['expenses_info'] = $this->Expense->get_info($expense_id); - $data['expense_categories'] = array(); + $expense_categories = array(); foreach($this->Expense_category->get_all(0, 0, TRUE)->result_array() as $row) { $expense_categories[$row['expense_category_id']] = $row['category_name']; @@ -128,7 +128,7 @@ class Expenses extends Secure_Controller $expense_data = array( 'date' => $date_formatter->format('Y-m-d H:i:s'), - 'supplier_name' => $this->input->post('supplier_name'), + 'supplier_id' => $this->input->post('supplier_id') == '' ? NULL : $this->input->post('supplier_id'), 'supplier_tax_code' => $this->input->post('supplier_tax_code'), 'amount' => parse_decimals($this->input->post('amount')), 'tax_amount' => parse_decimals($this->input->post('tax_amount')), @@ -159,6 +159,13 @@ class Expenses extends Secure_Controller } } + public function ajax_check_amount() + { + $value = $this->input->post(); + $parsed_value = parse_decimals(array_pop($value)); + echo json_encode(array('success' => $parsed_value !== FALSE)); + } + public function delete() { $expenses_to_delete = $this->input->post('ids'); diff --git a/application/controllers/Giftcards.php b/application/controllers/Giftcards.php index 4b37366dd..a988361b8 100644 --- a/application/controllers/Giftcards.php +++ b/application/controllers/Giftcards.php @@ -131,7 +131,7 @@ class Giftcards extends Secure_Controller public function ajax_check_number_giftcard() { $parsed_value = parse_decimals($this->input->post('giftcard_amount')); - echo json_encode(array('success' => $parsed_value !== FALSE, 'giftcard_amount' => $parsed_value)); + echo json_encode(array('success' => $parsed_value !== FALSE, 'giftcard_amount' => to_currency_no_money($parsed_value))); } public function delete() diff --git a/application/controllers/Item_kits.php b/application/controllers/Item_kits.php index bf7e8ecd7..050689ae6 100644 --- a/application/controllers/Item_kits.php +++ b/application/controllers/Item_kits.php @@ -14,10 +14,11 @@ class Item_kits extends Secure_Controller */ private function _add_totals_to_item_kit($item_kit) { - $kit_item_info = $this->Item->get_info($item_kit->item_id); + $kit_item_info = $this->Item->get_info(isset($item_kit->kit_item_id) ? $item_kit->kit_item_id : $item_kit->item_id); $item_kit->total_cost_price = 0; - $item_kit->total_unit_price = $kit_item_info->unit_price; + $item_kit->total_unit_price = (float)$kit_item_info->unit_price; + $total_quantity = 0; foreach($this->Item_kit_items->get_info($item_kit->item_kit_id) as $item_kit_item) { @@ -32,11 +33,13 @@ class Item_kits extends Secure_Controller if($item_kit->price_option == PRICE_OPTION_ALL || ($item_kit->price_option == PRICE_OPTION_KIT_STOCK && $item_info->stock_type == HAS_STOCK )) { $item_kit->total_unit_price += $item_info->unit_price * $item_kit_item['quantity']; + $total_quantity += $item_kit_item['quantity']; } } - $discount_fraction = bcdiv($item_kit->kit_discount_percent, 100); - $item_kit->total_unit_price = $item_kit->total_unit_price - round(bcmul($item_kit->total_unit_price, $discount_fraction), totals_decimals(), PHP_ROUND_HALF_UP); + $discount_fraction = bcdiv($item_kit->kit_discount, 100); + + $item_kit->total_unit_price = $item_kit->total_unit_price - round(($item_kit->kit_discount_type == PERCENT)?bcmul($item_kit->total_unit_price, $discount_fraction): $item_kit->kit_discount, totals_decimals(), PHP_ROUND_HALF_UP); return $item_kit; } @@ -129,7 +132,8 @@ class Item_kits extends Secure_Controller $item_kit_data = array( 'name' => $this->input->post('name'), 'item_id' => $this->input->post('kit_item_id'), - 'kit_discount_percent' => $this->input->post('kit_discount_percent'), + 'kit_discount' => $this->input->post('kit_discount'), + 'kit_discount_type' => $this->input->post('kit_discount_type') == NULL ? PERCENT : $this->input->post('kit_discount_type'), 'price_option' => $this->input->post('price_option'), 'print_option' => $this->input->post('print_option'), 'description' => $this->input->post('description') diff --git a/application/controllers/Items.php b/application/controllers/Items.php index f6f7991bc..518cd2391 100644 --- a/application/controllers/Items.php +++ b/application/controllers/Items.php @@ -13,6 +13,8 @@ class Items extends Secure_Controller public function index() { + $this->session->set_userdata('allow_temp_items', 0); + $data['table_headers'] = $this->xss_clean(get_items_manage_table_headers()); $data['stock_location'] = $this->xss_clean($this->item_lib->get_item_location()); @@ -23,8 +25,9 @@ class Items extends Secure_Controller 'low_inventory' => $this->lang->line('items_low_inventory_items'), 'is_serialized' => $this->lang->line('items_serialized_items'), 'no_description' => $this->lang->line('items_no_description_items'), - 'search_custom' => $this->lang->line('items_search_custom_items'), - 'is_deleted' => $this->lang->line('items_is_deleted')); + 'search_custom' => $this->lang->line('items_search_attributes'), + 'is_deleted' => $this->lang->line('items_is_deleted'), + 'temporary' => $this->lang->line('items_temp')); $this->load->view('items/manage', $data); } @@ -42,6 +45,8 @@ class Items extends Secure_Controller $this->item_lib->set_item_location($this->input->get('stock_location')); + $definition_names = $this->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_ITEMS); + $filters = array('start_date' => $this->input->get('start_date'), 'end_date' => $this->input->get('end_date'), 'stock_location_id' => $this->item_lib->get_item_location(), @@ -50,7 +55,9 @@ class Items extends Secure_Controller 'is_serialized' => FALSE, 'no_description' => FALSE, 'search_custom' => FALSE, - 'is_deleted' => FALSE); + 'is_deleted' => FALSE, + 'temporary' => FALSE, + 'definition_ids' => array_keys($definition_names)); // check if any filter is set in the multiselect dropdown $filledup = array_fill_keys($this->input->get('filters'), TRUE); @@ -124,6 +131,15 @@ class Items extends Secure_Controller echo json_encode($suggestions); } + + public function suggest_low_sell() + { + $suggestions = $this->xss_clean($this->Item->get_low_sell_suggestions($this->input->post_get('name'))); + + echo json_encode($suggestions); + } + + public function suggest_kits() { $suggestions = $this->xss_clean($this->Item->get_kit_search_suggestions($this->input->post_get('term'), @@ -151,16 +167,6 @@ class Items extends Secure_Controller echo json_encode($suggestions); } - - /* - Gives search suggestions based on what is being searched for - */ - public function suggest_custom() - { - $suggestions = $this->xss_clean($this->Item->get_custom_suggestions($this->input->post('term'), $this->input->post('field_no'))); - - echo json_encode($suggestions); - } public function get_row($item_ids) { @@ -177,17 +183,53 @@ class Items extends Secure_Controller public function view($item_id = -1) { + if($item_id == -1) + { + $data = array(); + } + + // allow_temp_items is set in the index function of items.php or sales.php + $data['allow_temp_item'] = $this->session->userdata('allow_temp_items'); $data['item_tax_info'] = $this->xss_clean($this->Item_taxes->get_info($item_id)); $data['default_tax_1_rate'] = ''; $data['default_tax_2_rate'] = ''; - $data['item_kits_enabled'] = $this->Employee->has_grant('item_kits', $this->Employee->get_logged_in_employee_info()->person_id); + $data['item_type_disabled'] = !$this->Employee->has_grant('item_kits', $this->Employee->get_logged_in_employee_info()->person_id); + $data['definition_values'] = $this->Attribute->get_attributes_by_item($item_id); + $data['definition_names'] = $this->Attribute->get_definition_names(); + + foreach($data['definition_values'] as $definition_id => $definition) + { + unset($data['definition_names'][$definition_id]); + } $item_info = $this->Item->get_info($item_id); + foreach(get_object_vars($item_info) as $property => $value) { $item_info->$property = $this->xss_clean($value); } + if($data['allow_temp_item'] == 1) + { + if($item_id != -1) + { + if($item_info->item_type != ITEM_TEMP) + { + $data['allow_temp_item'] = 0; + } + } + } + else + { + if($item_info->item_type == ITEM_TEMP) + { + $data['allow_temp_item'] = 1; + } + } + + $use_destination_based_tax = (boolean)$this->config->item('use_destination_based_tax'); + $data['include_hsn'] = $this->config->item('include_hsn') == '1'; + if($item_id == -1) { $data['default_tax_1_rate'] = $this->config->item('default_tax_1_rate'); @@ -196,8 +238,16 @@ class Items extends Secure_Controller $item_info->receiving_quantity = 1; $item_info->reorder_level = 1; $item_info->item_type = ITEM; // standard + $item_info->item_id = $item_id; $item_info->stock_type = HAS_STOCK; - $item_info->tax_category_id = 1; // Standard + $item_info->tax_category_id = NULL; + $item_info->qty_per_pack = 1; + $item_info->pack_name = $this->lang->line('items_default_pack_name'); + $data['hsn_code'] = ''; + if($use_destination_based_tax) + { + $item_info->tax_category_id = $this->config->item('default_tax_category'); + } } $data['item_info'] = $item_info; @@ -210,23 +260,38 @@ class Items extends Secure_Controller $data['suppliers'] = $suppliers; $data['selected_supplier'] = $item_info->supplier_id; - $customer_sales_tax_support = $this->config->item('customer_sales_tax_support'); - if($customer_sales_tax_support == '1') + if($data['include_hsn']) { - $data['customer_sales_tax_enabled'] = TRUE; - $tax_categories = array(); - foreach($this->Tax->get_all_tax_categories()->result_array() as $row) - { - $tax_categories[$this->xss_clean($row['tax_category_id'])] = $this->xss_clean($row['tax_category']); - } - $data['tax_categories'] = $tax_categories; - $data['selected_tax_category'] = $item_info->tax_category_id; + $data['hsn_code'] = $item_info->hsn_code; } else { - $data['customer_sales_tax_enabled'] = FALSE; + $data['hsn_code'] = ''; + } + + if($use_destination_based_tax) + { + $data['use_destination_based_tax'] = TRUE; + $tax_categories = array(); + foreach($this->Tax_category->get_all()->result_array() as $row) + { + $tax_categories[$this->xss_clean($row['tax_category_id'])] = $this->xss_clean($row['tax_category']); + } + $tax_category = ""; + if ($item_info->tax_category_id != NULL) + { + $tax_category_info=$this->Tax_category->get_info($item_info->tax_category_id); + $tax_category= $tax_category_info->tax_category; + } + $data['tax_categories'] = $tax_categories; + $data['tax_category'] = $tax_category; + $data['tax_category_id'] = $item_info->tax_category_id; + } + else + { + $data['use_destination_based_tax'] = FALSE; $data['tax_categories'] = array(); - $data['selected_tax_category'] = ''; + $data['tax_category'] = ''; } $data['logo_exists'] = $item_info->pic_filename != ''; @@ -253,6 +318,18 @@ class Items extends Secure_Controller $data['stock_locations'] = $location_array; } + $data['selected_low_sell_item_id'] = $item_info->low_sell_item_id; + + if($item_id != -1 && $item_info->item_id != $item_info->low_sell_item_id) + { + $low_sell_item_info = $this->Item->get_info($item_info->low_sell_item_id); + $data['selected_low_sell_item'] = implode(NAME_SEPARATOR, array($low_sell_item_info->name, $low_sell_item_info->pack_name)); + } + else + { + $data['selected_low_sell_item'] = ''; + } + $this->load->view('items/form', $data); } @@ -336,6 +413,40 @@ class Items extends Secure_Controller $this->load->view('barcodes/barcode_sheet', $data); } + public function attributes($item_id) + { + $data['item_id'] = $item_id; + $definition_ids = json_decode($this->input->post('definition_ids'), TRUE); + $data['definition_values'] = $this->Attribute->get_attributes_by_item($item_id) + $this->Attribute->get_values_by_definitions($definition_ids); + $data['definition_names'] = $this->Attribute->get_definition_names(); + + foreach($data['definition_values'] as $definition_id => $definition_value) + { + $attribute_value = $this->Attribute->get_attribute_value($item_id, $definition_id); + $attribute_id = (empty($attribute_value) || empty($attribute_value->attribute_id)) ? NULL : $attribute_value->attribute_id; + $values = &$data['definition_values'][$definition_id]; + $values['attribute_id'] = $attribute_id; + $values['attribute_value'] = $attribute_value; + $values['selected_value'] = ''; + + if ($definition_value['definition_type'] == DROPDOWN) + { + $values['values'] = $this->Attribute->get_definition_values($definition_id); + $link_value = $this->Attribute->get_link_value($item_id, $definition_id); + $values['selected_value'] = (empty($link_value)) ? '' : $link_value->attribute_id; + } + + if (!empty($definition_ids[$definition_id])) + { + $values['selected_value'] = $definition_ids[$definition_id]; + } + + unset($data['definition_names'][$definition_id]); + } + + $this->load->view('attributes/item', $data); + } + public function bulk_edit() { $suppliers = array('' => $this->lang->line('items_none')); @@ -364,34 +475,57 @@ class Items extends Secure_Controller $upload_success = $this->_handle_image_upload(); $upload_data = $this->upload->data(); + $receiving_quantity = parse_decimals($this->input->post('receiving_quantity')); + $item_type = $this->input->post('item_type') == NULL ? ITEM : $this->input->post('item_type'); + + if($receiving_quantity == '0' && $item_type!= ITEM_TEMP) + { + $receiving_quantity = '1'; + } + $default_pack_name = $this->lang->line('items_default_pack_name'); + + + if ($item_id == -1) + { + // Set low_sell_item_id to -1 for a new item so that when it is saved the item will point to itself for the + // low sell item. + $low_sell_item_id = $this->input->post('low_sell_item_id') == NULL ? -1 : $this->input->post('low_sell_item_id'); + } + else + { + // On an existing item where the low sell item is not prompted for always force the item_id as the low sell item Id + $low_sell_item_id = $this->input->post('low_sell_item_id') == NULL ? $item_id : $this->input->post('low_sell_item_id'); + } + //Save item data $item_data = array( 'name' => $this->input->post('name'), 'description' => $this->input->post('description'), 'category' => $this->input->post('category'), - 'item_type' => $this->input->post('item_type') == NULL ? ITEM : $this->input->post('item_type'), + 'item_type' => $item_type, 'stock_type' => $this->input->post('stock_type') == NULL ? HAS_STOCK : $this->input->post('stock_type'), 'supplier_id' => $this->input->post('supplier_id') == '' ? NULL : $this->input->post('supplier_id'), 'item_number' => $this->input->post('item_number') == '' ? NULL : $this->input->post('item_number'), 'cost_price' => parse_decimals($this->input->post('cost_price')), 'unit_price' => parse_decimals($this->input->post('unit_price')), 'reorder_level' => parse_decimals($this->input->post('reorder_level')), - 'receiving_quantity' => parse_decimals($this->input->post('receiving_quantity')), + 'receiving_quantity' => $receiving_quantity, 'allow_alt_description' => $this->input->post('allow_alt_description') != NULL, 'is_serialized' => $this->input->post('is_serialized') != NULL, + 'qty_per_pack' => $this->input->post('qty_per_pack') == NULL ? 1 : $this->input->post('qty_per_pack'), + 'pack_name' => $this->input->post('pack_name') == NULL ? $default_pack_name : $this->input->post('pack_name'), + 'low_sell_item_id' => $low_sell_item_id, 'deleted' => $this->input->post('is_deleted') != NULL, - 'custom1' => $this->input->post('custom1') == NULL ? '' : $this->input->post('custom1'), - 'custom2' => $this->input->post('custom2') == NULL ? '' : $this->input->post('custom2'), - 'custom3' => $this->input->post('custom3') == NULL ? '' : $this->input->post('custom3'), - 'custom4' => $this->input->post('custom4') == NULL ? '' : $this->input->post('custom4'), - 'custom5' => $this->input->post('custom5') == NULL ? '' : $this->input->post('custom5'), - 'custom6' => $this->input->post('custom6') == NULL ? '' : $this->input->post('custom6'), - 'custom7' => $this->input->post('custom7') == NULL ? '' : $this->input->post('custom7'), - 'custom8' => $this->input->post('custom8') == NULL ? '' : $this->input->post('custom8'), - 'custom9' => $this->input->post('custom9') == NULL ? '' : $this->input->post('custom9'), - 'custom10' => $this->input->post('custom10') == NULL ? '' : $this->input->post('custom10') + 'hsn_code' => $this->input->post('hsn_code') == NULL ? '' : $this->input->post('hsn_code') ); + if($item_data['item_type'] == ITEM_TEMP) + { + $item_data['stock_type'] = HAS_NO_STOCK; + $item_data['receiving_quantity'] = 0; + $item_data['reorder_level'] = 0; + } + $x = $this->input->post('tax_category_id'); if(!isset($x)) { @@ -399,7 +533,7 @@ class Items extends Secure_Controller } else { - $item_data['tax_category_id'] = $this->input->post('tax_category_id'); + $item_data['tax_category_id'] = $this->input->post('tax_category_id') == '' ? NULL : $this->input->post('tax_category_id'); } if(!empty($upload_data['orig_name'])) @@ -412,8 +546,7 @@ class Items extends Secure_Controller } $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; - $cur_item_info = $this->Item->get_info($item_id); - + if($this->Item->save($item_data, $item_id)) { $success = TRUE; @@ -424,29 +557,40 @@ class Items extends Secure_Controller $item_id = $item_data['item_id']; $new_item = TRUE; } - - $items_taxes_data = array(); - $tax_names = $this->input->post('tax_names'); - $tax_percents = $this->input->post('tax_percents'); - $count = count($tax_percents); - for ($k = 0; $k < $count; ++$k) + + $use_destination_based_tax = (boolean)$this->config->item('use_destination_based_tax'); + + if(!$use_destination_based_tax) { - $tax_percentage = parse_decimals($tax_percents[$k]); - if(is_numeric($tax_percentage)) + $items_taxes_data = array(); + $tax_names = $this->input->post('tax_names'); + $tax_percents = $this->input->post('tax_percents'); + $count = count($tax_percents); + for ($k = 0; $k < $count; ++$k) { - $items_taxes_data[] = array('name' => $tax_names[$k], 'percent' => $tax_percentage); + $tax_percentage = parse_decimals($tax_percents[$k]); + if(is_numeric($tax_percentage)) + { + $items_taxes_data[] = array('name' => $tax_names[$k], 'percent' => $tax_percentage); + } } + $success &= $this->Item_taxes->save($items_taxes_data, $item_id); } - $success &= $this->Item_taxes->save($items_taxes_data, $item_id); //Save item quantity $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); foreach($stock_locations as $location) { $updated_quantity = parse_decimals($this->input->post('quantity_' . $location['location_id'])); + if($item_data['item_type'] == ITEM_TEMP) + { + $updated_quantity = 0; + } $location_detail = array('item_id' => $item_id, 'location_id' => $location['location_id'], 'quantity' => $updated_quantity); + + $item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location['location_id']); if($item_quantity->quantity != $updated_quantity || $new_item) { @@ -465,6 +609,20 @@ class Items extends Secure_Controller } } + // Save item attributes + $attribute_links = $this->input->post('attribute_links') != NULL ? $this->input->post('attribute_links') : array(); + $attribute_ids = $this->input->post('attribute_ids'); + $this->Attribute->delete_link($item_id); + foreach($attribute_links as $definition_id => $attribute_id) + { + $definition_type = $this->Attribute->get_info($definition_id)->definition_type; + if($definition_type != DROPDOWN) + { + $attribute_id = $this->Attribute->save_value($attribute_id, $definition_id, $item_id, $attribute_ids[$definition_id], $definition_type); + } + $this->Attribute->save_link($item_id, $definition_id, $attribute_id); + } + if($success && $upload_success) { $message = $this->xss_clean($this->lang->line('items_successful_' . ($new_item ? 'adding' : 'updating')) . ' ' . $item_data['name']); @@ -597,7 +755,7 @@ class Items extends Secure_Controller $tax_percents = $this->input->post('tax_percents'); $tax_updated = FALSE; $count = count($tax_percents); - for ($k = 0; $k < $count; ++$k) + for($k = 0; $k < $count; ++$k) { if(!empty($tax_names[$k]) && is_numeric($tax_percents[$k])) { @@ -652,6 +810,8 @@ class Items extends Secure_Controller public function do_excel_import() { + $non_repeating_element_count = 18; + if($_FILES['file_path']['error'] != UPLOAD_ERR_OK) { echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_failed'))); @@ -665,14 +825,13 @@ class Items extends Secure_Controller $i = 1; $failCodes = array(); - + while(($data = fgetcsv($handle)) !== FALSE) { // XSS file data sanity check $data = $this->xss_clean($data); - /* haven't touched this so old templates will work, or so I guess... */ - if(sizeof($data) >= 23) + if(sizeof($data) >= $non_repeating_element_count) { $item_data = array( 'name' => $data[1], @@ -684,16 +843,7 @@ class Items extends Secure_Controller 'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : NULL, 'allow_alt_description' => $data[12] != '' ? '1' : '0', 'is_serialized' => $data[13] != '' ? '1' : '0', - 'custom1' => $data[14], - 'custom2' => $data[15], - 'custom3' => $data[16], - 'custom4' => $data[17], - 'custom5' => $data[18], - 'custom6' => $data[19], - 'custom7' => $data[20], - 'custom8' => $data[21], - 'custom9' => $data[22], - 'custom10' => $data[23] + 'hsn_code' => $data[15] ); /* we could do something like this, however, the effectiveness of @@ -701,7 +851,7 @@ class Items extends Secure_Controller into that directory, so you really can do whatever you want, this probably needs further discussion */ - $pic_file = $data[24]; + $pic_file = $data[14]; /*if(strcmp('.htaccess', $pic_file)==0) { $pic_file=''; @@ -751,7 +901,7 @@ class Items extends Secure_Controller // array to store information if location got a quantity $allowed_locations = $this->Stock_location->get_allowed_locations(); - for($col = 25; $col < $cols; $col = $col + 2) + for($col = 16; $col < $cols; $col = $col + 2) { $location_id = $data[$col]; if(array_key_exists($location_id, $allowed_locations)) diff --git a/application/controllers/Login.php b/application/controllers/Login.php index 3b39e9f95..2c8fb8dd4 100644 --- a/application/controllers/Login.php +++ b/application/controllers/Login.php @@ -4,6 +4,7 @@ class Login extends CI_Controller { public function index() { + $this->load->library('migration'); if($this->Employee->is_logged_in()) { redirect('home'); @@ -14,6 +15,7 @@ class Login extends CI_Controller $this->form_validation->set_rules('username', 'lang:login_username', 'required|callback_login_check'); + if($this->config->item('gcaptcha_enable')) { $this->form_validation->set_rules('g-recaptcha-response', 'lang:login_gcaptcha', 'required|callback_gcaptcha_check'); @@ -41,6 +43,13 @@ class Login extends CI_Controller return FALSE; } + if (!$this->migration->is_latest()) + { + set_time_limit(1200); + // trigger any required upgrade before starting the application + $this->migration->latest(); + } + if(!$this->Employee->login($username, $password)) { $this->form_validation->set_message('login_check', $this->lang->line('login_invalid_username_and_password')); @@ -48,10 +57,6 @@ class Login extends CI_Controller return FALSE; } - // trigger any required upgrade before starting the application - $this->load->library('migration'); - $this->migration->latest(); - return TRUE; } diff --git a/application/controllers/Receivings.php b/application/controllers/Receivings.php index 5e4f0a1c2..7872eff29 100644 --- a/application/controllers/Receivings.php +++ b/application/controllers/Receivings.php @@ -93,6 +93,8 @@ class Receivings extends Secure_Controller $this->barcode_lib->parse_barcode_fields($quantity, $item_id_or_number_or_item_kit_or_receipt); $quantity = ($mode == 'receive' || $mode == 'requisition') ? $quantity : -$quantity; $item_location = $this->receiving_lib->get_stock_source(); + $discount = $this->config->item('default_receivings_discount'); + $discount_type = $this->config->item('default_receivings_discount_type'); if($mode == 'return' && $this->Receiving->is_valid_receipt($item_id_or_number_or_item_kit_or_receipt)) { @@ -100,9 +102,9 @@ class Receivings extends Secure_Controller } elseif($this->Item_kit->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt)) { - $this->receiving_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location); + $this->receiving_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location, $discount, $discount_type); } - elseif(!$this->receiving_lib->add_item($item_id_or_number_or_item_kit_or_receipt, $quantity, $item_location)) + elseif(!$this->receiving_lib->add_item($item_id_or_number_or_item_kit_or_receipt, $quantity, $item_location, $discount, $discount_type)) { $data['error'] = $this->lang->line('receivings_unable_to_add_item'); } @@ -123,11 +125,13 @@ class Receivings extends Secure_Controller $price = parse_decimals($this->input->post('price')); $quantity = parse_decimals($this->input->post('quantity')); $discount = parse_decimals($this->input->post('discount')); + $discount_type = parse_decimals($this->input->post('discount_type')); $item_location = $this->input->post('location'); + $receiving_quantity = $this->input->post('receiving_quantity'); if($this->form_validation->run() != FALSE) { - $this->receiving_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $price); + $this->receiving_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $discount_type, $price, $receiving_quantity); } else { @@ -263,8 +267,8 @@ class Receivings extends Secure_Controller foreach($this->receiving_lib->get_cart() as $item) { $this->receiving_lib->delete_item($item['line']); - $this->receiving_lib->add_item($item['item_id'], $item['quantity'], $this->receiving_lib->get_stock_destination()); - $this->receiving_lib->add_item($item['item_id'], -$item['quantity'], $this->receiving_lib->get_stock_source()); + $this->receiving_lib->add_item($item['item_id'], $item['quantity'], $this->receiving_lib->get_stock_destination(), $item['discount_type']); + $this->receiving_lib->add_item($item['item_id'], -$item['quantity'], $this->receiving_lib->get_stock_source(), $item['discount_type']); } $this->complete(); diff --git a/application/controllers/Reports.php b/application/controllers/Reports.php index 42e941c81..c4d6c760b 100644 --- a/application/controllers/Reports.php +++ b/application/controllers/Reports.php @@ -318,11 +318,60 @@ class Reports extends Secure_Controller $this->load->view('reports/tabular', $data); } - //Summary Discounts report - public function summary_discounts($start_date, $end_date, $sale_type, $location_id = 'all') + //Summary Sales Taxes report + public function summary_sales_taxes($start_date, $end_date, $sale_type, $location_id = 'all') { $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id); + $this->load->model('reports/Summary_sales_taxes'); + $model = $this->Summary_sales_taxes; + + $report_data = $model->getData($inputs); + $summary = $this->xss_clean($model->getSummaryData($inputs)); + + $tabular_data = array(); + foreach($report_data as $row) + { + $tabular_data[] = $this->xss_clean(array( + 'reporting_authority' => $row['reporting_authority'], + 'jurisdiction_name' => $row['jurisdiction_name'], + 'tax_category' => $row['tax_category'], + 'tax_rate' => $row['tax_rate'], + 'tax' => to_currency_tax($row['tax']) + )); + } + + $data = array( + 'title' => $this->lang->line('reports_sales_taxes_summary_report'), + 'subtitle' => $this->_get_subtitle_report(array('start_date' => $start_date, 'end_date' => $end_date)), + 'headers' => $this->xss_clean($model->getDataColumns()), + 'data' => $tabular_data, + 'summary_data' => $summary + ); + + $this->load->view('reports/tabular', $data); + } + + public function summary_discounts_input() + { + $data = array(); + $stock_locations = $data = $this->xss_clean($this->Stock_location->get_allowed_locations('sales')); + $stock_locations['all'] = $this->lang->line('reports_all'); + $data['stock_locations'] = array_reverse($stock_locations, TRUE); + $data['mode'] = 'sale'; + $data['discount_type_options'] = array( + '0' => $this->lang->line('reports_discount_percent'), + '1'=> $this->lang->line('reports_discount_fixed')); + $data['sale_type_options'] = $this->get_sale_type_options(); + + $this->load->view('reports/date_input', $data); + } + + //Summary Discounts report + public function summary_discounts($start_date, $end_date, $sale_type, $location_id = 'all', $discount_type=0) + { + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id,'discount_type'=>$discount_type); + $this->load->model('reports/Summary_discounts'); $model = $this->Summary_discounts; @@ -333,7 +382,8 @@ class Reports extends Secure_Controller foreach($report_data as $row) { $tabular_data[] = $this->xss_clean(array( - 'discount' => $row['discount_percent'], + 'total' => to_currency($row['total']), + 'discount' => $row['discount'], 'count' => $row['count'] )); } @@ -366,7 +416,7 @@ class Reports extends Secure_Controller $tabular_data[] = $this->xss_clean(array( 'payment_type' => $row['payment_type'], 'report_count' => $row['count'], - 'amount_tendered' => to_currency($row['payment_amount']) + 'amount_due' => to_currency($row['payment_amount']) )); } @@ -669,6 +719,40 @@ class Reports extends Secure_Controller $this->load->view('reports/graphical', $data); } + //Graphical summary sales taxes report + public function graphical_summary_sales_taxes($start_date, $end_date, $sale_type, $location_id = 'all') + { + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id); + + $this->load->model('reports/Summary_sales_taxes'); + $model = $this->Summary_sales_taxes; + + $report_data = $model->getData($inputs); + $summary = $this->xss_clean($model->getSummaryData($inputs)); + + $labels = array(); + $series = array(); + foreach($report_data as $row) + { + $row = $this->xss_clean($row); + + $labels[] = $row['jurisdiction_name']; + $series[] = array('meta' => $row['tax_rate'] . '%', 'value' => $row['tax']); + } + + $data = array( + 'title' => $this->lang->line('reports_sales_taxes_summary_report'), + 'subtitle' => $this->_get_subtitle_report(array('start_date' => $start_date, 'end_date' => $end_date)), + 'chart_type' => 'reports/graphs/pie', + 'labels_1' => $labels, + 'series_data_1' => $series, + 'summary_data_1' => $summary, + 'show_currency' => TRUE + ); + + $this->load->view('reports/graphical', $data); + } + //Graphical summary customers report public function graphical_summary_customers($start_date, $end_date, $sale_type, $location_id = 'all') { @@ -706,9 +790,9 @@ class Reports extends Secure_Controller } //Graphical summary discounts report - public function graphical_summary_discounts($start_date, $end_date, $sale_type, $location_id = 'all') + public function graphical_summary_discounts($start_date, $end_date, $sale_type, $location_id = 'all', $discount_type=0) { - $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id); + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id,'discount_type'=>$discount_type); $this->load->model('reports/Summary_discounts'); $model = $this->Summary_discounts; @@ -722,7 +806,7 @@ class Reports extends Secure_Controller { $row = $this->xss_clean($row); - $labels[] = $row['discount_percent']; + $labels[] = $row['discount']; $series[] = $row['count']; } @@ -734,7 +818,7 @@ class Reports extends Secure_Controller 'series_data_1' => $series, 'summary_data_1' => $summary, 'yaxis_title' => $this->lang->line('reports_count'), - 'xaxis_title' => $this->lang->line('reports_discount_percent'), + 'xaxis_title' => $this->lang->line('reports_discount'), 'show_currency' => FALSE ); @@ -869,7 +953,7 @@ class Reports extends Secure_Controller to_currency($drow['total']), to_currency($drow['cost']), to_currency($drow['profit']), - $drow['discount_percent'].'%')); + ($drow['discount_type'] == PERCENT)? $drow['discount'].'%':to_currency($drow['discount']))); } if(isset($report_data['rewards'][$key])) @@ -980,7 +1064,7 @@ class Reports extends Secure_Controller to_currency($drow['total']), to_currency($drow['cost']), to_currency($drow['profit']), - $drow['discount_percent'].'%')); + ($drow['discount_type'] == PERCENT)? $drow['discount'].'%':to_currency($drow['discount']))); } if(isset($report_data['rewards'][$key])) @@ -1018,6 +1102,9 @@ class Reports extends Secure_Controller $discounts[$i] = $i . '%'; } $data['specific_input_data'] = $discounts; + $data['discount_type_options'] = array( + '0' => $this->lang->line('reports_discount_percent'), + '1'=> $this->lang->line('reports_discount_fixed')); $data['sale_type_options'] = $this->get_sale_type_options(); $data = $this->xss_clean($data); @@ -1025,9 +1112,9 @@ class Reports extends Secure_Controller $this->load->view('reports/specific_input', $data); } - public function specific_discount($start_date, $end_date, $discount, $sale_type) + public function specific_discount($start_date, $end_date, $discount, $sale_type, $discount_type) { - $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'discount' => $discount, 'sale_type' => $sale_type); + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'discount' => $discount, 'sale_type' => $sale_type, 'discount_type' => $discount_type); $this->load->model('reports/Specific_discount'); $model = $this->Specific_discount; @@ -1085,7 +1172,7 @@ class Reports extends Secure_Controller to_currency($drow['total']), to_currency($drow['cost']), to_currency($drow['profit']), - $drow['discount_percent'].'%')); + ($drow['discount_type'] == PERCENT)? $drow['discount'].'%':to_currency($drow['discount']))); } if(isset($report_data['rewards'][$key])) @@ -1172,14 +1259,19 @@ class Reports extends Secure_Controller public function detailed_sales($start_date, $end_date, $sale_type, $location_id = 'all') { - $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id); + $definition_names = $this->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_SALES); + + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'sale_type' => $sale_type, 'location_id' => $location_id, 'definition_ids' => array_keys($definition_names)); $this->load->model('reports/Detailed_sales'); $model = $this->Detailed_sales; $model->create($inputs); - $headers = $this->xss_clean($model->getDataColumns()); + $columns = $model->getDataColumns(); + $columns['details'] = array_merge($columns['details'], $definition_names); + + $headers = $this->xss_clean($columns); $report_data = $model->getData($inputs); @@ -1227,7 +1319,11 @@ class Reports extends Secure_Controller { $quantity_purchased .= ' [' . $this->Stock_location->get_location_name($drow['item_location']) . ']'; } - $details_data[$row['sale_id']][] = $this->xss_clean(array( + + $attribute_values = (isset($drow['attribute_values'])) ? $drow['attribute_values'] : ''; + $attribute_values = expand_attribute_values($definition_names, $attribute_values); + + $details_data[$row['sale_id']][] = $this->xss_clean(array_merge(array( $drow['name'], $drow['category'], $drow['serialnumber'], @@ -1238,7 +1334,8 @@ class Reports extends Secure_Controller to_currency($drow['total']), to_currency($drow['cost']), to_currency($drow['profit']), - $drow['discount_percent'].'%')); + ($drow['discount_type'] == PERCENT)? $drow['discount'].'%':to_currency($drow['discount'])), $attribute_values)); + } if(isset($report_data['rewards'][$key])) @@ -1294,14 +1391,19 @@ class Reports extends Secure_Controller public function detailed_receivings($start_date, $end_date, $receiving_type, $location_id = 'all') { - $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'receiving_type' => $receiving_type, 'location_id' => $location_id); + $definition_names = $this->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_RECEIVINGS); + + $inputs = array('start_date' => $start_date, 'end_date' => $end_date, 'receiving_type' => $receiving_type, 'location_id' => $location_id, 'definition_ids' => array_keys($definition_names)); $this->load->model('reports/Detailed_receivings'); $model = $this->Detailed_receivings; $model->create($inputs); - $headers = $this->xss_clean($model->getDataColumns()); + $columns = $model->getDataColumns(); + $columns['details'] = array_merge($columns['details'], $definition_names); + + $headers = $this->xss_clean($columns); $report_data = $model->getData($inputs); $summary_data = array(); @@ -1334,13 +1436,18 @@ class Reports extends Secure_Controller { $quantity_purchased .= ' [' . $this->Stock_location->get_location_name($drow['item_location']) . ']'; } - $details_data[$row['receiving_id']][] = $this->xss_clean(array( + + $attribute_values = (isset($drow['attribute_values'])) ? $drow['attribute_values'] : ''; + $attribute_values = expand_attribute_values($definition_names, $attribute_values); + + $details_data[$row['receiving_id']][] = $this->xss_clean(array_merge(array( $drow['item_number'], $drow['name'], $drow['category'], $quantity_purchased, to_currency($drow['total']), - $drow['discount_percent'].'%')); + ($drow['discount_type'] == PERCENT)? $drow['discount'].'%':to_currency($drow['discount'])), $attribute_values)); + } } @@ -1420,6 +1527,7 @@ class Reports extends Secure_Controller 'item_name' => $row['name'], 'item_number' => $row['item_number'], 'quantity' => to_quantity_decimals($row['quantity']), + 'low_sell_quantity' => to_quantity_decimals($row['low_sell_quantity']), 'reorder_level' => to_quantity_decimals($row['reorder_level']), 'location_name' => $row['location_name'], 'cost_price' => to_currency($row['cost_price']), diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index 01388f403..731991390 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -19,6 +19,7 @@ class Sales extends Secure_Controller public function index() { + $this->session->set_userdata('allow_temp_items', 1); $this->_reload(); } @@ -135,12 +136,13 @@ class Sales extends Secure_Controller if($this->Customer->exists($customer_id)) { $this->sale_lib->set_customer($customer_id); - $discount_percent = $this->Customer->get_info($customer_id)->discount_percent; + $discount = $this->Customer->get_info($customer_id)->discount; + $discount_type = $this->Customer->get_info($customer_id)->discount_type; // apply customer default discount to items that have 0 discount - if($discount_percent != '') + if($discount != '') { - $this->sale_lib->apply_customer_discount($discount_percent); + $this->sale_lib->apply_customer_discount($discount, $discount_type); } } @@ -365,26 +367,23 @@ class Sales extends Secure_Controller { $data = array(); - $discount = 0; + $discount = $this->config->item('default_sales_discount'); + $discount_type = $this->config->item('default_sales_discount_type'); // check if any discount is assigned to the selected customer $customer_id = $this->sale_lib->get_customer(); if($customer_id != -1) { // load the customer discount if any - $discount_percent = $this->Customer->get_info($customer_id)->discount_percent; - if($discount_percent != '') + $customer_discount = $this->Customer->get_info($customer_id)->discount; + $customer_discount_type = $this->Customer->get_info($customer_id)->discount_type; + if($customer_discount != '') { - $discount = $discount_percent; + $discount = $customer_discount; + $discount_type = $customer_discount_type; } } - // if the customer discount is 0 or no customer is selected apply the default sales discount - if($discount == 0) - { - $discount = $this->config->item('default_sales_discount'); - } - $item_id_or_number_or_item_kit_or_receipt = $this->input->post('item'); $this->barcode_lib->parse_barcode_fields($quantity, $item_id_or_number_or_item_kit_or_receipt); $mode = $this->sale_lib->get_mode(); @@ -405,9 +404,10 @@ class Sales extends Secure_Controller $kit_price_option = $item_kit_info->price_option; $kit_print_option = $item_kit_info->print_option; // 0-all, 1-priced, 2-kit-only - if($item_kit_info->kit_discount_percent != 0 && $item_kit_info->kit_discount_percent > $discount) + if($item_kit_info->kit_discount != 0 && $item_kit_info->kit_discount > $discount) { - $discount = $item_kit_info->kit_discount_percent; + $discount = $item_kit_info->kit_discount; + $discount_type = $item_kit_info->kit_discount_type; } $price = NULL; @@ -415,7 +415,7 @@ class Sales extends Secure_Controller if(!empty($kit_item_id)) { - if(!$this->sale_lib->add_item($kit_item_id, $quantity, $item_location, $discount, PRICE_MODE_STANDARD)) + if(!$this->sale_lib->add_item($kit_item_id, $quantity, $item_location, $discount, $discount_type, PRICE_MODE_STANDARD)) { $data['error'] = $this->lang->line('sales_unable_to_add_item'); } @@ -427,7 +427,7 @@ class Sales extends Secure_Controller // Add item kit items to order $stock_warning = NULL; - if(!$this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location, $discount, $kit_price_option, $kit_print_option, $stock_warning)) + if(!$this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location, $discount, $discount_type, $kit_price_option, $kit_print_option, $stock_warning)) { $data['error'] = $this->lang->line('sales_unable_to_add_item'); } @@ -438,7 +438,7 @@ class Sales extends Secure_Controller } else { - if(!$this->sale_lib->add_item($item_id_or_number_or_item_kit_or_receipt, $quantity, $item_location, $discount, PRICE_MODE_STANDARD)) + if(!$this->sale_lib->add_item($item_id_or_number_or_item_kit_or_receipt, $quantity, $item_location, $discount, $discount_type, PRICE_MODE_STANDARD)) { $data['error'] = $this->lang->line('sales_unable_to_add_item'); } @@ -463,12 +463,14 @@ class Sales extends Secure_Controller $price = parse_decimals($this->input->post('price')); $quantity = parse_decimals($this->input->post('quantity')); $discount = parse_decimals($this->input->post('discount')); + $discount_type = $this->input->post('discount_type'); + $item_location = $this->input->post('location'); $discounted_total = $this->input->post('discounted_total') != '' ? $this->input->post('discounted_total') : NULL; if($this->form_validation->run() != FALSE) { - $this->sale_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $price, $discounted_total); + $this->sale_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $discount_type, $price, $discounted_total); } else { @@ -506,18 +508,29 @@ class Sales extends Secure_Controller $data = array(); $data['dinner_table'] = $this->sale_lib->get_dinner_table(); $data['cart'] = $this->sale_lib->get_cart(); + + $data['include_hsn'] = ($this->config->item('include_hsn') == '1'); $data['transaction_time'] = date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat')); $data['transaction_date'] = date($this->config->item('dateformat')); $data['show_stock_locations'] = $this->Stock_location->show_locations('sales'); $data['comments'] = $this->sale_lib->get_comment(); $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; $employee_info = $this->Employee->get_info($employee_id); - $data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name[0]; + $data['employee'] = $employee_info->first_name . ' ' . mb_substr($employee_info->last_name, 0, 1); + $data['company_info'] = implode("\n", array( $this->config->item('address'), - $this->config->item('phone'), - $this->config->item('account_number') + $this->config->item('phone') )); + if($this->config->item('account_number')) + { + $data['company_info'] .= "\n" . $this->lang->line('sales_account_number') . ": " . $this->config->item('account_number'); + } + if($this->config->item('tax_id') != '') + { + $data['company_info'] .= "\n" . $this->lang->line('sales_tax_id') . ": " . $this->config->item('tax_id'); + } + $data['invoice_number_enabled'] = $this->sale_lib->is_invoice_mode(); $data['cur_giftcard_value'] = $this->sale_lib->get_giftcard_remainder(); $data['cur_rewards_value'] = $this->sale_lib->get_rewards_remainder(); @@ -536,13 +549,15 @@ class Sales extends Secure_Controller if($customer_info != NULL) { $data["customer_comments"] = $customer_info->comments; + $data['tax_id'] = $customer_info->tax_id; } - $data['taxes'] = $this->sale_lib->get_taxes(); + $tax_details = $this->tax_lib->get_taxes($data['cart']); + $data['taxes'] = $tax_details[0]; $data['discount'] = $this->sale_lib->get_discount(); $data['payments'] = $this->sale_lib->get_payments(); // Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'payments_cover_total' - $totals = $this->sale_lib->get_totals(); + $totals = $this->sale_lib->get_totals($tax_details[0]); $data['subtotal'] = $totals['subtotal']; $data['total'] = $totals['total']; $data['payments_total'] = $totals['payment_total']; @@ -626,8 +641,11 @@ class Sales extends Secure_Controller $data['sale_status'] = COMPLETED; $sale_type = SALE_TYPE_INVOICE; + // The PHP file name is the same as the invoice_type key + $invoice_view = $this->config->item('invoice_type'); + // Save the data to the sales table - $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details); $data['sale_id'] = 'POS ' . $data['sale_id_num']; // Resort and filter cart lines for printing @@ -642,7 +660,7 @@ class Sales extends Secure_Controller else { $data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']); - $this->load->view('sales/invoice', $data); + $this->load->view('sales/'.$invoice_view, $data); $this->sale_lib->clear_all(); } } @@ -676,7 +694,7 @@ class Sales extends Secure_Controller $data['sale_status'] = SUSPENDED; $sale_type = SALE_TYPE_WORK_ORDER; - $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details); $this->sale_lib->set_suspended_id($data['sale_id_num']); $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); @@ -713,7 +731,7 @@ class Sales extends Secure_Controller $data['sale_status'] = SUSPENDED; $sale_type = SALE_TYPE_QUOTE; - $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details); $this->sale_lib->set_suspended_id($data['sale_id_num']); $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); @@ -740,7 +758,7 @@ class Sales extends Secure_Controller $sale_type = SALE_TYPE_POS; } - $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_id_num'] = $this->Sale->save($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details); $data['sale_id'] = 'POS ' . $data['sale_id_num']; @@ -853,14 +871,15 @@ class Sales extends Secure_Controller $data['customer_address'] = $customer_info->address_1; if(!empty($customer_info->zip) || !empty($customer_info->city)) { - $data['customer_location'] = $customer_info->zip . ' ' . $customer_info->city; + $data['customer_location'] = $customer_info->zip . ' ' . $customer_info->city . ', ' . $customer_info->state; } else { $data['customer_location'] = ''; } $data['customer_account_number'] = $customer_info->account_number; - $data['customer_discount_percent'] = $customer_info->discount_percent; + $data['customer_discount'] = $customer_info->discount; + $data['customer_discount_type'] = $customer_info->discount_type; $package_id = $this->Customer->get_info($customer_id)->package_id; if($package_id != NULL) { @@ -880,9 +899,17 @@ class Sales extends Secure_Controller $data['customer_info'] = implode("\n", array( $data['customer'], $data['customer_address'], - $data['customer_location'], - $data['customer_account_number'] + $data['customer_location'] )); + if($data['customer_account_number']) + { + $data['customer_info'] .= "\n" . $this->lang->line('sales_account_number') . ": " . $data['customer_account_number']; + } + if($customer_info->tax_id != '') + { + $data['customer_info'] .= "\n" . $this->lang->line('sales_tax_id') . ": " . $customer_info->tax_id; + } + $data['tax_id'] = $customer_info->tax_id; } return $customer_info; @@ -899,15 +926,17 @@ class Sales extends Secure_Controller $data['payments'] = $this->sale_lib->get_payments(); $data['selected_payment_type'] = $this->sale_lib->get_payment_type(); - $data['taxes'] = $this->sale_lib->get_taxes(); + $tax_details = $this->tax_lib->get_taxes($data['cart']); + $data['taxes'] = $this->Sale->get_sales_taxes($sale_id); $data['discount'] = $this->sale_lib->get_discount(); $data['transaction_time'] = date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($sale_info['sale_time'])); $data['transaction_date'] = date($this->config->item('dateformat'), strtotime($sale_info['sale_time'])); $data['show_stock_locations'] = $this->Stock_location->show_locations('sales'); + $data['include_hsn'] = ($this->config->item('include_hsn') == '1'); // Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'payments_cover_total' - $totals = $this->sale_lib->get_totals(); + $totals = $this->sale_lib->get_totals($tax_details[0]); $data['subtotal'] = $totals['subtotal']; $data['total'] = $totals['total']; $data['payments_total'] = $totals['payment_total']; @@ -932,7 +961,7 @@ class Sales extends Secure_Controller $data['amount_change'] = $data['amount_due'] * -1; $employee_info = $this->Employee->get_info($this->sale_lib->get_employee()); - $data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name[0]; + $data['employee'] = $employee_info->first_name . ' ' . mb_substr($employee_info->last_name, 0, 1); $this->_load_customer_data($this->sale_lib->get_customer(), $data); $data['sale_id_num'] = $sale_id; @@ -941,11 +970,20 @@ class Sales extends Secure_Controller $data['invoice_number'] = $sale_info['invoice_number']; $data['quote_number'] = $sale_info['quote_number']; $data['sale_status'] = $sale_info['sale_status']; + $data['company_info'] = implode("\n", array( $this->config->item('address'), - $this->config->item('phone'), - $this->config->item('account_number') + $this->config->item('phone') )); + if($this->config->item('account_number')) + { + $data['company_info'] .= "\n" . $this->lang->line('sales_account_number') . ": " . $this->config->item('account_number'); + } + if($this->config->item('tax_id') != '') + { + $data['company_info'] .= "\n" . $this->lang->line('sales_tax_id') . ": " . $this->config->item('tax_id'); + } + $data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']); $data['print_after_sale'] = FALSE; $data['price_work_orders'] = FALSE; @@ -976,6 +1014,9 @@ class Sales extends Secure_Controller $data['customer_required'] = $this->lang->line('sales_customer_optional'); } + $invoice_type = $this->config->item('invoice_type'); + + $data['invoice_view'] = $invoice_type; return $this->xss_clean($data); } @@ -997,14 +1038,15 @@ class Sales extends Secure_Controller $data['stock_locations'] = $this->Stock_location->get_allowed_locations('sales'); $data['stock_location'] = $this->sale_lib->get_sale_location(); $data['tax_exclusive_subtotal'] = $this->sale_lib->get_subtotal(TRUE, TRUE); - $data['taxes'] = $this->sale_lib->get_taxes(); + $tax_details = $this->tax_lib->get_taxes($data['cart']); + $data['taxes'] = $tax_details[0]; $data['discount'] = $this->sale_lib->get_discount(); $data['payments'] = $this->sale_lib->get_payments(); // sale_type (0=pos, 1=invoice, 2=work order, 3=quote, 4=return) $sale_type = $this->sale_lib->get_sale_type(); // Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'payments_cover_total' - $totals = $this->sale_lib->get_totals(); + $totals = $this->sale_lib->get_totals($tax_details[0]); $data['item_count'] = $totals['item_count']; $data['total_units'] = $totals['total_units']; $data['subtotal'] = $totals['subtotal']; @@ -1100,7 +1142,8 @@ class Sales extends Secure_Controller public function invoice($sale_id) { $data = $this->_load_sale_data($sale_id); - $this->load->view('sales/invoice', $data); + + $this->load->view('sales/'.$data['invoice_view'], $data); $this->sale_lib->clear_all(); } @@ -1274,6 +1317,10 @@ class Sales extends Secure_Controller $this->session->set_userdata('sale_id', -1); } } + else + { + $this->sale_lib->remove_temp_items(); + } $this->sale_lib->clear_all(); $this->_reload(); @@ -1315,7 +1362,7 @@ class Sales extends Secure_Controller $sale_status = SUSPENDED; $data = array(); - $sales_taxes = array(); + $sales_taxes = array(array(), array()); if($this->Sale->save($sale_id, $sale_status, $cart, $customer_id, $employee_id, $comment, $invoice_number, $work_order_number, $quote_number, $sale_type, $payments, $dinner_table, $sales_taxes) == '-1') { $data['error'] = $this->lang->line('sales_unsuccessfully_suspended_sale'); @@ -1387,6 +1434,58 @@ class Sales extends Secure_Controller return $filtered_cart; } -} + public function change_item_number() + { + $item_id = $this->input->post('item_id'); + $item_number = $this->input->post('item_number'); + $this->Item->update_item_number($item_id, $item_number); + $cart = $this->sale_lib->get_cart(); + $x = $this->search_cart_for_item_id($item_id, $cart); + if($x != NULL) + { + $cart[$x]['item_number'] = $item_number; + } + $this->sale_lib->set_cart($cart); + } + + public function change_item_name() + { + $item_id = $this->input->post('item_id'); + $name = $this->input->post('item_name'); + $this->Item->update_item_name($item_id, $name); + $cart = $this->sale_lib->get_cart(); + $x = $this->search_cart_for_item_id($item_id, $cart); + if($x != NULL) { + $cart[$x]['name'] = $name; + } + $this->sale_lib->set_cart($cart); + } + + public function change_item_description() + { + $item_id = $this->input->post('item_id'); + $description = $this->input->post('item_description'); + $this->Item->update_item_description($item_id, $description); + $cart = $this->sale_lib->get_cart(); + $x = $this->search_cart_for_item_id($item_id, $cart); + if($x != NULL) + { + $cart[$x]['description'] = $description; + } + $this->sale_lib->set_cart($cart); + } + + function search_cart_for_item_id($id, $array) + { + foreach($array as $key => $val) + { + if ($val['item_id'] === $id) + { + return $key; + } + } + return NULL; + } +} ?> diff --git a/application/controllers/Suppliers.php b/application/controllers/Suppliers.php index b07218866..82fa95975 100644 --- a/application/controllers/Suppliers.php +++ b/application/controllers/Suppliers.php @@ -43,7 +43,9 @@ class Suppliers extends Persons $data_rows = array(); foreach($suppliers->result() as $supplier) { - $data_rows[] = $this->xss_clean(get_supplier_data_row($supplier)); + $row = $this->xss_clean(get_supplier_data_row($supplier)); + $row['category'] = $this->Supplier->get_category_name($row['category']); + $data_rows[] = $row; } echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); @@ -77,6 +79,7 @@ class Suppliers extends Persons $info->$property = $this->xss_clean($value); } $data['person_info'] = $info; + $data['categories'] = $this->Supplier->get_categories(); $this->load->view("suppliers/form", $data); } @@ -112,7 +115,9 @@ class Suppliers extends Persons $supplier_data = array( 'company_name' => $this->input->post('company_name'), 'agency_name' => $this->input->post('agency_name'), - 'account_number' => $this->input->post('account_number') == '' ? NULL : $this->input->post('account_number') + 'category' => $this->input->post('category'), + 'account_number' => $this->input->post('account_number') == '' ? NULL : $this->input->post('account_number'), + 'tax_id' => $this->input->post('tax_id') == '' ? NULL : $this->input->post('tax_id') ); if($this->Supplier->save_supplier($person_data, $supplier_data, $supplier_id)) diff --git a/application/controllers/Tax_categories.php b/application/controllers/Tax_categories.php new file mode 100644 index 000000000..952b166df --- /dev/null +++ b/application/controllers/Tax_categories.php @@ -0,0 +1,100 @@ +xss_clean(get_tax_categories_table_headers()); + + $this->load->view('taxes/tax_categories', $data); + } + + /* + * Returns tax_category table data rows. This will be called with AJAX. + */ + public function search() + { + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + + $tax_categories = $this->Tax_category->search($search, $limit, $offset, $sort, $order); + $total_rows = $this->Tax_category->get_found_rows($search); + + $data_rows = array(); + foreach($tax_categories->result() as $tax_category) + { + $data_rows[] = $this->xss_clean(get_tax_category_data_row($tax_category)); + } + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function get_row($row_id) + { + $data_row = $this->xss_clean(get_tax_category_data_row($this->Tax_category->get_info($row_id))); + + echo json_encode($data_row); + } + + public function view($tax_category_id = -1) + { + $data['tax_category_info'] = $this->Tax_category->get_info($tax_category_id); + + $this->load->view("taxes/tax_category_form", $data); + } + + + public function save($tax_category_id = -1) + { + $tax_category_data = array( + 'tax_category' => $this->input->post('tax_category'), + 'tax_category_code' => $this->input->post('tax_category_code'), + 'tax_group_sequence' => $this->input->post('tax_group_sequence') + ); + + if($this->Tax_category->save($tax_category_data, $tax_category_id)) + { + $tax_category_data = $this->xss_clean($tax_category_data); + + // New tax_category_id + if($tax_category_id == -1) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_categories_successful_adding'), 'id' => $tax_category_data['tax_category_id'])); + } + else + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_categories_successful_updating'), 'id' => $tax_category_id)); + } + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_categories_error_adding_updating') . ' ' . $tax_category_data['tax_category'], 'id' => -1)); + } + } + + public function delete() + { + $tax_categories_to_delete = $this->input->post('ids'); + + if($this->Tax_category->delete_list($tax_categories_to_delete)) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_categories_successful_deleted') . ' ' . count($tax_categories_to_delete) . ' ' . $this->lang->line('taxes_categories_one_or_multiple'))); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_categories_cannot_be_deleted'))); + } + } +} +?> diff --git a/application/controllers/Tax_codes.php b/application/controllers/Tax_codes.php new file mode 100644 index 000000000..af21db696 --- /dev/null +++ b/application/controllers/Tax_codes.php @@ -0,0 +1,104 @@ +load->view('taxes/tax_codes',get_data()); + } + + public function get_data() + { + $data['table_headers'] = $this->xss_clean(get_tax_codes_table_headers()); + return $data; + } + + /* + * Returns tax_category table data rows. This will be called with AJAX. + */ + public function search() + { + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + + $tax_codes = $this->Tax_code->search($search, $limit, $offset, $sort, $order); + $total_rows = $this->Tax_code->get_found_rows($search); + + $data_rows = array(); + foreach($tax_codes->result() as $tax_code) + { + $data_rows[] = $this->xss_clean(get_tax_code_data_row($tax_code)); + } + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function get_row($row_id) + { + $data_row = $this->xss_clean(get_tax_code_data_row($this->Tax_code->get_info($row_id))); + + echo json_encode($data_row); + } + + public function view($tax_code_id = -1) + { + $data['tax_code_info'] = $this->Tax_code->get_info($tax_code_id); + + $this->load->view("taxes/tax_code_form", $data); + } + + + public function save($tax_code_id = -1) + { + $tax_code_data = array( + 'tax_code' => $this->input->post('tax_code'), + 'tax_code_name' => $this->input->post('tax_code_name'), + 'city' => $this->input->post('city'), + 'state' => $this->input->post('state') + ); + + if($this->Tax_code->save($tax_code_data)) + { + $tax_code_data = $this->xss_clean($tax_code_data); + + if($tax_code_id == -1) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_codes_successful_adding'), 'id' => $tax_code_data['tax_code_id'])); + } + else + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_codes_successful_updating'), 'id' => $tax_code_id)); + } + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_codes_error_adding_updating') . ' ' . $tax_code_data['tax_code_id'], 'id' => -1)); + } + } + + public function delete() + { + $tax_codes_to_delete = $this->input->post('ids'); + + if($this->Tax_code->delete_list($tax_codes_to_delete)) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_codes_successful_deleted') . ' ' . count($tax_codes_to_delete) . ' ' . $this->lang->line('taxes_codes_one_or_multiple'))); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_codes_cannot_be_deleted'))); + } + } +} +?> diff --git a/application/controllers/Tax_jurisdictions.php b/application/controllers/Tax_jurisdictions.php new file mode 100644 index 000000000..7059f7bcf --- /dev/null +++ b/application/controllers/Tax_jurisdictions.php @@ -0,0 +1,98 @@ +xss_clean(get_tax_jurisdictions_table_headers()); + + $this->load->view('taxes/tax_jurisdictions', $data); + } + + /* + * Returns tax_category table data rows. This will be called with AJAX. + */ + public function search() + { + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + + $tax_jurisdictions = $this->Tax_jurisdiction->search($search, $limit, $offset, $sort, $order); + $total_rows = $this->Tax_jurisdiction->get_found_rows($search); + + $data_rows = array(); + foreach($tax_jurisdictions->result() as $tax_jurisdiction) + { + $data_rows[] = $this->xss_clean(get_tax_jurisdiction_data_row($tax_jurisdiction)); + } + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function get_row($row_id) + { + $data_row = $this->xss_clean(get_tax_jurisdiction_data_row($this->Tax_jurisdiction->get_info($row_id))); + + echo json_encode($data_row); + } + + public function view($tax_jurisdiction_id = -1) + { + $data['tax_jurisdiction_info'] = $this->Tax_jurisdiction->get_info($tax_jurisdiction_id); + + $this->load->view("taxes/tax_jurisdiction_form", $data); + } + + + public function save($jurisdiction_id = -1) + { + $tax_jurisdiction_data = array( + 'jurisdiction_name' => $this->input->post('jurisdiction_name'), + 'reporting_authority' => $this->input->post('reporting_authority') + ); + + if($this->Tax_jurisdiction->save($tax_jurisdiction_data)) + { + $tax_jurisdiction_data = $this->xss_clean($tax_jurisdiction_data); + + if($jurisdiction_id == -1) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_jurisdictions_successful_adding'), 'id' => $tax_jurisdiction_data['jurisdiction_id'])); + } + else + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_jurisdictions_successful_updating'), 'id' => $jurisdiction_id)); + } + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_jurisdictions_error_adding_updating') . ' ' . $tax_jurisdiction_data['jurisdiction_name'], 'id' => -1)); + } + } + + public function delete() + { + $tax_jurisdictions_to_delete = $this->input->post('ids'); + + if($this->Tax_jurisdiction->delete_list($tax_jurisdictions_to_delete)) + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_jurisdictions_successful_deleted') . ' ' . count($tax_jurisdictions_to_delete) . ' ' . $this->lang->line('taxes_jurisdictions_one_or_multiple'))); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_jurisdictions_cannot_be_deleted'))); + } + } +} +?> diff --git a/application/controllers/Taxes.php b/application/controllers/Taxes.php index f02734674..873bb7b95 100644 --- a/application/controllers/Taxes.php +++ b/application/controllers/Taxes.php @@ -9,16 +9,46 @@ class Taxes extends Secure_Controller parent::__construct('taxes'); $this->load->model('enums/Rounding_mode'); - + $this->load->library('tax_lib'); + $this->load->helper('tax_helper'); } public function index() { - $data['table_headers'] = $this->xss_clean(get_taxes_manage_table_headers()); + $data['tax_codes'] = $this->xss_clean($this->Tax_code->get_all()->result_array()); + if (count($data['tax_codes']) == 0) + { + $data['tax_codes'] = $this->Tax_code->get_empty_row(); + } + $data['tax_categories'] = $this->xss_clean($this->Tax_category->get_all()->result_array()); + if (count($data['tax_categories']) == 0) + { + $data['tax_categories'] = $this->Tax_category->get_empty_row(); + } + $data['tax_jurisdictions'] = $this->xss_clean($this->Tax_jurisdiction->get_all()->result_array()); + if (count($data['tax_jurisdictions']) == 0) + { + $data['tax_jurisdictions'] = $this->Tax_jurisdiction->get_empty_row(); + } + $data['tax_rate_table_headers'] = $this->xss_clean(get_tax_rates_manage_table_headers()); + $data['tax_categories_table_headers'] = $this->xss_clean(get_tax_categories_table_headers()); + $data['tax_types'] = $this->tax_lib->get_tax_types(); + + if($this->config->item('tax_included') == '1') + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_INCLUDED; + } + else + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_EXCLUDED; + } + + $data['tax_type_options'] = $this->tax_lib->get_tax_type_options($data['default_tax_type']); $this->load->view('taxes/manage', $data); } + /* Returns tax_codes table data rows. This will be called with AJAX. */ @@ -30,14 +60,14 @@ class Taxes extends Secure_Controller $sort = $this->input->get('sort'); $order = $this->input->get('order'); - $tax_codes = $this->Tax->search($search, $limit, $offset, $sort, $order); + $tax_rates = $this->Tax->search($search, $limit, $offset, $sort, $order); $total_rows = $this->Tax->get_found_rows($search); $data_rows = array(); - foreach($tax_codes->result() as $tax_code_row) + foreach($tax_rates->result() as $tax_rate_row) { - $data_rows[] = $this->xss_clean(get_tax_data_row($tax_code_row)); + $data_rows[] = $this->xss_clean(get_tax_rates_data_row($tax_rate_row)); } echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); @@ -58,7 +88,7 @@ class Taxes extends Secure_Controller */ public function suggest_tax_categories() { - $suggestions = $this->xss_clean($this->Tax->get_tax_category_suggestions($this->input->post('term'))); + $suggestions = $this->xss_clean($this->Tax_category->get_tax_category_suggestions($this->input->post('term'))); echo json_encode($suggestions); } @@ -66,12 +96,12 @@ class Taxes extends Secure_Controller public function get_row($row_id) { - $data_row = $this->xss_clean(get_tax_codes_data_row($this->Tax->get_info($row_id), $this)); + $data_row = $this->xss_clean(get_tax_rates_data_row($this->Tax->get_info($row_id), $this)); echo json_encode($data_row); } - public function view($tax_code = -1) + public function view_tax_codes($tax_code = -1) { $tax_code_info = $this->Tax->get_info($tax_code); @@ -80,6 +110,15 @@ class Taxes extends Secure_Controller $tax_rate_info = $this->Tax->get_rate_info($tax_code, $default_tax_category_id); + if($this->config->item('tax_included') == '1') + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_INCLUDED; + } + else + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_EXCLUDED; + } + $data['rounding_options'] = Rounding_mode::get_rounding_options(); $data['html_rounding_options'] = $this->get_html_rounding_options(); @@ -114,21 +153,197 @@ class Taxes extends Secure_Controller $data = $this->xss_clean($data); - $tax_code_rates = array(); + $tax_rates = array(); foreach($this->Tax->get_tax_code_rate_exceptions($tax_code) as $tax_code_rate) { - $tax_code_row = array(); - $tax_code_row['rate_tax_category_id'] = $this->xss_clean($tax_code_rate['rate_tax_category_id']); - $tax_code_row['tax_category'] = $this->xss_clean($tax_code_rate['tax_category']); - $tax_code_row['tax_rate'] = $this->xss_clean($tax_code_rate['tax_rate']); - $tax_code_row['rounding_code'] = $this->xss_clean($tax_code_rate['rounding_code']); + $tax_rate_row = array(); + $tax_rate_row['rate_tax_category_id'] = $this->xss_clean($tax_code_rate['rate_tax_category_id']); + $tax_rate_row['tax_category'] = $this->xss_clean($tax_code_rate['tax_category']); + $tax_rate_row['tax_rate'] = $this->xss_clean($tax_code_rate['tax_rate']); + $tax_rate_row['rounding_code'] = $this->xss_clean($tax_code_rate['rounding_code']); - $tax_code_rates[] = $tax_code_row; + $tax_rates[] = $tax_rate_row; } - $data['tax_code_rates'] = $tax_code_rates; + $data['tax_rates'] = $tax_rates; - $this->load->view("taxes/form", $data); + $this->load->view('taxes/tax_code_form', $data); + } + + + public function view($tax_rate_id = -1) + { + + $tax_rate_info = $this->Tax->get_info($tax_rate_id); + + $data['tax_rate_id'] = $tax_rate_id; + $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(); + + if($tax_rate_id == -1) + { + $data['rate_tax_code_id'] = $this->config->item('default_tax_code'); + $data['rate_tax_category_id'] = $this->config->item('default_tax_category'); + $data['rate_jurisdiction_id'] = $this->config->item('default_tax_jurisdiction'); + $data['tax_rounding_code'] = Rounding_mode::HALF_UP; + $data['tax_rate'] = '0.0000'; + } + else + { + $data['rate_tax_code_id'] = $tax_rate_info->rate_tax_code_id; + $data['rate_tax_code'] = $tax_rate_info->tax_code; + $data['rate_tax_category_id'] = $tax_rate_info->rate_tax_category_id; + $data['rate_jurisdiction_id'] = $tax_rate_info->rate_jurisdiction_id; + $data['tax_rounding_code'] = $tax_rate_info->tax_rounding_code; + $data['tax_rate'] = $tax_rate_info->tax_rate; + } + + $data = $this->xss_clean($data); + + $this->load->view('taxes/tax_rates_form', $data); + } + + + + public function view_tax_categories($tax_code = -1) + { + $tax_code_info = $this->Tax->get_info($tax_code); + + $default_tax_category_id = 1; // Tax category id is always the default tax category + $default_tax_category = $this->Tax->get_tax_category($default_tax_category_id); + + $tax_rate_info = $this->Tax->get_rate_info($tax_code, $default_tax_category_id); + + $data['rounding_options'] = Rounding_mode::get_rounding_options(); + $data['html_rounding_options'] = $this->get_html_rounding_options(); + + if($this->config->item('tax_included') == '1') + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_INCLUDED; + } + else + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_EXCLUDED; + } + + if($tax_code == -1) + { + $data['tax_code'] = ''; + $data['tax_code_name'] = ''; + $data['tax_code_type'] = '0'; + $data['city'] = ''; + $data['state'] = ''; + $data['tax_rate'] = '0.0000'; + $data['rate_tax_code'] = ''; + $data['rate_tax_category_id'] = 1; + $data['tax_category'] = ''; + $data['add_tax_category'] = ''; + $data['rounding_code'] = '0'; + } + else + { + $data['tax_code'] = $tax_code; + $data['tax_code_name'] = $tax_code_info->tax_code_name; + $data['tax_code_type'] = $tax_code_info->tax_code_type; + $data['city'] = $tax_code_info->city; + $data['state'] = $tax_code_info->state; + $data['rate_tax_code'] = $tax_code_info->rate_tax_code; + $data['rate_tax_category_id'] = $tax_code_info->rate_tax_category_id; + $data['tax_category'] = $tax_code_info->tax_category; + $data['add_tax_category'] = ''; + $data['tax_rate'] = $tax_rate_info->tax_rate; + $data['rounding_code'] = $tax_rate_info->rounding_code; + } + + $data = $this->xss_clean($data); + + $tax_rates = array(); + foreach($this->Tax->get_tax_code_rate_exceptions($tax_code) as $tax_code_rate) + { + $tax_rate_row = array(); + $tax_rate_row['rate_tax_category_id'] = $this->xss_clean($tax_code_rate['rate_tax_category_id']); + $tax_rate_row['tax_category'] = $this->xss_clean($tax_code_rate['tax_category']); + $tax_rate_row['tax_rate'] = $this->xss_clean($tax_code_rate['tax_rate']); + $tax_rate_row['rounding_code'] = $this->xss_clean($tax_code_rate['rounding_code']); + + $tax_rates[] = $tax_rate_row; + } + + $data['tax_rates'] = $tax_rates; + + $this->load->view('taxes/tax_category_form', $data); + } + + public function view_tax_jurisdictions($tax_code = -1) + { + $tax_code_info = $this->Tax->get_info($tax_code); + + $default_tax_category_id = 1; // Tax category id is always the default tax category + $default_tax_category = $this->Tax->get_tax_category($default_tax_category_id); + + $tax_rate_info = $this->Tax->get_rate_info($tax_code, $default_tax_category_id); + + $data['rounding_options'] = Rounding_mode::get_rounding_options(); + $data['html_rounding_options'] = $this->get_html_rounding_options(); + + if($this->config->item('tax_included') == '1') + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_INCLUDED; + } + else + { + $data['default_tax_type'] = Tax_lib::TAX_TYPE_EXCLUDED; + } + + if($tax_code == -1) + { + $data['tax_code'] = ''; + $data['tax_code_name'] = ''; + $data['tax_code_type'] = '0'; + $data['city'] = ''; + $data['state'] = ''; + $data['tax_rate'] = '0.0000'; + $data['rate_tax_code'] = ''; + $data['rate_tax_category_id'] = 1; + $data['tax_category'] = ''; + $data['add_tax_category'] = ''; + $data['rounding_code'] = '0'; + } + else + { + $data['tax_code'] = $tax_code; + $data['tax_code_name'] = $tax_code_info->tax_code_name; + $data['tax_code_type'] = $tax_code_info->tax_code_type; + $data['city'] = $tax_code_info->city; + $data['state'] = $tax_code_info->state; + $data['rate_tax_code'] = $tax_code_info->rate_tax_code; + $data['rate_tax_category_id'] = $tax_code_info->rate_tax_category_id; + $data['tax_category'] = $tax_code_info->tax_category; + $data['add_tax_category'] = ''; + $data['tax_rate'] = $tax_rate_info->tax_rate; + $data['rounding_code'] = $tax_rate_info->rounding_code; + } + + $data = $this->xss_clean($data); + + $tax_rates = array(); + foreach($this->Tax->get_tax_code_rate_exceptions($tax_code) as $tax_code_rate) + { + $tax_rate_row = array(); + $tax_rate_row['rate_tax_category_id'] = $this->xss_clean($tax_code_rate['rate_tax_category_id']); + $tax_rate_row['tax_category'] = $this->xss_clean($tax_code_rate['tax_category']); + $tax_rate_row['tax_rate'] = $this->xss_clean($tax_code_rate['tax_rate']); + $tax_rate_row['rounding_code'] = $this->xss_clean($tax_code_rate['rounding_code']); + + $tax_rates[] = $tax_rate_row; + } + + $data['tax_rates'] = $tax_rates; + + $this->load->view('taxes/tax_jurisdiction_form', $data); } public static function get_html_rounding_options() @@ -136,63 +351,37 @@ class Taxes extends Secure_Controller return Rounding_mode::get_html_rounding_options(); } - public function save($tax_code = -1) + public function save($tax_rate_id = -1) { - $entered_tax_code = $this->xss_clean($this->input->post('tax_code')); - $tax_code_data = array( - 'tax_code' => strtoupper($this->input->post('tax_code')), - 'tax_code_name' => $this->input->post('tax_code_name'), - 'tax_code_type' => $this->input->post('tax_code_type'), - 'city' => $this->input->post('city'), - 'state' => $this->input->post('state')); + $tax_category_id = $this->input->post('rate_tax_category_id'); + $tax_rate = parse_decimals($this->input->post('tax_rate')); + + if ($tax_rate == 0) { + $tax_category_info = $this->Tax_category->get_info($tax_category_id); + } $tax_rate_data = array( - 'rate_tax_code' => $this->input->post('tax_code'), - 'rate_tax_category_id' => 1, - 'tax_rate' => parse_decimals($this->input->post('tax_rate')), - 'rounding_code' => $this->input->post('rounding_code') + 'rate_tax_code_id' => $this->input->post('rate_tax_code_id'), + 'rate_tax_category_id' => $this->input->post('rate_tax_category_id'), + 'rate_jurisdiction_id' => $this->input->post('rate_jurisdiction_id'), + 'tax_rate' => $tax_rate, + 'tax_rounding_code' => $this->input->post('tax_rounding_code') ); - if($this->Tax->save($tax_code_data, $tax_rate_data, $tax_code)) + if($this->Tax->save($tax_rate_data, $tax_rate_id)) { - $tax_code_rate_exceptions = array(); - if(!empty($this->input->post('exception_tax_rate'))) + if($tax_rate_id == -1) { - foreach($this->input->post('exception_tax_rate') as $tax_category_id => $exception_tax_rate) - { - $exception_rounding_code = $this->input->post('exception_rounding_code[' . $tax_category_id . ']'); - $tax_code_rate_exceptions[] = array( - 'rate_tax_code' => $entered_tax_code, - 'rate_tax_category_id' => $tax_category_id, - 'tax_rate' => $exception_tax_rate, - 'rounding_code' => $exception_rounding_code - ); - } - } - - if(!empty($tax_code_rate_exceptions)) - { - $success = $this->Tax->save_tax_rate_exceptions($tax_code_rate_exceptions, $entered_tax_code); - } - - $tax_code_data = $this->xss_clean($tax_code_data); - - //New tax_code record - if($tax_code == -1) - { - echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_tax_code_successfully_added') . ' ' . $entered_tax_code)); + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_tax_rate_successfully_added'))); } else //Existing tax_code { - echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_tax_code_successful_updated') . ' ' . $entered_tax_code)); + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('taxes_tax_rate_successful_updated'))); } } - else //failure + else { - $tax_code_data = $this->xss_clean($tax_code_data); - - echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_tax_code_error_adding_updating') . ' ' . - $entered_tax_code)); + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('taxes_tax_rate_error_adding_updating'))); } } @@ -209,12 +398,130 @@ class Taxes extends Secure_Controller } } - public function suggest_sales_tax_codes() + public function suggest_tax_codes() { - $suggestions = $this->xss_clean($this->Tax->get_sales_tax_codes_search_suggestions($this->input->post_get('term'))); + $suggestions = $this->xss_clean($this->Tax_code->get_tax_codes_search_suggestions($this->input->post_get('term'))); echo json_encode($suggestions); } + + public function save_tax_codes() + { + $tax_code_id = $this->input->post('tax_code_id'); + $tax_code = $this->input->post('tax_code'); + $tax_code_name = $this->input->post('tax_code_name'); + $tax_code_id = $this->input->post('tax_code_id'); + $city = $this->input->post('city'); + $state = $this->input->post('state'); + + $array_save = array(); + foreach($tax_code_id as $key=>$val) + { + $array_save[] = array('tax_code_id'=>$this->xss_clean($val), 'tax_code'=>$this->xss_clean($tax_code[$key]), + 'tax_code_name'=>$this->xss_clean($tax_code_name[$key]), 'tax_code_id'=>$this->xss_clean($tax_code_id[$key]), + 'city'=>$this->xss_clean($city[$key]), 'state'=>$this->xss_clean($state[$key])); + } + + $success = $this->Tax_code->save_tax_codes($array_save); + + echo json_encode(array( + 'success' => $success, + 'message' => $this->lang->line('taxes_tax_codes_saved_' . ($success ? '' : 'un') . 'successfully') + )); + } + + public function save_tax_jurisdictions() + { + $jurisdiction_id = $this->input->post('jurisdiction_id'); + $jurisdiction_name = $this->input->post('jurisdiction_name'); + $tax_group = $this->input->post('tax_group'); + $tax_type = $this->input->post('tax_type'); + $reporting_authority = $this->input->post('reporting_authority'); + $tax_group_sequence = $this->input->post('tax_group_sequence'); + $cascade_sequence = $this->input->post('cascade_sequence'); + + $array_save = array(); + + foreach($jurisdiction_id as $key => $val) + { + $array_save[] = array( + 'jurisdiction_id'=>$this->xss_clean($val), + 'jurisdiction_name'=>$this->xss_clean($jurisdiction_name[$key]), + 'tax_group'=>$this->xss_clean($tax_group[$key]), + 'tax_type'=>$this->xss_clean($tax_type[$key]), + 'reporting_authority'=>$this->xss_clean($reporting_authority[$key]), + 'tax_group_sequence'=>$this->xss_clean($tax_group_sequence[$key]), + 'cascade_sequence'=>$this->xss_clean($cascade_sequence[$key])); + } + + $success = $this->Tax_jurisdiction->save_jurisdictions($array_save); + + echo json_encode(array( + 'success' => $success, + 'message' => $this->lang->line('taxes_tax_jurisdictions_saved_' . ($success ? '' : 'un') . 'successfully') + )); + } + + public function save_tax_categories() + { + $tax_category_id = $this->input->post('tax_category_id'); + $tax_category = $this->input->post('tax_category'); + $tax_group_sequence = $this->input->post('tax_group_sequence'); + + $array_save= array(); + + foreach($tax_category_id as $key => $val) + { + $array_save[] = array( + 'tax_category_id'=>$this->xss_clean($val), + 'tax_category'=>$this->xss_clean($tax_category[$key]), + 'tax_group_sequence'=>$this->xss_clean($tax_group_sequence[$key])); + } + + $success = $this->Tax_category->save_categories($array_save); + + echo json_encode(array( + 'success' => $success, + 'message' => $this->lang->line('taxes_tax_categories_saved_' . ($success ? '' : 'un') . 'successfully') + )); + } + + public function ajax_tax_codes() + { + $tax_codes = $this->Tax_code->get_all()->result_array(); + + $tax_codes = $this->xss_clean($tax_codes); + + $this->load->view('partial/tax_codes', array('tax_codes' => $tax_codes)); + } + + public function ajax_tax_categories() + { + $tax_categories = $this->Tax_category->get_all()->result_array(); + + $tax_categories = $this->xss_clean($tax_categories); + + $this->load->view('partial/tax_categories', array('tax_categories' => $tax_categories)); + } + + public function ajax_tax_jurisdictions() + { + $tax_jurisdictions = $this->Tax_jurisdiction->get_all()->result_array(); + + if($this->config->item('tax_included') == '1') + { + $default_tax_type = Tax_lib::TAX_TYPE_INCLUDED; + } + else + { + $default_tax_type = Tax_lib::TAX_TYPE_EXCLUDED; + } + + $tax_jurisdictions = $this->xss_clean($tax_jurisdictions); + $tax_types = $this->tax_lib->get_tax_types(); + + $this->load->view('partial/tax_jurisdictions', array('tax_jurisdictions' => $tax_jurisdictions, 'tax_types' => $tax_types, 'default_tax_type' => $default_tax_type)); + } } ?> diff --git a/application/helpers/locale_helper.php b/application/helpers/locale_helper.php index fc392bee4..665d24266 100644 --- a/application/helpers/locale_helper.php +++ b/application/helpers/locale_helper.php @@ -1,35 +1,49 @@ Employee; + // Returns the language code of the employee if set or system language code if not - if(get_instance()->Employee->is_logged_in() && $load_system_language != TRUE) + if($employee->is_logged_in() && $load_system_language != TRUE) { - $employee_language_code = get_instance()->Employee->get_logged_in_employee_info()->language_code; - if($employee_language_code != NULL && $employee_language_code != '') + $employee_info = $employee->get_logged_in_employee_info(); + + if(property_exists($employee_info, 'language_code') && !empty($employee_info->language_code)) { - return $employee_language_code; + return $employee_info->language_code; } } - return get_instance()->config->item('language_code'); + + $language_code = get_instance()->config->item('language_code'); + return empty($language_code) ? DEFAULT_LANGUAGE_CODE : $language_code; } function current_language($load_system_language = FALSE) { + $employee = get_instance()->Employee; + // Returns the language of the employee if set or system language if not - if(get_instance()->Employee->is_logged_in() && $load_system_language != TRUE) + if($employee->is_logged_in() && $load_system_language != TRUE) { - $employee_language = get_instance()->Employee->get_logged_in_employee_info()->language; - if($employee_language != NULL && $employee_language != '') + $employee_info = $employee->get_logged_in_employee_info(); + if(property_exists($employee_info, 'language') && !empty($employee_info->language)) { - return $employee_language; + return $employee_info->language; } } - return get_instance()->config->item('language'); + + $language = get_instance()->config->item('language'); + return empty($language) ? DEFAULT_LANGUAGE : $language; } function get_languages() @@ -57,24 +71,27 @@ function get_languages() 'th:thai' => 'Thai', 'tr:turkish' => 'Turkish', 'vi:vietnamese' => 'Vietnamese', - 'zh:simplified-chinese' => 'Chinese' + 'zh-Hans:simplified-chinese' => 'Chinese Simplified Script', + 'zh-Hant:traditional-chinese' => 'Chinese Traditional Script' ); } function load_language($load_system_language = FALSE, array $lang_array) { + $lang = get_instance()->lang; + if($load_system_language = TRUE) { foreach($lang_array as $language_file) { - get_instance()->lang->load($language_file,current_language_code(TRUE)); + $lang->load($language_file, current_language_code(TRUE)); } } else { foreach($lang_array as $language_file) { - get_instance()->lang->load($language_file,current_language_code()); + $lang->load($language_file, current_language_code()); } } } @@ -95,10 +112,11 @@ function get_timezones() 'America/Chihuahua' => '(GMT-07:00) Chihuahua, La Paz, Mazatlan', 'America/Dawson_Creek' => '(GMT-07:00) Arizona', 'America/Belize' => '(GMT-06:00) Saskatchewan, Central America', - 'America/Cancun' => '(GMT-06:00) Guadalajara, Mexico City, Monterrey', + 'America/Mexico_City' => '(GMT-06:00) Guadalajara, Mexico City, Monterrey', 'Chile/EasterIsland' => '(GMT-06:00) Easter Island', 'America/Chicago' => '(GMT-06:00) Central Time (US & Canada)', 'America/New_York' => '(GMT-05:00) Eastern Time (US & Canada)', + 'America/Cancun' => '(GMT-05:00) Cancun', 'America/Havana' => '(GMT-05:00) Cuba', 'America/Bogota' => '(GMT-05:00) Bogota, Lima, Quito, Rio Branco', 'America/Caracas' => '(GMT-04:30) Caracas', @@ -198,6 +216,62 @@ function get_timeformats() ); } + +/* +Gets the payment options +*/ +function get_payment_options() +{ + $config = get_instance()->config; + $lang = get_instance()->lang; + + $payments = array(); + + + if($config->item('payment_options_order') == 'debitcreditcash') + { + $payments[$lang->line('sales_debit')] = $lang->line('sales_debit'); + $payments[$lang->line('sales_credit')] = $lang->line('sales_credit'); + $payments[$lang->line('sales_cash')] = $lang->line('sales_cash'); + } + elseif($config->item('payment_options_order') == 'debitcashcredit') + { + $payments[$lang->line('sales_debit')] = $lang->line('sales_debit'); + $payments[$lang->line('sales_cash')] = $lang->line('sales_cash'); + $payments[$lang->line('sales_credit')] = $lang->line('sales_credit'); + } + elseif($config->item('payment_options_order') == 'creditdebitcash') + { + $payments[$lang->line('sales_credit')] = $lang->line('sales_credit'); + $payments[$lang->line('sales_debit')] = $lang->line('sales_debit'); + $payments[$lang->line('sales_cash')] = $lang->line('sales_cash'); + } + elseif($config->item('payment_options_order') == 'creditcashdebit') + { + $payments[$lang->line('sales_credit')] = $lang->line('sales_credit'); + $payments[$lang->line('sales_cash')] = $lang->line('sales_cash'); + $payments[$lang->line('sales_debit')] = $lang->line('sales_debit'); + } + else // default: if($config->item('payment_options_order') == 'cashdebitcredit') + { + $payments[$lang->line('sales_cash')] = $lang->line('sales_cash'); + $payments[$lang->line('sales_debit')] = $lang->line('sales_debit'); + $payments[$lang->line('sales_credit')] = $lang->line('sales_credit'); + } + + $payments[$lang->line('sales_due')] = $lang->line('sales_due'); + $payments[$lang->line('sales_check')] = $lang->line('sales_check'); + + // If India (list of country codes include India) then include Unified Payment Interface + if (stripos(get_instance()->config->item('country_codes'), 'IN') !== false) + { + $payments[$lang->line('sales_upi')] = $lang->line('sales_upi'); + } + + + return $payments; +} + function currency_side() { $config = get_instance()->config; @@ -236,6 +310,13 @@ function tax_decimals() return $config->item('tax_decimals') ? $config->item('tax_decimals') : 0; } +function to_datetime($datetime) +{ + $config = get_instance()->config; + + return date($config->item('dateformat') . ' ' . $config->item('timeformat'), $datetime); +} + function to_currency($number) { return to_decimals($number, 'currency_decimals', \NumberFormatter::CURRENCY); @@ -250,13 +331,13 @@ function to_currency_tax($number) { $config = get_instance()->config; - if($config->item('customer_sales_tax_support') == '1') + if($config->item('tax_included') == '1') { - return to_decimals($number, 'currency_decimals', \NumberFormatter::CURRENCY); + return to_decimals($number, 'tax_decimals', \NumberFormatter::CURRENCY); } else { - return to_decimals($number, 'tax_decimals', \NumberFormatter::CURRENCY); + return to_decimals($number, 'currency_decimals', \NumberFormatter::CURRENCY); } } diff --git a/application/helpers/tabular_helper.php b/application/helpers/tabular_helper.php index 9e1101983..ef8e298f8 100644 --- a/application/helpers/tabular_helper.php +++ b/application/helpers/tabular_helper.php @@ -274,6 +274,7 @@ function get_suppliers_manage_table_headers() array('people.person_id' => $CI->lang->line('common_id')), array('company_name' => $CI->lang->line('suppliers_company_name')), array('agency_name' => $CI->lang->line('suppliers_agency_name')), + array('category' => $CI->lang->line('suppliers_category')), array('last_name' => $CI->lang->line('common_last_name')), array('first_name' => $CI->lang->line('common_first_name')), array('email' => $CI->lang->line('common_email')), @@ -300,6 +301,7 @@ function get_supplier_data_row($supplier) 'people.person_id' => $supplier->person_id, 'company_name' => $supplier->company_name, 'agency_name' => $supplier->agency_name, + 'category' => $supplier->category, 'last_name' => $supplier->last_name, 'first_name' => $supplier->first_name, 'email' => empty($supplier->email) ? '' : mailto($supplier->email, $supplier->email), @@ -319,6 +321,8 @@ function get_items_manage_table_headers() { $CI =& get_instance(); + $definition_names = $CI->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_ITEMS); + $headers = array( array('items.item_id' => $CI->lang->line('common_id')), array('item_number' => $CI->lang->line('items_item_number')), @@ -327,12 +331,27 @@ function get_items_manage_table_headers() array('company_name' => $CI->lang->line('suppliers_company_name')), array('cost_price' => $CI->lang->line('items_cost_price')), array('unit_price' => $CI->lang->line('items_unit_price')), - array('quantity' => $CI->lang->line('items_quantity')), - array('tax_percents' => $CI->lang->line('items_tax_percents'), 'sortable' => FALSE), - array('item_pic' => $CI->lang->line('items_image'), 'sortable' => FALSE), - array('inventory' => ''), - array('stock' => '') + array('quantity' => $CI->lang->line('items_quantity')) ); + if ($CI->config->item('use_destination_based_tax') == '1') + { + $headers[] = array('tax_percents' => $CI->lang->line('items_tax_category'), 'sortable' => FALSE); + } + else + { + $headers[] = array('tax_percents' => $CI->lang->line('items_tax_percents'), 'sortable' => FALSE); + + } + + $headers[] = array('item_pic' => $CI->lang->line('items_image'), 'sortable' => FALSE); + + foreach($definition_names as $definition_id => $definition_name) + { + $headers[] = array($definition_id => $definition_name); + } + + $headers[] = array('inventory' => ''); + $headers[] = array('stock' => ''); return transform_headers($headers); } @@ -343,14 +362,32 @@ Get the html data row for the item function get_item_data_row($item) { $CI =& get_instance(); - $item_tax_info = $CI->Item_taxes->get_info($item->item_id); - $tax_percents = ''; - foreach($item_tax_info as $tax_info) + + if ($CI->config->item('use_destination_based_tax') == '1') { - $tax_percents .= to_tax_decimals($tax_info['percent']) . '%, '; + if ($item->tax_category_id == NULL) + { + $tax_percents = '-'; + } + else + { + $tax_category_info = $CI->Tax_category->get_info($item->tax_category_id); + $tax_percents = $tax_category_info->tax_category; + } } - // remove ', ' from last item - $tax_percents = substr($tax_percents, 0, -2); + else + { + $item_tax_info = $CI->Item_taxes->get_info($item->item_id); + $tax_percents = ''; + foreach($item_tax_info as $tax_info) + { + $tax_percents .= to_tax_decimals($tax_info['percent']) . '%, '; + } + // remove ', ' from last item + $tax_percents = substr($tax_percents, 0, -2); + $tax_percents = !$tax_percents ? '-' : $tax_percents; + } + $controller_name = strtolower(get_class($CI)); $image = NULL; @@ -374,7 +411,14 @@ function get_item_data_row($item) } } - return array ( + if ($CI->config->item('multi_pack_enabled') == '1') + { + $item->name .= NAME_SEPARATOR . $item->pack_name; + } + + $definition_names = $CI->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_ITEMS); + + $columns = array ( 'items.item_id' => $item->item_id, 'item_number' => $item->item_number, 'name' => $item->name, @@ -384,7 +428,10 @@ function get_item_data_row($item) 'unit_price' => to_currency($item->unit_price), 'quantity' => to_quantity_decimals($item->quantity), 'tax_percents' => !$tax_percents ? '-' : $tax_percents, - 'item_pic' => $image, + 'item_pic' => $image + ); + + $icons = array( 'inventory' => anchor($controller_name."/inventory/$item->item_id", '', array('class' => 'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title' => $CI->lang->line($controller_name.'_count')) ), @@ -393,7 +440,11 @@ function get_item_data_row($item) ), 'edit' => anchor($controller_name."/view/$item->item_id", '', array('class' => 'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title' => $CI->lang->line($controller_name.'_update')) - )); + ) + ); + + $attribute_values = (property_exists($item, 'attribute_values')) ? $item->attribute_values : ""; + return $columns + expand_attribute_values($definition_names, $attribute_values) + $icons; } @@ -434,51 +485,6 @@ function get_giftcard_data_row($giftcard) )); } - -/* -Get the header for the taxes tabular view -*/ -function get_taxes_manage_table_headers() -{ - $CI =& get_instance(); - - $headers = array( - array('tax_code' => $CI->lang->line('taxes_tax_code')), - array('tax_code_name' => $CI->lang->line('taxes_tax_code_name')), - array('tax_code_type_name' => $CI->lang->line('taxes_tax_code_type')), - array('tax_rate' => $CI->lang->line('taxes_tax_rate')), - array('rounding_code_name' => $CI->lang->line('taxes_rounding_code')), - array('city' => $CI->lang->line('common_city')), - array('state' => $CI->lang->line('common_state')) - ); - - return transform_headers($headers); -} - -/* -Get the html data row for the tax -*/ -function get_tax_data_row($tax_code_row) -{ - $CI =& get_instance(); - $controller_name=strtolower(get_class($CI)); - - return array ( - 'tax_code' => $tax_code_row->tax_code, - 'tax_code_name' => $tax_code_row->tax_code_name, - 'tax_code_type' => $tax_code_row->tax_code_type, - 'tax_rate' => $tax_code_row->tax_rate, - 'rounding_code' =>$tax_code_row->rounding_code, - 'tax_code_type_name' => $CI->Tax->get_tax_code_type_name($tax_code_row->tax_code_type), - 'rounding_code_name' => Rounding_mode::get_rounding_code_name($tax_code_row->rounding_code), - 'city' => $tax_code_row->city, - 'state' => $tax_code_row->state, - 'edit' => anchor($controller_name."/view/$tax_code_row->tax_code", '', - array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) - )); -} - - /* Get the header for the item kits tabular view */ @@ -516,6 +522,69 @@ function get_item_kit_data_row($item_kit) )); } +function expand_attribute_values($definition_names, $attribute_values) +{ + $values = explode('|', $attribute_values); + + $indexed_values = array(); + foreach($values as $attribute_value) + { + $exploded_value = explode(':', $attribute_value); + $indexed_values[$exploded_value[0]] = isset($exploded_value[1]) ? $exploded_value[1] : '-'; + } + + $attribute_values = array(); + foreach($definition_names as $definition_id => $definition_name) + { + $attribute_value = isset($indexed_values[$definition_id]) ? $indexed_values[$definition_id] : '-'; + $attribute_values["$definition_id"] = $attribute_value; + } + return $attribute_values; +} + +function get_attribute_definition_manage_table_headers() +{ + $CI =& get_instance(); + + $headers = array( + array('definition_id' => $CI->lang->line('attributes_definition_id')), + array('definition_name' => $CI->lang->line('attributes_definition_name')), + array('definition_type' => $CI->lang->line('attributes_definition_type')), + array('definition_flags' => $CI->lang->line('attributes_definition_flags')), + array('definition_group' => $CI->lang->line('attributes_definition_group')), + ); + + return transform_headers($headers); +} + +function get_attribute_definition_data_row($attribute) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + + if (count($attribute->definition_flags) == 0) + { + $definition_flags = $CI->lang->line('common_none_selected_text'); + } + else if ($attribute->definition_type == GROUP) + { + $definition_flags = "-"; + } + else + { + $definition_flags = implode(', ', $attribute->definition_flags); + } + + return array ( + 'definition_id' => $attribute->definition_id, + 'definition_name' => $attribute->definition_name, + 'definition_type' => $attribute->definition_type, + 'definition_group' => $attribute->definition_group, + 'definition_flags' => $definition_flags, + 'edit' => anchor("$controller_name/view/$attribute->definition_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} /* Get the header for the expense categories tabular view @@ -567,14 +636,14 @@ function get_expenses_manage_table_headers() array('payment_type' => $CI->lang->line('expenses_payment')), array('category_name' => $CI->lang->line('expenses_categories_name')), array('description' => $CI->lang->line('expenses_description')), - array('createdBy' => $CI->lang->line('expenses_employee')) + array('created_by' => $CI->lang->line('expenses_employee')) ); return transform_headers($headers); } /* -Gets the html data row for the expenses. +Gets the html data row for the expenses */ function get_expenses_data_row($expense) { @@ -590,7 +659,7 @@ function get_expenses_data_row($expense) 'payment_type' => $expense->payment_type, 'category_name' => $expense->category_name, 'description' => $expense->description, - 'createdBy' => $expense->first_name.' '. $expense->last_name, + 'created_by' => $expense->first_name.' '. $expense->last_name, 'edit' => anchor($controller_name."/view/$expense->expense_id", '', array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) )); @@ -638,4 +707,55 @@ function get_expenses_manage_payments_summary($payments, $expenses) return $table; } + +/* +Get the header for the cashup tabular view +*/ +function get_cashups_manage_table_headers() +{ + $CI =& get_instance(); + $headers = array( + array('cashup_id' => $CI->lang->line('cashups_id')), + array('open_date' => $CI->lang->line('cashups_opened_date')), + array('open_employee_id' => $CI->lang->line('cashups_open_employee')), + array('open_amount_cash' => $CI->lang->line('cashups_open_amount_cash')), + array('transfer_amount_cash' => $CI->lang->line('cashups_transfer_amount_cash')), + array('close_date' => $CI->lang->line('cashups_closed_date')), + array('close_employee_id' => $CI->lang->line('cashups_close_employee')), + array('closed_amount_cash' => $CI->lang->line('cashups_closed_amount_cash')), + array('note' => $CI->lang->line('cashups_note')), + array('closed_amount_due' => $CI->lang->line('cashups_closed_amount_due')), + array('closed_amount_card' => $CI->lang->line('cashups_closed_amount_card')), + array('closed_amount_check' => $CI->lang->line('cashups_closed_amount_check')), + array('closed_amount_total' => $CI->lang->line('cashups_closed_amount_total')) + ); + + return transform_headers($headers); +} + +/* +Gets the html data row for the cashups +*/ +function get_cash_up_data_row($cash_up) +{ + $CI =& get_instance(); + $controller_name = strtolower(get_class($CI)); + return array ( + 'cashup_id' => $cash_up->cashup_id, + 'open_date' => date($CI->config->item('dateformat') . ' ' . $CI->config->item('timeformat'), strtotime($cash_up->open_date)), + 'open_employee_id' => $cash_up->open_first_name . ' ' . $cash_up->open_last_name, + 'open_amount_cash' => to_currency($cash_up->open_amount_cash), + 'transfer_amount_cash' => to_currency($cash_up->transfer_amount_cash), + 'close_date' => date($CI->config->item('dateformat') . ' ' . $CI->config->item('timeformat'), strtotime($cash_up->close_date)), + 'close_employee_id' => $cash_up->close_first_name . ' ' . $cash_up->close_last_name, + 'closed_amount_cash' => to_currency($cash_up->closed_amount_cash), + 'note' => $cash_up->note ? '' : '', + 'closed_amount_due' => to_currency($cash_up->closed_amount_due), + 'closed_amount_card' => to_currency($cash_up->closed_amount_card), + 'closed_amount_check' => to_currency($cash_up->closed_amount_check), + 'closed_amount_total' => to_currency($cash_up->closed_amount_total), + 'edit' => anchor($controller_name."/view/$cash_up->cashup_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} ?> diff --git a/application/helpers/tax_helper.php b/application/helpers/tax_helper.php new file mode 100644 index 000000000..75273ffe1 --- /dev/null +++ b/application/helpers/tax_helper.php @@ -0,0 +1,151 @@ + $CI->lang->line('taxes_tax_code')), + array('tax_code_name' => $CI->lang->line('taxes_tax_code_name')), + array('city' => $CI->lang->line('common_city')), + array('state' => $CI->lang->line('common_state')) + ); + + return transform_headers($headers); +} + +/* +Get the html data row for the tax +*/ +function get_tax_code_data_row($tax_code_row) +{ + $CI =& get_instance(); + $controller_name='tax_codes'; + + return array ( + 'tax_code' => $tax_code_row->tax_code, + 'tax_code_name' => $tax_code_row->tax_code_name, + 'tax_code_type' => $tax_code_row->tax_code_type, + 'city' => $tax_code_row->city, + 'state' => $tax_code_row->state, + 'edit' => anchor($controller_name."/view_tax_codes/$tax_code_row->tax_code", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update_tax_codes')) + )); +} + +/* +Get the header for the taxes tabular view +*/ +function get_tax_categories_table_headers() +{ + $CI =& get_instance(); + + $headers = array( + array('tax_category' => $CI->lang->line('taxes_tax_category_name')), + array('tax_category_code' => $CI->lang->line('taxes_tax_category_code')), + array('tax_group_sequence' => $CI->lang->line('taxes_tax_group_sequence')), + ); + + return transform_headers($headers); +} + +/* +Get the html data row for the tax +*/ +function get_tax_categories_data_row($tax_categories_row) +{ + $CI =& get_instance(); + $controller_name='tax_categories'; + + return array ( + 'tax_category_id' => $tax_categories_row->tax_category_id, + 'tax_category' => $tax_categories_row->tax_category, + 'tax_category_code' => $tax_categories_row->tax_category_code, + 'tax_group_sequence' => $tax_categories_row->tax_group_sequence, + 'edit' => anchor($controller_name."/view/$tax_categories_row->tax_category_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} + +/* +Get the header for the taxes tabular view +*/ +function get_tax_jurisdictions_table_headers() +{ + $CI =& get_instance(); + + $headers = array( + array('jurisdiction_id' => $CI->lang->line('taxes_jurisdiction_id')), + array('jurisdiction_name' => $CI->lang->line('taxes_jurisdiction_name')), + array('reporting_authority' => $CI->lang->line('taxes_reporting_authority')) + ); + + return transform_headers($headers); +} + +/* +Get the html data row for the tax +*/ +function get_tax_jurisdictions_data_row($tax_jurisdiction_row) +{ + $CI =& get_instance(); + $controller_name='tax_jurisdictions'; + + return array ( + 'jurisdiction_id' => $tax_jurisdiction_row->jurisdiction_id, + 'jurisdiction_name' => $tax_jurisdiction_row->jurisdiction_name, + 'reporting_authority' => $tax_jurisdiction_row->reporting_authority, + 'edit' => anchor($controller_name."/view/$tax_jurisdiction_row->jurisdiction_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} + +/* +Get the header for the taxes tabular view +*/ +function get_tax_rates_manage_table_headers() +{ + $CI =& get_instance(); + + $headers = array( + array('tax_code' => $CI->lang->line('taxes_tax_code')), + array('tax_code_name' => $CI->lang->line('taxes_tax_code_name')), + array('jurisdiction_name' => $CI->lang->line('taxes_jurisdiction_name')), + array('tax_category' => $CI->lang->line('taxes_tax_category')), + array('tax_rate' => $CI->lang->line('taxes_tax_rate')), + array('rounding_code_name' => $CI->lang->line('taxes_rounding_code')) + ); + + return transform_headers($headers); +} + +/* +Get the html data row for the tax +*/ +function get_tax_rates_data_row($tax_rates_row) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + + return array ( + 'tax_rate_id' => $tax_rates_row->tax_rate_id, + 'tax_code' => $tax_rates_row->tax_code, + 'tax_code_name' => $tax_rates_row->tax_code_name, + 'tax_category' => $tax_rates_row->tax_category, + 'tax_rate' => $tax_rates_row->tax_rate, + 'jurisdiction_name' => $tax_rates_row->jurisdiction_name, + 'tax_rounding_code' =>$tax_rates_row->tax_rounding_code, + 'rounding_code_name' => Rounding_mode::get_rounding_code_name($tax_rates_row->tax_rounding_code), + 'edit' => anchor($controller_name."/view/$tax_rates_row->tax_rate_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} + +?> diff --git a/application/hooks/load_config.php b/application/hooks/load_config.php index 972c42625..1cb4b0ec5 100644 --- a/application/hooks/load_config.php +++ b/application/hooks/load_config.php @@ -7,25 +7,28 @@ function load_config() { $CI =& get_instance(); + $migration = $CI->load->library('migration'); + if (!$CI->migration->is_latest()) + { + $CI->session->sess_destroy(); + } + foreach($CI->Appconfig->get_all()->result() as $app_config) { $CI->config->set_item($CI->security->xss_clean($app_config->key), $CI->security->xss_clean($app_config->value)); } - - //Loads all the language files from the language directory - if(!empty(current_language())) - { - // fallback to English if language folder does not exist - if(!file_exists('../application/language/' . current_language_code())) - { - $CI->config->set_item('language', 'english'); - $CI->config->set_item('language_code', 'en-US'); - } - _load_language_files($CI, '../vendor/codeigniter/framework/system/language', current_language()); - _load_language_files($CI, '../application/language', current_language_code()); + // fallback to English if language settings are not correct + $file_exists = !file_exists('../application/language/' . current_language_code()); + if(current_language_code() == null || current_language() == null || $file_exists) + { + $CI->config->set_item('language', 'english'); + $CI->config->set_item('language_code', 'en-US'); } - + + _load_language_files($CI, '../vendor/codeigniter/framework/system/language', current_language()); + _load_language_files($CI, '../application/language', current_language_code()); + //Set timezone from config database if($CI->config->item('timezone')) { diff --git a/application/language/Language code definition b/application/language/Language code definition index be122151f..fb6d86c0b 100644 --- a/application/language/Language code definition +++ b/application/language/Language code definition @@ -235,6 +235,8 @@ xh Xhosa xh-ZA Xhosa (South Africa) zh Chinese zh-CN Chinese (S) +zh-Hans Chinese in the simplified scrip +zh-Hant Chinese in the traditional script zh-HK Chinese (Hong Kong) zh-MO Chinese (Macau) zh-SG Chinese (Singapore) diff --git a/application/language/ar-EG/attributes_lang.php b/application/language/ar-EG/attributes_lang.php new file mode 100644 index 000000000..ab7a1c61a --- /dev/null +++ b/application/language/ar-EG/attributes_lang.php @@ -0,0 +1,28 @@ + Aussetzen"; -$lang["sales_suspended_doc_id"] = ""; +$lang["sales_suspended_doc_id"] = "Dokument"; $lang["sales_suspended_sale_id"] = "ID"; $lang["sales_suspended_sales"] = "Ausgesetzte Aufträge"; $lang["sales_table"] = "Tisch"; $lang["sales_takings"] = "Einnahmen"; -$lang["sales_tax"] = "MWSt"; -$lang["sales_tax_percent"] = "MWSt %"; -$lang["sales_total"] = "Total"; -$lang["sales_total_tax_exclusive"] = "Total exkl. MWSt."; -$lang["sales_transaction_failed"] = "Verarbeitung fehlerhaft"; +$lang["sales_tax"] = "Steuer"; +$lang["sales_tax_id"] = "Steuer ID"; +$lang["sales_tax_invoice"] = "Steuerrechnung"; +$lang["sales_tax_percent"] = "Steuer %"; +$lang["sales_total"] = "Gesamtbetrag"; +$lang["sales_total_tax_exclusive"] = "exkl. Steuer"; +$lang["sales_transaction_failed"] = "Verarbeitung fehlerhaft."; $lang["sales_unable_to_add_item"] = "Kann Artikel nicht zum Auftrag hinzufügen"; -$lang["sales_unsuccessfully_deleted"] = "Löschung nicht erfolgreich"; -$lang["sales_unsuccessfully_restored"] = ""; -$lang["sales_unsuccessfully_suspended_sale"] = "Auftrag wurde erfolgreich pendent gehalten"; -$lang["sales_unsuccessfully_updated"] = "Änderung nicht erfolgreich"; +$lang["sales_unsuccessfully_deleted"] = "Löschen des Verkaufs fehlgeschlagen."; +$lang["sales_unsuccessfully_restored"] = "Wiederherstellung fehlgeschlagen."; +$lang["sales_unsuccessfully_suspended_sale"] = "Verkaufsstopp fehlgeschlagen."; +$lang["sales_unsuccessfully_updated"] = "Änderung fehlgeschlagen."; $lang["sales_unsuspend"] = "Aktivieren"; $lang["sales_unsuspend_and_delete"] = "Aktivieren und löschen"; $lang["sales_update"] = "Ändern"; -$lang["sales_work_order"] = ""; -$lang["sales_work_order_number"] = ""; -$lang["sales_work_order_number_duplicate"] = ""; -$lang["sales_work_order_sent"] = ""; -$lang["sales_work_order_unsent"] = ""; +$lang["sales_upi"] = "UPI"; +$lang["sales_work_order"] = "Arbeitsauftrag"; +$lang["sales_work_order_number"] = "Arbeitsauftragsnummer"; +$lang["sales_work_order_number_duplicate"] = "Arbeitsauftragsnummer muss eindeutig sein."; +$lang["sales_work_order_sent"] = "Arbeitsauftrag gesendet an"; +$lang["sales_work_order_unsent"] = "Der Arbeitsauftrag konnte nicht gesendet werden an"; diff --git a/application/language/de/suppliers_lang.php b/application/language/de/suppliers_lang.php index a9ebd001b..811d0ebef 100644 --- a/application/language/de/suppliers_lang.php +++ b/application/language/de/suppliers_lang.php @@ -1,13 +1,16 @@ "; +$lang["sales_invoice_total"] = ""; +$lang["sales_invoice_type_custom_invoice"] = ""; +$lang["sales_invoice_type_custom_tax_invoice"] = ""; +$lang["sales_invoice_type_invoice"] = ""; +$lang["sales_invoice_type_tax_invoice"] = ""; $lang["sales_invoice_unsent"] = "Fatura şuna gönderilemedi"; $lang["sales_invoice_update"] = ""; $lang["sales_item_insufficient_of_stock"] = "Ürün Stoğu Yetersiz"; @@ -99,31 +109,32 @@ $lang["sales_print_after_sale"] = "Satıştan sonra yazdır"; $lang["sales_quantity"] = "Adet"; $lang["sales_quantity_less_than_reorder_level"] = "Dikkat, İstenen stok yetersiz."; $lang["sales_quantity_less_than_zero"] = "Dikkat, İstenen stok yetersiz. Satışa devam edebilirsiniz ama stoğunuzu kontrol ediniz"; -$lang["sales_quantity_of_items"] = ""; -$lang["sales_quote"] = ""; -$lang["sales_quote_number"] = ""; -$lang["sales_quote_number_duplicate"] = ""; -$lang["sales_quote_sent"] = ""; +$lang["sales_quantity_of_items"] = "Ürün sayısı %1"; +$lang["sales_quote"] = "Teklif"; +$lang["sales_quote_number"] = "Teklif Sayısı"; +$lang["sales_quote_number_duplicate"] = "Teklif Sayısı diğerlerinden farklı olmalıdır "; +$lang["sales_quote_sent"] = "Teklif gönderildi =>"; $lang["sales_quote_unsent"] = ""; -$lang["sales_receipt"] = "Satış Faturası"; -$lang["sales_receipt_number"] = ""; -$lang["sales_receipt_sent"] = "Fatura şuna gönderildi"; -$lang["sales_receipt_unsent"] = "Fatura şuna gönderilemedi"; +$lang["sales_receipt"] = "Satış(Fiş)"; +$lang["sales_receipt_no_email"] = "Müşteriye ait geçerli bir mail adresi yoktur"; +$lang["sales_receipt_number"] = "Fiş #"; +$lang["sales_receipt_sent"] = "Fatura gönderildi =>"; +$lang["sales_receipt_unsent"] = "Fatura gönderilemedi =>"; $lang["sales_register"] = "Satış Kaydı"; $lang["sales_remove_customer"] = "Müşteriyi Kaldır"; $lang["sales_return"] = "İade"; $lang["sales_rewards"] = ""; -$lang["sales_rewards_balance"] = ""; +$lang["sales_rewards_balance"] = "Hediye Puanı *Balance"; $lang["sales_sale"] = "Satış"; -$lang["sales_sale_by_invoice"] = ""; +$lang["sales_sale_by_invoice"] = "Faturalı Satış"; $lang["sales_sale_for_customer"] = "Müşteri:"; $lang["sales_sale_time"] = "Saat"; -$lang["sales_sales_tax"] = ""; -$lang["sales_select_customer"] = "Müşteri Seç (İsteğe Bağlı)"; +$lang["sales_sales_tax"] = "Satış Vergisi"; +$lang["sales_select_customer"] = "Müşteri Seç"; $lang["sales_send_invoice"] = "Fatura Gönder"; -$lang["sales_send_quote"] = ""; +$lang["sales_send_quote"] = "Teklif Gönder"; $lang["sales_send_receipt"] = "Fiş Gönder"; -$lang["sales_send_work_order"] = ""; +$lang["sales_send_work_order"] = "İş Emri Gönder"; $lang["sales_serial"] = "Seri"; $lang["sales_show_invoice"] = "Faturayı Göster"; $lang["sales_show_receipt"] = "Makbuzu Göster"; @@ -133,30 +144,33 @@ $lang["sales_stock"] = ""; $lang["sales_stock_location"] = "Stok yeri"; $lang["sales_sub_total"] = "Ara Toplam"; $lang["sales_successfully_deleted"] = "Satış silindi"; -$lang["sales_successfully_restored"] = ""; +$lang["sales_successfully_restored"] = "Satış onarıldı"; $lang["sales_successfully_suspended_sale"] = "Satış askıya alındı"; -$lang["sales_successfully_updated"] = "Satış düzenlendi"; +$lang["sales_successfully_updated"] = "Satış güncellendi"; $lang["sales_suspend_sale"] = "Satışı Askıya Al"; -$lang["sales_suspended_doc_id"] = ""; +$lang["sales_suspended_doc_id"] = "Doküman"; $lang["sales_suspended_sale_id"] = "No"; $lang["sales_suspended_sales"] = "Askıdaki Satışlar"; -$lang["sales_table"] = ""; -$lang["sales_takings"] = "Hasılat"; +$lang["sales_table"] = "Masa"; +$lang["sales_takings"] = "Günlük Satış"; $lang["sales_tax"] = "Vergi"; +$lang["sales_tax_id"] = ""; +$lang["sales_tax_invoice"] = ""; $lang["sales_tax_percent"] = "Vergi %"; $lang["sales_total"] = "Toplam"; $lang["sales_total_tax_exclusive"] = "Vergi hariç"; $lang["sales_transaction_failed"] = "Satış işlemi hatası"; $lang["sales_unable_to_add_item"] = "Ürün satışa eklenemedi"; $lang["sales_unsuccessfully_deleted"] = "Satış silinemedi"; -$lang["sales_unsuccessfully_restored"] = ""; -$lang["sales_unsuccessfully_suspended_sale"] = "Satış askıya alındı"; +$lang["sales_unsuccessfully_restored"] = "Satış onarılamadı"; +$lang["sales_unsuccessfully_suspended_sale"] = "Satış askıya alınamadı"; $lang["sales_unsuccessfully_updated"] = "Satış düzenlenemedi"; $lang["sales_unsuspend"] = "Satışa Al"; -$lang["sales_unsuspend_and_delete"] = ""; -$lang["sales_update"] = "Düzenle"; -$lang["sales_work_order"] = ""; -$lang["sales_work_order_number"] = ""; -$lang["sales_work_order_number_duplicate"] = ""; -$lang["sales_work_order_sent"] = ""; -$lang["sales_work_order_unsent"] = ""; +$lang["sales_unsuspend_and_delete"] = "Hareket"; +$lang["sales_update"] = "Güncelle"; +$lang["sales_upi"] = ""; +$lang["sales_work_order"] = "İş Emri"; +$lang["sales_work_order_number"] = "İş Emri Numarası"; +$lang["sales_work_order_number_duplicate"] = "İş Emri Numarası diğerinden farklı olmalı"; +$lang["sales_work_order_sent"] = "İş Emri Gönderildi =>"; +$lang["sales_work_order_unsent"] = "İş Emri gönderilemedi"; diff --git a/application/language/tr/suppliers_lang.php b/application/language/tr/suppliers_lang.php index 4a7550079..5c0117c08 100644 --- a/application/language/tr/suppliers_lang.php +++ b/application/language/tr/suppliers_lang.php @@ -1,19 +1,23 @@ - - - 403 Forbidden - - - -

Directory access is forbidden.

- - + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + diff --git a/application/language/zh/item_kits_lang.php b/application/language/zh-Hans/item_kits_lang.php old mode 100755 new mode 100644 similarity index 92% rename from application/language/zh/item_kits_lang.php rename to application/language/zh-Hans/item_kits_lang.php index d9b55ce9f..042b77e35 --- a/application/language/zh/item_kits_lang.php +++ b/application/language/zh-Hans/item_kits_lang.php @@ -6,7 +6,10 @@ $lang["item_kits_cannot_be_deleted"] = "無法刪除產品套件"; $lang["item_kits_confirm_delete"] = "你確定你要刪除選取的產品套件嗎?"; $lang["item_kits_confirm_restore"] = ""; $lang["item_kits_description"] = "產品套件描述"; +$lang["item_kits_discount"] = ""; +$lang["item_kits_discount_fixed"] = ""; $lang["item_kits_discount_percent"] = ""; +$lang["item_kits_discount_type"] = ""; $lang["item_kits_error_adding_updating"] = "新增/更新產品套件錯誤"; $lang["item_kits_find_kit_item"] = ""; $lang["item_kits_info"] = "產品套件資料"; diff --git a/application/language/zh/items_lang.php b/application/language/zh-Hans/items_lang.php old mode 100755 new mode 100644 similarity index 94% rename from application/language/zh/items_lang.php rename to application/language/zh-Hans/items_lang.php index 9801eea31..10e9b5033 --- a/application/language/zh/items_lang.php +++ b/application/language/zh-Hans/items_lang.php @@ -24,6 +24,7 @@ $lang["items_cost_price_number"] = "成本價必需是數值"; $lang["items_cost_price_required"] = "成本價為必填攔位"; $lang["items_count"] = "更新庫存"; $lang["items_current_quantity"] = "當前數量"; +$lang["items_default_pack_name"] = ""; $lang["items_description"] = "描述"; $lang["items_details_count"] = "庫存盤點詳情"; $lang["items_do_nothing"] = "沒有執行任何修改"; @@ -37,6 +38,7 @@ $lang["items_excel_import_nodata_wrongformat"] = "Your uploaded file has no data $lang["items_excel_import_partially_failed"] = "Most Items imported. But some were not, here is the list"; $lang["items_excel_import_success"] = "Import of Items successful"; $lang["items_generate_barcodes"] = "產生條碼"; +$lang["items_hsn_code"] = ""; $lang["items_image"] = "Avatar"; $lang["items_import_items_excel"] = "Import items from Excel sheet"; $lang["items_info_provided_by"] = "訊息提供者"; @@ -55,6 +57,7 @@ $lang["items_item_number_duplicate"] = "The item number is already present in th $lang["items_kit"] = ""; $lang["items_location"] = "位置"; $lang["items_low_inventory_items"] = "低庫存產品"; +$lang["items_low_sell_item"] = ""; $lang["items_manually_editing_of_quantity"] = "手動編輯數量"; $lang["items_name"] = "產品名稱"; $lang["items_name_required"] = "產品名稱為必填"; @@ -67,6 +70,8 @@ $lang["items_nonstock"] = ""; $lang["items_number_information"] = "產品編號"; $lang["items_number_required"] = "UPC/EAN/ISBN is a required field"; $lang["items_one_or_multiple"] = "產品"; +$lang["items_pack_name"] = ""; +$lang["items_qty_per_pack"] = ""; $lang["items_quantity"] = "數量"; $lang["items_quantity_number"] = "數量必需是數值"; $lang["items_quantity_required"] = "數量為必填欄位"; @@ -78,8 +83,8 @@ $lang["items_reorder_level_required"] = "補貨點為必填欄位"; $lang["items_retrive_item_info"] = "檢索產品訊息"; $lang["items_sales_tax_1"] = "營業稅"; $lang["items_sales_tax_2"] = "營業稅 2"; -$lang["items_search_attributes"] = ""; -$lang["items_search_custom_items"] = "Search Custom Fields"; +$lang["items_search_attributes"] = "Search Custom Fields"; +$lang["items_search_custom_items"] = ""; $lang["items_select_image"] = "Select Image"; $lang["items_serialized_items"] = "序列化產品"; $lang["items_standard"] = ""; @@ -93,10 +98,12 @@ $lang["items_successful_updating"] = "已成功更新產品"; $lang["items_supplier"] = "供貨商"; $lang["items_tax_1"] = "稅額 1"; $lang["items_tax_2"] = "稅額 2"; +$lang["items_tax_category"] = ""; $lang["items_tax_percent"] = "稅率"; $lang["items_tax_percent_number"] = ""; $lang["items_tax_percent_required"] = "稅率為必填欄位"; $lang["items_tax_percents"] = "稅率 %"; +$lang["items_temp"] = ""; $lang["items_type"] = ""; $lang["items_unit_price"] = "單價"; $lang["items_unit_price_number"] = "單價必需是數值"; diff --git a/application/language/zh/login_lang.php b/application/language/zh-Hans/login_lang.php old mode 100755 new mode 100644 similarity index 100% rename from application/language/zh/login_lang.php rename to application/language/zh-Hans/login_lang.php diff --git a/application/language/zh/messages_lang.php b/application/language/zh-Hans/messages_lang.php similarity index 100% rename from application/language/zh/messages_lang.php rename to application/language/zh-Hans/messages_lang.php diff --git a/application/language/zh/module_lang.php b/application/language/zh-Hans/module_lang.php old mode 100755 new mode 100644 similarity index 92% rename from application/language/zh/module_lang.php rename to application/language/zh-Hans/module_lang.php index d9cb86444..798fbe56f --- a/application/language/zh/module_lang.php +++ b/application/language/zh-Hans/module_lang.php @@ -1,6 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/zh-Hant/item_kits_lang.php b/application/language/zh-Hant/item_kits_lang.php new file mode 100644 index 000000000..042b77e35 --- /dev/null +++ b/application/language/zh-Hant/item_kits_lang.php @@ -0,0 +1,35 @@ +find_migrations(); + return basename(end($migrations)); + } + + public function is_latest() + { + $last_migration = $this->get_last_migration(); + $last_version = $this->_get_migration_number($last_migration); + $current_version = $this->_get_version(); + + return $last_version == $current_version; + } + +} \ No newline at end of file diff --git a/application/libraries/Receiving_lib.php b/application/libraries/Receiving_lib.php index 894474bc9..a7982d6c3 100644 --- a/application/libraries/Receiving_lib.php +++ b/application/libraries/Receiving_lib.php @@ -159,7 +159,7 @@ class Receiving_lib $this->CI->session->unset_userdata('recv_stock_destination'); } - public function add_item($item_id, $quantity = 1, $item_location = NULL, $discount = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $receiving_quantity = NULL, $include_deleted = FALSE) + public function add_item($item_id, $quantity = 1, $item_location = NULL, $discount = 0, $discount_type = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $receiving_quantity = NULL, $receiving_id = NULL, $include_deleted = FALSE) { //make sure item exists in database. if(!$this->CI->Item->exists($item_id, $include_deleted)) @@ -209,22 +209,48 @@ class Receiving_lib $item_info = $this->CI->Item->get_info($item_id,$item_location); //array records are identified by $insertkey and item_id is just another field. $price = $price != NULL ? $price : $item_info->cost_price; + + if($this->CI->config->item('multi_pack_enabled') == '1') + { + $item_info->name .= NAME_SEPARATOR . $item_info->pack_name; + } + + if ($item_info->receiving_quantity == 0 || $item_info->receiving_quantity == 1) + { + $receiving_quantity_choices = array(1 => 'x1'); + } + else + { + $receiving_quantity_choices = array( + to_quantity_decimals($item_info->receiving_quantity) => 'x' . to_quantity_decimals($item_info->receiving_quantity), + 1 => 'x1'); + } + + if(is_null($receiving_quantity)) + { + $receiving_quantity = $item_info->receiving_quantity; + } + $item = array($insertkey => array( 'item_id' => $item_id, 'item_location' => $item_location, + 'item_number' => $item_info->item_number, 'stock_name' => $this->CI->Stock_location->get_location_name($item_location), 'line' => $insertkey, 'name' => $item_info->name, 'description' => $description != NULL ? $description: $item_info->description, 'serialnumber' => $serialnumber != NULL ? $serialnumber: '', + 'attribute_values' => $this->CI->Attribute->get_link_values($item_id, 'receiving_id', $receiving_id, Attribute::SHOW_IN_RECEIVINGS), 'allow_alt_description' => $item_info->allow_alt_description, 'is_serialized' => $item_info->is_serialized, 'quantity' => $quantity, 'discount' => $discount, + 'discount_type' => $discount_type, 'in_stock' => $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity, 'price' => $price, - 'receiving_quantity' => $receiving_quantity!=NULL ? $receiving_quantity : $item_info->receiving_quantity, - 'total' => $this->get_item_total($quantity, $price, $discount, $receiving_quantity) + 'receiving_quantity' => $receiving_quantity, + 'receiving_quantity_choices' => $receiving_quantity_choices, + 'total' => $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity) ) ); @@ -232,7 +258,7 @@ class Receiving_lib if($itemalreadyinsale) { $items[$updatekey]['quantity'] += $quantity; - $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount); + $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount, $discount_type, $items[$updatekey]['receiving_quantity']); } else { @@ -245,7 +271,7 @@ class Receiving_lib return TRUE; } - public function edit_item($line, $description, $serialnumber, $quantity, $discount, $price) + public function edit_item($line, $description, $serialnumber, $quantity, $discount, $discount_type, $price, $receiving_quantity) { $items = $this->get_cart(); if(isset($items[$line])) @@ -254,9 +280,14 @@ class Receiving_lib $line['description'] = $description; $line['serialnumber'] = $serialnumber; $line['quantity'] = $quantity; + $line['receiving_quantity'] = $receiving_quantity; $line['discount'] = $discount; + if(!is_null($discount_type)) + { + $line['discount_type'] = $discount_type; + } $line['price'] = $price; - $line['total'] = $this->get_item_total($quantity, $price, $discount); + $line['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity); $this->set_cart($items); } @@ -289,13 +320,13 @@ class Receiving_lib foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) { - $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, TRUE); + $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $receiving_id, $row->receiving_quantity, TRUE); } $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); } - public function add_item_kit($external_item_kit_id, $item_location) + public function add_item_kit($external_item_kit_id, $item_location, $discount, $discount_type) { //KIT # $pieces = explode(' ',$external_item_kit_id); @@ -303,7 +334,7 @@ class Receiving_lib foreach($this->CI->Item_kit_items->get_info($item_kit_id) as $item_kit_item) { - $this->add_item($item_kit_item['item_id'],$item_kit_item['quantity'], $item_location); + $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, $discount_type); } } @@ -314,7 +345,7 @@ class Receiving_lib foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, TRUE); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, TRUE); } $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); @@ -330,11 +361,16 @@ class Receiving_lib $this->clear_reference(); } - public function get_item_total($quantity, $price, $discount_percentage) + public function get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity) { - $total = bcmul($quantity, $price); - $discount_fraction = bcdiv($discount_percentage, 100); - $discount_amount = bcmul($total, $discount_fraction); + $extended_quantity = bcmul($quantity, $receiving_quantity); + $total = bcmul($extended_quantity, $price); + $discount_amount = $discount; + if($discount_type == PERCENT) + { + $discount_fraction = bcdiv($discount, 100); + $discount_amount = bcmul($total, $discount_fraction); + } return bcsub($total, $discount_amount); } @@ -344,7 +380,7 @@ class Receiving_lib $total = 0; foreach($this->get_cart() as $item) { - $total = bcadd($total, $this->get_item_total(($item['quantity']* $item['receiving_quantity']), $item['price'], $item['discount'])); + $total = bcadd($total, $this->get_item_total(($item['quantity']), $item['price'], $item['discount'], $item['discount_type'], $item['receiving_quantity'])); } return $total; diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php index 61ca5d259..5263c87de 100644 --- a/application/libraries/Sale_lib.php +++ b/application/libraries/Sale_lib.php @@ -47,6 +47,16 @@ class Sale_lib return $register_modes; } + public function get_invoice_type_options() + { + $invoice_types = array(); + $invoice_types['invoice'] = $this->CI->lang->line('sales_invoice_type_invoice'); + $invoice_types['tax_invoice'] = $this->CI->lang->line('sales_invoice_type_tax_invoice'); + $invoice_types['custom_invoice'] = $this->CI->lang->line('sales_invoice_type_custom_invoice'); + $invoice_types['custom_tax_invoice'] = $this->CI->lang->line('sales_invoice_type_custom_tax_invoice'); + return $invoice_types; + } + public function get_cart() { if(!$this->CI->session->userdata('sales_cart')) @@ -66,10 +76,14 @@ class Sale_lib $filtered_cart = array(); - foreach($cart as $k=>$v) + foreach($cart as $k => $v) { if($v['print_option'] == PRINT_YES) { + if($v['price'] == 0.0) + { + $v['discount'] = 0.0; + } $filtered_cart[] = $v; } } @@ -78,7 +92,7 @@ class Sale_lib if($this->CI->config->item('line_sequence') == '0') { $sort = array(); - foreach($filtered_cart as $k=>$v) + foreach($filtered_cart as $k => $v) { $sort['line'][$k] = $v['line']; } @@ -88,19 +102,19 @@ class Sale_lib elseif($this->CI->config->item('line_sequence') == '1') { $sort = array(); - foreach($filtered_cart as $k=>$v) + foreach($filtered_cart as $k => $v) { $sort['stock_type'][$k] = $v['stock_type']; $sort['description'][$k] = $v['description']; $sort['name'][$k] = $v['name']; } - array_multisort($sort['stock_type'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC. $filtered_cart); + array_multisort($sort['stock_type'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC . $filtered_cart); } // Group by Item Category elseif($this->CI->config->item('line_sequence') == '2') { $sort = array(); - foreach($filtered_cart as $k=>$v) + foreach($filtered_cart as $k => $v) { $sort['category'][$k] = $v['stock_type']; $sort['description'][$k] = $v['description']; @@ -112,7 +126,7 @@ class Sale_lib else { $sort = array(); - foreach($filtered_cart as $k=>$v) + foreach($filtered_cart as $k => $v) { $sort['line'][$k] = $v['line']; } @@ -132,6 +146,19 @@ class Sale_lib $this->CI->session->unset_userdata('sales_cart'); } + public function remove_temp_items() + { + // Loop through the cart items and delete temporary items specific to this sale + $cart = $this->get_cart(); + foreach($cart as $line=>$item) + { + if($item['item_type'] == ITEM_TEMP) + { + $this->CI->Item->delete($item['item_id']); + } + } + } + public function get_comment() { // avoid returning a NULL that results in a 0 in the comment if nothing is set/available @@ -399,7 +426,7 @@ class Sale_lib // Multiple Payments public function get_payments_total() { - $subtotal = 0; + $subtotal = 0.0; $this->reset_cash_flags(); foreach($this->get_payments() as $payments) { @@ -417,18 +444,18 @@ class Sale_lib * Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'paid_in_full' * 'subtotal', 'discounted_subtotal', 'tax_exclusive_subtotal', 'item_count', 'total_units' */ - public function get_totals() + public function get_totals($taxes) { $cash_rounding = $this->CI->session->userdata('cash_rounding'); $totals = array(); - $prediscount_subtotal = 0; - $subtotal = 0; - $total = 0; - $total_discount = 0; + $prediscount_subtotal = 0.0; + $subtotal = 0.0; + $total = 0.0; + $total_discount = 0.0; $item_count = 0; - $total_units = 0; + $total_units = 0.0; foreach($this->get_cart() as $item) { @@ -437,7 +464,7 @@ class Sale_lib $item_count++; $total_units += $item['quantity']; } - $discount_amount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount']); + $discount_amount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']); $total_discount = bcadd($total_discount, $discount_amount); $extended_amount = $this->get_extended_amount($item['quantity'], $item['price']); @@ -447,7 +474,7 @@ class Sale_lib if($this->CI->config->item('tax_included')) { - $subtotal = bcadd($subtotal, $this->get_extended_total_tax_exclusive($item['item_id'], $extended_discounted_amount, $item['quantity'], $item['price'], $item['discount'])); + $subtotal = bcadd($subtotal, $this->get_extended_total_tax_exclusive($item['item_id'], $extended_discounted_amount, $item['quantity'], $item['price'], $item['discount'],$item['discount_type'])); } else { @@ -459,18 +486,14 @@ class Sale_lib $totals['total_discount'] = $total_discount; $totals['subtotal'] = $subtotal; - if($this->CI->config->item('tax_included')) + foreach($taxes as $tax_excluded) { - $totals['total'] = $total; - } - else - { - foreach($this->get_taxes() as $sales_tax) + if($tax_excluded['tax_type'] == Tax_lib::TAX_TYPE_EXCLUDED) { - $total = bcadd($total, $sales_tax['sale_tax_amount']); + $total = bcadd($total, $tax_excluded['sale_tax_amount']); } - $totals['total'] = $total; } + $totals['total'] = $total; if($cash_rounding) { @@ -530,7 +553,7 @@ class Sale_lib $precision = totals_decimals(); $rounded_due = bccomp(round($amount_due, $precision, PHP_ROUND_HALF_UP), 0, $precision); // take care of rounding error introduced by round tripping payment amount to the browser - return $rounded_due == 0 ? 0 : $amount_due; + return $rounded_due == 0.0 ? 0.0 : $amount_due; } public function get_customer() @@ -683,10 +706,9 @@ class Sale_lib $this->CI->session->unset_userdata('sales_rewards_remainder'); } - public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0, $price_mode = PRICE_MODE_STANDARD, $kit_price_option = NULL, $kit_print_option = NULL, $price_override = NULL, $description = NULL, $serialnumber = NULL, $include_deleted = FALSE, $print_option = NULL ) + public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0.0, $discount_type = 0, $price_mode = PRICE_MODE_STANDARD, $kit_price_option = NULL, $kit_print_option = NULL, $price_override = NULL, $description = NULL, $serialnumber = NULL, $sale_id = NULL, $include_deleted = FALSE, $print_option = NULL, $line = NULL ) { - $item_info = $this->CI->Item->get_info_by_id_or_number($item_id); - + $item_info = $this->CI->Item->get_info_by_id_or_number($item_id, $include_deleted); //make sure item exists if(empty($item_info)) { @@ -737,11 +759,6 @@ class Sale_lib $price = $price_override; } - if($price == 0.00) - { - $discount = 0.00; - } - // Serialization and Description //Get all items in the cart so far... @@ -812,9 +829,16 @@ class Sale_lib } } - $total = $this->get_item_total($quantity, $price, $discount); - $discounted_total = $this->get_item_total($quantity, $price, $discount, TRUE); - //Item already exists and is not serialized, add to quantity + $total = $this->get_item_total($quantity, $price, $discount, $discount_type); + $discounted_total = $this->get_item_total($quantity, $price, $discount, $discount_type, TRUE); + + if($this->CI->config->item('multi_pack_enabled') == '1') + { + $item_info->name .= NAME_SEPARATOR . $item_info->pack_name; + } + + + //Item already exists and is not serialized, add to quantity if(!$itemalreadyinsale || $item_info->is_serialized) { $item = array($insertkey => array( @@ -824,12 +848,14 @@ class Sale_lib 'line' => $insertkey, 'name' => $item_info->name, 'item_number' => $item_info->item_number, + 'attribute_values' => $this->CI->Attribute->get_link_values($item_id, 'sale_id', $sale_id, Attribute::SHOW_IN_SALES), 'description' => $description != NULL ? $description : $item_info->description, 'serialnumber' => $serialnumber != NULL ? $serialnumber : '', 'allow_alt_description' => $item_info->allow_alt_description, 'is_serialized' => $item_info->is_serialized, 'quantity' => $quantity, 'discount' => $discount, + 'discount_type' => $discount_type, 'in_stock' => $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity, 'price' => $price, 'cost_price' => $cost_price, @@ -838,6 +864,7 @@ class Sale_lib 'print_option' => $print_option_selected, 'stock_type' => $stock_type, 'item_type' => $item_type, + 'hsn_code' => $item_info->hsn_code, 'tax_category_id' => $item_info->tax_category_id ) ); @@ -862,7 +889,7 @@ class Sale_lib //make sure item exists if($item_id != -1) { - $item_info = $this->CI->Item->get_info_by_id_or_number($item_id); + $item_info = $this->CI->Item->get_info_by_id_or_number($item_id, TRUE); if($item_info->stock_type == HAS_STOCK) { @@ -913,7 +940,7 @@ class Sale_lib return -1; } - public function edit_item($line, $description, $serialnumber, $quantity, $discount, $price, $discounted_total=NULL) + public function edit_item($line, $description, $serialnumber, $quantity, $discount, $discount_type, $price, $discounted_total=NULL) { $items = $this->get_cart(); if(isset($items[$line])) @@ -928,9 +955,13 @@ class Sale_lib $line['serialnumber'] = $serialnumber; $line['quantity'] = $quantity; $line['discount'] = $discount; + if(!is_null($discount_type)) + { + $line['discount_type'] = $discount_type; + } $line['price'] = $price; - $line['total'] = $this->get_item_total($quantity, $price, $discount); - $line['discounted_total'] = $this->get_item_total($quantity, $price, $discount, TRUE); + $line['total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type']); + $line['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type'], TRUE); $this->set_cart($items); } @@ -940,6 +971,12 @@ class Sale_lib public function delete_item($line) { $items = $this->get_cart(); + $item_type = $items[$line]['item_type']; + if($item_type == ITEM_TEMP) + { + $item_id = $items[$line]['item_id']; + $this->CI->Item->delete($item_id); + } unset($items[$line]); $this->set_cart($items); } @@ -955,13 +992,13 @@ class Sale_lib foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_percent, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE); + $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE); } $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); } - public function add_item_kit($external_item_kit_id, $item_location, $discount, $kit_price_option, $kit_print_option, &$stock_warning) + public function add_item_kit($external_item_kit_id, $item_location, $discount, $discount_type, $kit_price_option, $kit_print_option, &$stock_warning) { //KIT # $pieces = explode(' ', $external_item_kit_id); @@ -970,7 +1007,7 @@ class Sale_lib foreach($this->CI->Item_kit_items->get_info($item_kit_id) as $item_kit_item) { - $result &= $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, PRICE_MODE_KIT, $kit_price_option, $kit_print_option, NULL, NULL, NULL, NULL); + $result &= $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, $discount_type, PRICE_MODE_KIT, $kit_price_option, $kit_print_option, NULL, NULL, NULL, FALSE); if($stock_warning == NULL) { @@ -988,7 +1025,7 @@ class Sale_lib foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, TRUE, $row->print_option); } foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row) @@ -1016,7 +1053,7 @@ class Sale_lib $this->empty_cart(); foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, TRUE, $row->print_option); } return $this->CI->session->userdata('sales_cart'); @@ -1078,69 +1115,7 @@ class Sale_lib return $customer->taxable or $customer_id == -1; } - /* - * This returns taxes for VAT taxes and for pre 3.1.0 sales taxes. - */ - public function get_taxes() - { - $register_mode = $this->CI->config->item('default_register_mode'); - $tax_decimals = tax_decimals(); - $customer_id = $this->get_customer(); - $customer = $this->CI->Customer->get_info($customer_id); - $sales_taxes = array(); - //Do not charge sales tax if we have a customer that is not taxable - if($customer->taxable or $customer_id == -1) - { - foreach($this->get_cart() as $line => $item) - { - // Start of current VAT tax apply - $tax_info = $this->CI->Item_taxes->get_info($item['item_id']); - $tax_group_sequence = 0; - foreach($tax_info as $tax) - { - // This computes tax for each line item and adds it to the tax type total - $tax_group = (float)$tax['percent'] . '% ' . $tax['name']; - $tax_type = Tax_lib::TAX_TYPE_VAT; - $tax_basis = $this->get_item_total($item['quantity'], $item['price'], $item['discount'], TRUE); - $tax_amount = 0; - - if($this->CI->config->item('tax_included')) - { - $tax_amount = $this->get_item_tax($item['quantity'], $item['price'], $item['discount'], $tax['percent']); - } - elseif($this->CI->config->item('customer_sales_tax_support') == '0') - { - $tax_amount = $this->CI->tax_lib->get_sales_tax_for_amount($tax_basis, $tax['percent'], '0', $tax_decimals); - } - - if($tax_amount <> 0) - { - $this->CI->tax_lib->update_sales_taxes($sales_taxes, $tax_type, $tax_group, $tax['percent'], $tax_basis, $tax_amount, $tax_group_sequence, '0', -1); - $tax_group_sequence += 1; - } - } - - $tax_category = ''; - $tax_rate = ''; - $rounding_code = Rounding_mode::HALF_UP; - $tax_group_sequence = 0; - $tax_code = ''; - - if($this->CI->config->item('customer_sales_tax_support') == '1') - { - // Now calculate what the sales taxes should be (storing them in the $sales_taxes array - $this->CI->tax_lib->apply_sales_tax($item, $customer->city, $customer->state, $customer->sales_tax_code, $register_mode, 0, $sales_taxes, $tax_category, $tax_rate, $rounding_code, $tax_group_sequence, $tax_code); - } - - } - - $this->CI->tax_lib->round_sales_taxes($sales_taxes); - } - - return $sales_taxes; - } - - public function apply_customer_discount($discount_percent) + public function apply_customer_discount($discount, $discount_type) { // Get all items in the cart so far... $items = $this->get_cart(); @@ -1151,11 +1126,11 @@ class Sale_lib $price = $item['price']; // set a new discount only if the current one is 0 - if($item['discount'] == 0) + if($item['discount'] == 0.0) { - $item['discount'] = $discount_percent; - $item['total'] = $this->get_item_total($quantity, $price, $discount_percent); - $item['discounted_total'] = $this->get_item_total($quantity, $price, $discount_percent, TRUE); + $item['discount'] = $discount; + $item['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type); + $item['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, TRUE); } } @@ -1164,12 +1139,12 @@ class Sale_lib public function get_discount() { - $discount = 0; + $discount = 0.0; foreach($this->get_cart() as $item) { - if($item['discount'] > 0) + if($item['discount'] > 0.0) { - $item_discount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount']); + $item_discount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']); $discount = bcadd($discount, $item_discount); } } @@ -1182,39 +1157,39 @@ class Sale_lib return $this->calculate_subtotal($include_discount, $exclude_tax); } - public function get_item_total_tax_exclusive($item_id, $quantity, $price, $discount_percentage, $include_discount = FALSE) + public function get_item_total_tax_exclusive($item_id, $quantity, $price, $discount, $discount_type, $include_discount = FALSE) { $tax_info = $this->CI->Item_taxes->get_info($item_id); - $item_total = $this->get_item_total($quantity, $price, $discount_percentage, $include_discount); + $item_total = $this->get_item_total($quantity, $price, $discount, $discount_type, $include_discount); // only additive tax here foreach($tax_info as $tax) { $tax_percentage = $tax['percent']; - $item_total = bcsub($item_total, $this->get_item_tax($quantity, $price, $discount_percentage, $tax_percentage)); + $item_total = bcsub($item_total, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage)); } return $item_total; } - public function get_extended_total_tax_exclusive($item_id, $discounted_extended_amount, $quantity, $price, $discount_percentage = 0) + public function get_extended_total_tax_exclusive($item_id, $discounted_extended_amount, $quantity, $price, $discount = 0.0, $discount_type = 0) { $tax_info = $this->CI->Item_taxes->get_info($item_id); // only additive tax here foreach($tax_info as $tax) { $tax_percentage = $tax['percent']; - $discounted_extended_amount = bcsub($discounted_extended_amount, $this->get_item_tax($quantity, $price, $discount_percentage, $tax_percentage)); + $discounted_extended_amount = bcsub($discounted_extended_amount, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage)); } return $discounted_extended_amount; } - public function get_item_total($quantity, $price, $discount_percentage, $include_discount = FALSE) + public function get_item_total($quantity, $price, $discount, $discount_type, $include_discount = FALSE) { $total = bcmul($quantity, $price); if($include_discount) { - $discount_amount = $this->get_item_discount($quantity, $price, $discount_percentage); + $discount_amount = $this->get_item_discount($quantity, $price, $discount, $discount_type); return bcsub($total, $discount_amount); } @@ -1236,24 +1211,28 @@ class Sale_lib return $quantity; } - public function get_extended_amount($quantity, $price, $discount_amount = 0) + public function get_extended_amount($quantity, $price, $discount_amount = 0.0) { $extended_amount = bcmul($quantity, $price); return bcsub($extended_amount, $discount_amount); } - public function get_item_discount($quantity, $price, $discount_percentage) + public function get_item_discount($quantity, $price, $discount, $discount_type) { $total = bcmul($quantity, $price); - $discount_fraction = bcdiv($discount_percentage, 100); - - return round(bcmul($total, $discount_fraction), totals_decimals(), PHP_ROUND_HALF_UP); + if($discount_type == PERCENT) + { + $discount_fraction = bcdiv($discount, 100); + $discount=bcmul($total,$discount_fraction); + } + + return round($discount, totals_decimals(), PHP_ROUND_HALF_UP); } - public function get_item_tax($quantity, $price, $discount_percentage, $tax_percentage) + public function get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage) { - $price = $this->get_item_total($quantity, $price, $discount_percentage, TRUE); + $price = $this->get_item_total($quantity, $price, $discount, $discount_type, TRUE); if($this->CI->config->item('tax_included')) { $tax_fraction = bcadd(100, $tax_percentage); @@ -1269,16 +1248,16 @@ class Sale_lib public function calculate_subtotal($include_discount = FALSE, $exclude_tax = FALSE) { - $subtotal = 0; + $subtotal = 0.0; foreach($this->get_cart() as $item) { if($exclude_tax && $this->CI->config->item('tax_included')) { - $subtotal = bcadd($subtotal, $this->get_item_total_tax_exclusive($item['item_id'], $item['quantity'], $item['price'], $item['discount'], $include_discount)); + $subtotal = bcadd($subtotal, $this->get_item_total_tax_exclusive($item['item_id'], $item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount)); } else { - $subtotal = bcadd($subtotal, $this->get_item_total($item['quantity'], $item['price'], $item['discount'], $include_discount)); + $subtotal = bcadd($subtotal, $this->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount)); } } @@ -1293,9 +1272,9 @@ class Sale_lib if(!$this->CI->config->item('tax_included')) { - foreach($this->get_taxes() as $sales_tax) + foreach($this->CI->tax_lib->get_taxes($this->get_cart())[0] as $tax) { - $total = bcadd($total, $sales_tax['sale_tax_amount']); + $total = bcadd($total, $tax['sale_tax_amount']); } } diff --git a/application/libraries/Tax_lib.php b/application/libraries/Tax_lib.php index 7713f62e4..7c03c625c 100644 --- a/application/libraries/Tax_lib.php +++ b/application/libraries/Tax_lib.php @@ -8,9 +8,8 @@ class Tax_lib { - const TAX_TYPE_SALES = 1; - const TAX_TYPE_SALES_BY_INVOICE = 2; - const TAX_TYPE_VAT = 0; + const TAX_TYPE_EXCLUDED = 1; + const TAX_TYPE_INCLUDED = 0; private $CI; @@ -22,50 +21,152 @@ class Tax_lib public function get_tax_types() { return array( - TAX_TYPE_SALES => $this->CI->lang->line('taxes_sales_tax'), - TAX_TYPE_SALES_BY_INVOICE => $this->CI->lang->line('taxes_sales_tax_by_invoice'), - TAX_TYPE_VAT => $this->CI->lang->line('taxes_vat_tax') + Tax_lib::TAX_TYPE_EXCLUDED => $this->CI->lang->line('taxes_tax_excluded'), + Tax_lib::TAX_TYPE_INCLUDED => $this->CI->lang->line('taxes_tax_included') ); } /* * Compute the tax basis and returns the tax amount */ - public function get_item_sales_tax($quantity, $price, $discount_percentage, $tax_percentage, $rounding_code) + public function get_item_sales_tax($quantity, $price, $discount, $discount_type, $tax_percentage, $rounding_code) { $decimals = tax_decimals(); // The tax basis should be returned at the currency scale - $tax_basis = $this->CI->sale_lib->get_item_total($quantity, $price, $discount_percentage, TRUE); + $tax_basis = $this->CI->sale_lib->get_item_total($quantity, $price, $discount, $discount_type, TRUE); - return $this->get_sales_tax_for_amount($tax_basis, $tax_percentage, $rounding_code, $decimals); + return $this->get_tax_for_amount($tax_basis, $tax_percentage, $rounding_code, $decimals); } /* * Computes the item level sales tax amount for a given tax basis */ - public function get_sales_tax_for_amount($tax_basis, $tax_percentage, $rounding_mode, $decimals) + public function get_tax_for_amount($tax_basis, $tax_percentage, $rounding_mode, $decimals) { $tax_fraction = bcdiv($tax_percentage, 100); $tax_amount = bcmul($tax_basis, $tax_fraction); - $rounded_tax_amount = $tax_amount; return Rounding_mode::round_number($rounding_mode, $tax_amount, $decimals); } - /* - * Updates the sales_tax array which is later saved to the `sales_taxes` table and used for printing taxes on receipts and invoices - */ - public function update_sales_taxes(&$sales_taxes, $tax_type, $tax_group, $tax_rate, $tax_basis, $item_tax_amount, $tax_group_sequence, $rounding_code, $sale_id, $name='', $tax_code='') - { - $tax_group_index = $this->clean('X'.$tax_group); - if(!array_key_exists($tax_group_index, $sales_taxes)) + /** + * Compute taxes for all items in the cart + */ + public function get_taxes($cart) + { + $register_mode = $this->CI->sale_lib->get_mode(); + $tax_decimals = tax_decimals(); + $customer_id = $this->CI->sale_lib->get_customer(); + $customer_info = $this->CI->Customer->get_info($customer_id); + $taxes = array(); + $item_taxes = array(); + + // Charge sales tax if customer is not selected (walk-in) or customer is flagged as taxable + if($customer_id == -1 || $customer_info->taxable) + { + foreach($cart as $line => $item) + { + if(!($this->CI->config->item('use_destination_based_tax'))) + { + // Start of current Base System tax calculations + + $tax_info = $this->CI->Item_taxes->get_info($item['item_id']); + $tax_group_sequence = 0; + $cascade_level = 0; + $cascade_basis_level = 0; + + foreach($tax_info as $tax) + { + // This computes tax for each line item and adds it to the tax type total + $tax_basis = $this->CI->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], TRUE); + $tax_amount = 0.0; + + if($this->CI->config->item('tax_included')) + { + $tax_type = Tax_lib::TAX_TYPE_INCLUDED; + $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $tax['percent'], $tax_decimals, Rounding_mode::HALF_UP); + } + else + { + $tax_type = Tax_lib::TAX_TYPE_EXCLUDED; + $tax_amount = $this->get_tax_for_amount($tax_basis, $tax['percent'], Rounding_mode::HALF_UP, $tax_decimals); + } + + if($tax_amount <> 0) + { + $tax_group_sequence++; + $this->update_taxes($taxes, $tax_type, $tax['name'], $tax['percent'], $tax_basis, $tax_amount, $tax_group_sequence, Rounding_mode::HALF_UP, -1, $tax['name']); + $tax_group_sequence += 1; + } + $items_taxes_detail = array(); + $items_taxes_detail['item_id'] = $item['item_id']; + $items_taxes_detail['line'] = $item['line']; + $items_taxes_detail['name'] = $tax['name']; + $items_taxes_detail['percent'] = $tax['percent']; + $items_taxes_detail['tax_type'] = $tax_type; + $items_taxes_detail['rounding_code'] = Rounding_mode::HALF_UP; + $items_taxes_detail['cascade_sequence'] = 0; + $items_taxes_detail['item_tax_amount'] = $tax_amount; + $items_taxes_detail['sales_tax_code_id'] = NULL; + $items_taxes_detail['jurisdiction_id'] = NULL; + $items_taxes_detail['tax_category_id'] = NULL; + + $item_taxes[] = $items_taxes_detail; + } + } + else + { + // Start of destination based tax calculations + + if ($item['tax_category_id'] == NULL) + { + $item['tax_category_id'] = $this->CI->config->config['default_tax_category']; + } + $tax_category = ''; + $tax_rate = ''; + $rounding_code = Rounding_mode::HALF_UP; + $tax_group_sequence = 0; + $tax_code = ''; + $this->apply_destination_tax($item, $customer_info->city, $customer_info->state, $customer_info->sales_tax_code_id, $register_mode, 0, $taxes, $item_taxes, $item['line']); + } + } + $this->round_taxes($taxes); + } + + $tax_details = array(); + $tax_details[0] = $taxes; + $tax_details[1] = $item_taxes; + + return $tax_details; + } + + public function get_included_tax($quantity, $price, $discount_percentage, $tax_percentage, $tax_decimal, $rounding_code) + { + $price = $this->CI->sale_lib->get_item_total($quantity, $price, $discount_percentage, TRUE); + $tax_fraction = bcadd(100, $tax_percentage); + $tax_fraction = bcdiv($tax_fraction, 100); + $price_tax_excl = bcdiv($price, $tax_fraction); + $tax_amount = bcsub($price, $price_tax_excl); + + return Rounding_mode::round_number($rounding_code, $tax_amount, $tax_decimal); + } + + + /* + * Updates the sales_tax array which is later saved to the `sales_taxes` table and used for printing taxes on receipts and invoices + */ + public function update_taxes(&$taxes, $tax_type, $tax_group, $tax_rate, $tax_basis, $item_tax_amount, $tax_group_sequence, $rounding_code, $sale_id, $name = '', $tax_code_id = NULL, $jurisdiction_id = NULL,$tax_category_id = NULL ) + { + $tax_group_index = $this->clean('X' . (float)$tax_rate . '% ' . $tax_group); + + if(!array_key_exists($tax_group_index, $taxes)) { $insertkey = $tax_group_index; - $sales_tax = array($insertkey => array( + $tax = array($insertkey => array( 'sale_id' => $sale_id, 'tax_type' => $tax_type, 'tax_group' => $tax_group, @@ -74,101 +175,114 @@ class Tax_lib 'print_sequence' => $tax_group_sequence, 'name' => $name, 'tax_rate' => $tax_rate, - 'sales_tax_code' => $tax_code, + 'sales_tax_code_id' => $tax_code_id, + 'jurisdiction_id' => $jurisdiction_id, + 'tax_category_id' => $tax_category_id, 'rounding_code' => $rounding_code )); //add to existing array - $sales_taxes += $sales_tax; + $taxes += $tax; } else { // Important ... the sales amounts are accumulated for the group at the maximum configurable scale value of 4 // but the scale will in reality be the scale specified by the tax_decimal configuration value used for sales_items_taxes - $sales_taxes[$tax_group_index]['sale_tax_basis'] = bcadd($sales_taxes[$tax_group_index]['sale_tax_basis'], $tax_basis, 4); - $sales_taxes[$tax_group_index]['sale_tax_amount'] = bcadd($sales_taxes[$tax_group_index]['sale_tax_amount'], $item_tax_amount, 4); + $taxes[$tax_group_index]['sale_tax_basis'] = bcadd($taxes[$tax_group_index]['sale_tax_basis'], $tax_basis, 4); + $taxes[$tax_group_index]['sale_tax_amount'] = bcadd($taxes[$tax_group_index]['sale_tax_amount'], $item_tax_amount, 4); } } /* * If invoice taxing (as opposed to invoice_item_taxing) rules apply then recalculate the sales tax after tax group totals are final + * This is currently used ONLY for the original sales tax migration. */ - public function apply_invoice_taxing(&$sales_taxes) + public function apply_invoice_taxing(&$taxes) { - if(!empty($sales_taxes)) + if(!empty($taxes)) { $sort = array(); - foreach($sales_taxes as $k => $v) + foreach($taxes as $k => $v) { $sort['print_sequence'][$k] = $v['print_sequence']; } - array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes); + array_multisort($sort['print_sequence'], SORT_ASC, $taxes); } $decimals = totals_decimals(); - foreach($sales_taxes as $row_number => $sales_tax) + foreach($taxes as $row_number => $tax) { - $sales_taxes[$row_number]['sale_tax_amount'] = $this->get_sales_tax_for_amount($sales_tax['sale_tax_basis'], $sales_tax['tax_rate'], $sales_tax['rounding_code'], $decimals); + $taxes[$row_number]['sale_tax_amount'] = $this->get_tax_for_amount($tax['sale_tax_basis'], $tax['tax_rate'], $tax['rounding_code'], $decimals); } } /* * Apply rounding rules to the accumulated sales tax amounts */ - public function round_sales_taxes(&$sales_taxes) + public function round_taxes(&$taxes) { - if(!empty($sales_taxes)) + if(!empty($taxes)) { $sort = array(); - foreach($sales_taxes as $k=>$v) + foreach($taxes as $k => $v) { $sort['print_sequence'][$k] = $v['print_sequence']; } - array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes); + array_multisort($sort['print_sequence'], SORT_ASC, $taxes); } - $decimals = totals_decimals(); - - foreach($sales_taxes as $row_number => $sales_tax) + // If tax included then round decimal to tax decimals, otherwise round it to currency_decimals + if($this->CI->config->item('tax_included')) { - $sale_tax_amount = $sales_tax['sale_tax_amount']; + $decimals = tax_decimals(); + } + else + { + $decimals = totals_decimals(); + } + + + foreach($taxes as $row_number => $sales_tax) + { + $tax_amount = $sales_tax['sale_tax_amount']; $rounding_code = $sales_tax['rounding_code']; - $rounded_sale_tax_amount = $sale_tax_amount; + $rounded_tax_amount = $tax_amount; if($rounding_code == Rounding_mode::HALF_UP) { - $rounded_sale_tax_amount = round($sale_tax_amount, $decimals, PHP_ROUND_HALF_UP); + $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP); } elseif($rounding_code == Rounding_mode::HALF_DOWN) { - $rounded_sale_tax_amount = round($sale_tax_amount, $decimals, PHP_ROUND_HALF_DOWN); + $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_DOWN); } elseif($rounding_code == Rounding_mode::HALF_EVEN) { - $rounded_sale_tax_amount = round($sale_tax_amount, $decimals, PHP_ROUND_HALF_EVEN); + $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_EVEN); } elseif($rounding_code == Rounding_mode::HALF_ODD) { - $rounded_sale_tax_amount = round($sale_tax_amount, $decimals, PHP_ROUND_HALF_UP); + $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP); } elseif($rounding_code == Rounding_mode::ROUND_UP) { - $fig = (int) str_pad('1', $decimals, '0'); - $rounded_sale_tax_amount = (ceil($sale_tax_amount * $fig) / $fig); + $fig = (int)str_pad('1', $decimals, '0'); + $rounded_tax_amount = (ceil($tax_amount * $fig) / $fig); } elseif($rounding_code == Rounding_mode::ROUND_DOWN) { - $fig = (int) str_pad('1', $decimals, '0'); - $rounded_sale_tax_amount = (floor($sale_tax_amount * $fig) / $fig); + $fig = (int)str_pad('1', $decimals, '0'); + $rounded_tax_amount = (floor($tax_amount * $fig) / $fig); } elseif($rounding_code == Rounding_mode::HALF_FIVE) { - $rounded_sale_tax_amount = round($sale_tax_amount / 5) * 5; + $rounded_tax_amount = round($tax_amount / 5) * 5; } - $sales_taxes[$row_number]['sale_tax_amount'] = $rounded_sale_tax_amount; + $taxes[$row_number]['sale_tax_amount'] = $rounded_tax_amount; } + } @@ -176,110 +290,101 @@ class Tax_lib * Determine the applicable tax code and then determine the tax amount to be applied. * If a tax amount was identified then accumulate into the sales_taxes array */ - public function apply_sales_tax(&$item, &$city, &$state, &$sales_tax_code, $register_mode, $sale_id, &$sales_taxes) + public function apply_destination_tax(&$item, $city, $state, $sales_tax_code_id, $register_mode, $sale_id, &$taxes, &$item_taxes, $line) { - $tax_code = $this->get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code); + $tax_code_id = $this->get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code_id); // If tax code cannot be determined or the price is zero then skip this item - if($tax_code != '' && $item['price'] != 0) + if($tax_code_id != -1 && $item['price'] != 0) { - $tax_rate = 0.0000; - $rounding_code = Rounding_mode::HALF_UP; + $tax_decimals = tax_decimals(); - $tax_code_obj = $this->CI->Tax->get_info($tax_code); - $tax_category_id = $item['tax_category_id']; + $tax_definition = $this->CI->Tax->get_taxes($tax_code_id, $item['tax_category_id']); - if($tax_category_id != 0) + // The tax basis should be returned at the currency scale + $tax_basis = $this->CI->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], TRUE); + + $row = 0; + + $last_cascade_sequence = 0; + $cascade_tax_amount = 0.0; + + foreach($tax_definition as $tax) { - $tax_rate_info = $this->CI->Tax->get_rate_info($tax_code, $tax_category_id); - if($tax_rate_info) + $cascade_sequence = $tax['cascade_sequence']; + if($cascade_sequence != $last_cascade_sequence) { - $tax_rate = $tax_rate_info->tax_rate; - $rounding_code = $tax_rate_info->rounding_code; + $last_cascade_sequence = $cascade_sequence; + $tax_basis = $tax_basis + $cascade_tax_amount; + } + + $tax_rate = $tax['tax_rate']; + $rounding_code = $tax['tax_rounding_code']; + + // This computes tax for each line item and adds it to the tax type total + + $tax_type = $tax['tax_type']; + + if($tax_type == Tax_lib::TAX_TYPE_INCLUDED) + { + $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $tax_rate, $tax_decimals, $rounding_code); } else { - $tax_rate = $tax_code_obj->tax_rate; - $rounding_code = $tax_code_obj->rounding_code; + $tax_amount = $this->get_tax_for_amount($tax_basis, $tax_rate, $rounding_code, $tax_decimals); + $cascade_tax_amount = $cascade_tax_amount + $tax_amount; } + + if($tax_amount != 0) + { + + $this->update_taxes($taxes, $tax_type, $tax['tax_group'], $tax_rate, $tax_basis, $tax_amount, $tax['tax_group_sequence'], $rounding_code, $sale_id, $tax['tax_group'], $tax_code_id, $tax['rate_jurisdiction_id'], $item['tax_category_id']); + } + + $item_taxes_detail = array(); + $item_taxes_detail['line'] = $line; + $item_taxes_detail['item_id'] = $item['item_id']; + $item_taxes_detail['name'] = $tax['tax_group']; + $item_taxes_detail['percent'] = $tax['tax_rate']; + $item_taxes_detail['tax_type'] = $tax_type; + $item_taxes_detail['rounding_code'] = $rounding_code; + $item_taxes_detail['cascade_sequence'] = $cascade_sequence; + $item_taxes_detail['item_tax_amount'] = $tax_amount; + $item_taxes_detail['sales_tax_code_id'] = $tax_code_id; + $item_taxes_detail['jurisdiction_id'] = $tax['rate_jurisdiction_id']; + $item_taxes_detail['tax_category_id'] = $tax['rate_tax_category_id']; + $item_taxes_detail['tax_group_sequence'] = $tax['tax_group_sequence']; + + $item_taxes[] = $item_taxes_detail; } - - if($tax_category_id != 0) - { - $tax_rate_info = $this->CI->Tax->get_rate_info($tax_code, $tax_category_id); - $tax_rate = $tax_rate_info->tax_rate; - $rounding_code = $tax_rate_info->rounding_code; - $tax_group_sequence = $tax_rate_info->tax_group_sequence; - $tax_category = $tax_rate_info->tax_category; - } - else - { - $tax_rate = $tax_code_obj->tax_rate; - $rounding_code = $tax_code_obj->rounding_code; - $tax_group_sequence = $tax_code_obj->tax_group_sequence; - $tax_category = $tax_code_obj->tax_category; - } - - $decimals = tax_decimals(); - - // The tax basis should be returned at the currency scale - $tax_basis = $this->CI->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], TRUE); - $tax_amount = $this->get_sales_tax_for_amount($tax_basis, $tax_rate, $rounding_code, $decimals); - - $tax_group = (float)$tax_rate . '% ' . $tax_category; - $tax_type = Tax_lib::TAX_TYPE_SALES; - - if($tax_amount != 0) - { - $this->update_sales_taxes($sales_taxes, $tax_type, $tax_group, $tax_rate, $tax_basis, $tax_amount, $tax_group_sequence, $rounding_code, $sale_id, $tax_category, $tax_code); - } - - // input : register_mode - // input : city - // input : state - // input : sales_tax_code - // input : $item['price'] - // input : $item['tax_category_id'] - // input : $item['quantity'] - // input : $item['price'] - // input : $item['discount'] - // both : $sales_taxes - // output : tax_details['tax_rate'] - // output : tax_details['rounding_code'] - // output : tax_details['tax_group_sequence'] - // output : tax_details['tax_code'] - - $tax_details = array('item_tax_amount' => $tax_amount, 'tax_group' => $tax_group, 'tax_name' => $tax_category, 'tax_rate' => $tax_rate, 'rounding_code' => $rounding_code, 'tax_group_sequence' => $tax_group_sequence, 'tax_code' => $tax_code); - - return $tax_details; + return; } else { - $tax_details = array('item_tax_amount' => 0.0000, 'tax_group' => '', 'tax_name' => '', 'tax_rate' => 0.0000, 'rounding_code' => '0', 'tax_group_sequence' => '0', 'tax_code' => ''); - return $tax_details; + return; } } - public function get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code) + public function get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code_id) { + if($register_mode == "sale") { - $tax_code = $this->CI->config->config['default_origin_tax_code']; // overrides customer assigned code + $sales_tax_code_id = $this->CI->config->config['default_tax_code']; // overrides customer assigned code } else { - if($sales_tax_code == '') + if($sales_tax_code_id == NULL || $sales_tax_code_id == 0) { - $tax_code = $this->CI->Tax->get_sales_tax_code($city, $state); - } - else - { - // Use the customer assigned tax rate code - $tax_code = $sales_tax_code; + $sales_tax_code_id = $this->CI->Tax_code->get_sales_tax_code($city, $state); + + if($sales_tax_code_id == NULL || $sales_tax_code_id == 0) { + $sales_tax_code_id = $this->CI->config->config['default_tax_code']; // overrides customer assigned code + } } } - return $tax_code; + return $sales_tax_code_id; } public function clean($string) @@ -288,5 +393,68 @@ class Tax_lib return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars. } + + public function get_tax_code_options() + { + $tax_codes = $this->CI->Tax_code->get_all()->result_array(); + $tax_code_options = array(); + $tax_code_options[''] = ''; + foreach($tax_codes as $tax_code) + { + $a = $tax_code['tax_code_id']; + $b = $tax_code['tax_code_name']; + $tax_code_options[$a] = $b; + } + return $tax_code_options; + } + + public function get_tax_jurisdiction_options() + { + $tax_jurisdictions = $this->CI->Tax_jurisdiction->get_all()->result_array(); + $tax_jurisdiction_options = array(); + $tax_jurisdiction_options[0] = ''; + foreach($tax_jurisdictions as $tax_jurisdiction) + { + $a = $tax_jurisdiction['jurisdiction_id']; + $b = $tax_jurisdiction['jurisdiction_name']; + $tax_jurisdiction_options[$a] = $b; + } + return $tax_jurisdiction_options; + } + + public function get_tax_category_options() + { + $tax_categories = $this->CI->Tax_category->get_all()->result_array(); + $tax_category_options = array(); + $tax_category_options[0] = ''; + foreach($tax_categories as $tax_category) + { + $a = $tax_category['tax_category_id']; + $b = $tax_category['tax_category']; + + $tax_category_options[$a] = $b; + } + return $tax_category_options; + } + + public function get_tax_type_options($selected_tax_type) + { + $selected = 'selected=\"selected\" '; + + $s1 = ''; + $s2 = ''; + + if($selected_tax_type == Tax_lib::TAX_TYPE_EXCLUDED) + { + $s1 = $selected; + } + else if($selected_tax_type == Tax_lib::TAX_TYPE_INCLUDED) + { + $s2 = $selected; + } + return ''; + } + } ?> diff --git a/application/migrations/20170502221506_sales_tax_data.php b/application/migrations/20170502221506_sales_tax_data.php index 921d5c63e..9167c97a3 100644 --- a/application/migrations/20170502221506_sales_tax_data.php +++ b/application/migrations/20170502221506_sales_tax_data.php @@ -36,18 +36,10 @@ class Migration_Sales_Tax_Data extends CI_Migration private function upgrade_tax_history_for_sale($sale_id) { $CI =& get_instance(); - $tax_decimals = $CI->config->config['tax_decimals']; - $tax_included = $CI->config->config['tax_included']; - $customer_sales_tax_support = $CI->config->config['customer_sales_tax_support']; - - if($tax_included) - { - $tax_type = Tax_lib::TAX_TYPE_VAT; - } - else - { - $tax_type = Tax_lib::TAX_TYPE_SALES; - } + $tax_decimals = $CI->Appconfig->get('tax_decimals', 2); + $tax_included = $CI->Appconfig->get('tax_included', 0); + $customer_sales_tax_support = $CI->Appconfig->get('customer_sales_tax_support', 0); + $tax_type = $tax_included ? Tax_lib::TAX_TYPE_INCLUDED : Tax_lib::TAX_TYPE_EXCLUDED; $sales_taxes = array(); $tax_group_sequence = 0; @@ -57,11 +49,11 @@ class Migration_Sales_Tax_Data extends CI_Migration { // This computes tax for each line item and adds it to the tax type total $tax_group = (float)$item['percent'] . '% ' . $item['name']; - $tax_basis = $this->sale_lib->get_item_total($item['quantity_purchased'], $item['item_unit_price'], $item['discount_percent'], TRUE); + $tax_basis = $this->sale_lib->get_item_total($item['quantity_purchased'], $item['item_unit_price'], $item['discount_percent'], PERCENT, TRUE); $item_tax_amount = 0; if($tax_included) { - $item_tax_amount = $this->sale_lib->get_item_tax($item['quantity_purchased'], $item['item_unit_price'], $item['discount_percent'], $item['percent']); + $item_tax_amount = $this->sale_lib->get_item_tax($item['quantity_purchased'], $item['item_unit_price'], $item['discount_percent'], PERCENT, $item['percent']); } else { @@ -78,7 +70,7 @@ class Migration_Sales_Tax_Data extends CI_Migration $this->tax_lib->apply_invoice_taxing($sales_taxes); } - $this->tax_lib->round_sales_taxes($sales_taxes); + $this->tax_lib->round_taxes($sales_taxes); $this->save_sales_tax($sales_taxes); } diff --git a/application/migrations/20180429100000_upgrade_to_3_2_1.php b/application/migrations/20180501100000_upgrade_to_3_2_1.php similarity index 100% rename from application/migrations/20180429100000_upgrade_to_3_2_1.php rename to application/migrations/20180501100000_upgrade_to_3_2_1.php diff --git a/application/migrations/20181015100000_attributes.php b/application/migrations/20181015100000_attributes.php new file mode 100644 index 000000000..521e7b15d --- /dev/null +++ b/application/migrations/20181015100000_attributes.php @@ -0,0 +1,20 @@ + diff --git a/application/migrations/20190111270000_upgrade_to_3_3_0.php b/application/migrations/20190111270000_upgrade_to_3_3_0.php new file mode 100644 index 000000000..fda74aa77 --- /dev/null +++ b/application/migrations/20190111270000_upgrade_to_3_3_0.php @@ -0,0 +1,20 @@ + diff --git a/application/migrations/20190129212600_indiagst.php b/application/migrations/20190129212600_indiagst.php new file mode 100644 index 000000000..9e9836cf1 --- /dev/null +++ b/application/migrations/20190129212600_indiagst.php @@ -0,0 +1,151 @@ +db->field_exists('sales_tax_code', 'customers')) + { + return; + } + + // If number of entries is greater than zero then the tax data needs to be migrated + execute_script(APPPATH . 'migrations/sqlscripts/3.3.0_indiagst.sql'); + + error_log('Migrating tax configuration'); + + $count_of_tax_codes = $this->get_count_of_tax_code_entries(); + if($count_of_tax_codes > 0) + { + $this->migrate_tax_code_data(); + } + + + $this->migrate_customer_tax_codes(); + + $count_of_rate_entries = $this->get_count_of_rate_entries(); + + if($count_of_rate_entries > 0) + { + $this->migrate_tax_rates(); + } + + $count_of_sales_taxes_entries = $this->get_count_of_sales_taxes_entries(); + if($count_of_sales_taxes_entries > 0) + { + $this->migrate_sales_taxes_data(); + } + + error_log('Migrating tax configuration completed'); + } + + public function down() + { + $this->drop_backups(); + } + + private function get_count_of_tax_code_entries() + { + $this->db->select('COUNT(*) as count'); + $this->db->from('tax_codes_backup'); + + return $this->db->get()->row()->count; + } + + private function get_count_of_sales_taxes_entries() + { + $this->db->select('COUNT(*) as count'); + $this->db->from('sales_taxes'); + + return $this->db->get()->row()->count; + } + + private function get_count_of_rate_entries() + { + $this->db->select('COUNT(*) as count'); + $this->db->from('tax_code_rates_backup'); + + return $this->db->get()->row()->count; + } + + /* + * This copies the old tax code configuration into the new tax code configuration + * assigning a tax_code_id id to the entry This only needs to be done if there are + * tax codes in the table. + */ + private function migrate_tax_code_data() + { + $this->db->query('INSERT INTO ' . $this->db->dbprefix('tax_codes') . ' (tax_code, tax_code_name, city, state) + SELECT tax_code, tax_code_name, city, state FROM ' . $this->db->dbprefix('tax_codes_backup')); + + } + + /* + * The previous upgrade script added the new column to the customers table. + * This will assign a tax code id using the tax code field that was left in place on the customer table. + * After it is complete then it will drop the old customer tax code. + * This MUST run so that the old tax code is dropped + */ + private function migrate_customer_tax_codes() + { + $this->db->query('UPDATE ' . $this->db->dbprefix('customers') . ' AS fa SET fa.sales_tax_code_id = ( + SELECT tax_code_id FROM ' . $this->db->dbprefix('tax_codes') . ' AS fb where fa.sales_tax_code = fb.tax_code)'); + + $this->db->query('ALTER TABLE ' . $this->db->dbprefix('customers') . ' DROP COLUMN sales_tax_code'); + } + + /** + * The sales taxes table is undergoing a significant primary key change + * The new table assumes that sales taxes are associated with a jurisdiction + * For base taxes and the older tax system the tax jurisdiction code table will be + * initialized with an entry that is used to represent a dummy or consolidated jurisdiction. + * If there is only one tax jurisdiction then it can be renamed and life moves on. + * If the user wants to start reporting taxes by jurisdiction then the new jurisdictions need + * to be created and defined manually AFTER the upgrade. + * CONVERTING OLD TAX DATA TO BE SPLIT OUT BY JURISDICTION IS BEYOND THE SCOPE OF THIS EFFORT + */ + private function migrate_sales_taxes_data() + { + $this->db->query('INSERT INTO ' . $this->db->dbprefix('sales_taxes') + . ' (sale_id, jurisdiction_id, tax_category_id, tax_type, tax_group, sale_tax_basis, sale_tax_amount, print_sequence, ' + . '`name`, tax_rate, sales_tax_code_id, rounding_code) ' + . 'select sale_id, rate_jurisdiction_id, rate_tax_category_id, tax_type, tax_group, sale_tax_basis, sale_tax_amount, ' + . 'print_sequence, `name`, A.tax_rate, tax_code_id, rounding_code ' + . 'from ' . $this->db->dbprefix('sales_taxes_backup') . ' AS A ' + . 'left outer join ' . $this->db->dbprefix('tax_codes') . ' AS B on sales_tax_code = tax_code ' + . 'left outer join ' . $this->db->dbprefix('tax_rates') . ' AS C on tax_code_id = rate_tax_code_id and A.tax_rate = C.tax_rate ' + . 'order by sale_id'); + } + + private function migrate_tax_rates() + { + // create a dummy jurisdiction record and retrieve the jurisdiction rate id + + $this->db->query('INSERT INTO ' . $this->db->dbprefix('tax_jurisdictions') . ' (jurisdiction_name, tax_group, tax_type, reporting_authority, ' + . "tax_group_sequence, cascade_sequence, deleted) VALUES ('Jurisdiction1','TaxGroup1','1','Authority1',1,0,'0')"); + + $jurisdiction_id = $this->db->query('SELECT jurisdiction_id FROM ' . $this->db->dbprefix('tax_jurisdictions') . " WHERE jurisdiction_name = 'Jurisdiction1'")->row()->jurisdiction_id; + + + // Insert old tax_code rates data into the new tax rates table + + $this->db->query('INSERT INTO ' . $this->db->dbprefix('tax_rates') + . ' (rate_tax_category_id, rate_jurisdiction_id, rate_tax_code_id, tax_rate, tax_rounding_code) ' + . 'SELECT rate_tax_category_id, ' . $jurisdiction_id . ', tax_code_id, tax_rate, rounding_code FROM ' + . $this->db->dbprefix('tax_code_rates_backup') . ' JOIN ' . $this->db->dbprefix('tax_codes') + . ' ON tax_code = rate_tax_code'); + } + + private function drop_backups() + { + $this->db->query('DROP TABLE IF EXISTS' . $this->db->dbprefix('tax_codes_backup')); + $this->db->query('DROP TABLE IF EXISTS' . $this->db->dbprefix('sales_taxes_backup')); + $this->db->query('DROP TABLE IF EXISTS' . $this->db->dbprefix('tax_code_rates_backup')); + } +} +?> diff --git a/application/migrations/sqlscripts/3.0.2_to_3.1.1.sql b/application/migrations/sqlscripts/3.0.2_to_3.1.1.sql index a74b193d1..f1b80715b 100644 --- a/application/migrations/sqlscripts/3.0.2_to_3.1.1.sql +++ b/application/migrations/sqlscripts/3.0.2_to_3.1.1.sql @@ -69,7 +69,8 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('last_used_invoice_number', '0'), ('last_used_quote_number', '0'), ('line_sequence', '0'), -('dinner_table_enable', '0'); +('dinner_table_enable', '0'), +('customer_sales_tax_support', '0'); -- -- Table structure for table `ospos_customer_packages` @@ -259,15 +260,8 @@ DELETE FROM `ospos_tax_categories` where tax_category_id in (0, 1, 2, 3); ALTER TABLE `ospos_tax_categories` MODIFY COLUMN `tax_category_id` int(10) NOT NULL AUTO_INCREMENT; -INSERT INTO `ospos_tax_categories` ( `tax_category_id`, `tax_category`, `tax_group_sequence` ) VALUES -(1, 'Standard', 10), -(2, 'Service', 12), -(3, 'Alcohol', 11); - ALTER TABLE `ospos_items` - MODIFY COLUMN `tax_category_id` int(10) NOT NULL DEFAULT 1; - -UPDATE `ospos_items` SET `tax_category_id` = 1 WHERE `tax_category_id` = 0; + MODIFY COLUMN `tax_category_id` int(10) DEFAULT NULL; -- If you have added any tax codes, the following will correct the rate_tax_category_id on the tax_code_rates table, -- but you might need to add more UPDATE statements depending on how may tax codes and/or tax categories you've added @@ -415,3 +409,4 @@ ALTER TABLE ospos_items -- Change language code en to be en-US UPDATE `ospos_app_config` SET `value` = 'en-US' WHERE `key` = 'language_code' AND `value` = 'en'; + diff --git a/application/migrations/sqlscripts/3.1.1_to_3.2.0.sql b/application/migrations/sqlscripts/3.1.1_to_3.2.0.sql index de433753f..4fa20ba59 100644 --- a/application/migrations/sqlscripts/3.1.1_to_3.2.0.sql +++ b/application/migrations/sqlscripts/3.1.1_to_3.2.0.sql @@ -142,9 +142,6 @@ CREATE TABLE IF NOT EXISTS `ospos_expense_categories` ( `deleted` int(1) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `ospos_expense_categories` (`expense_category_id`, `category_name`, `category_description`) VALUES -(1, 'Utilities', 'Water'); - -- Table structure for table `ospos_expenses` @@ -160,12 +157,6 @@ CREATE TABLE IF NOT EXISTS `ospos_expenses` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- Dumping data for table `ospos_expenses` - -INSERT INTO `ospos_expenses` (`expense_id`, `date`, `amount`, `expense_category_id`, `description`, `employee_id`) VALUES -(1, '2017-04-20 07:00:00', '15.00', 1, 'Water', 1); - - -- Indexes for table `ospos_expense_categories` ALTER TABLE `ospos_expense_categories` diff --git a/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql b/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql index ac92db486..d7c93906b 100644 --- a/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql +++ b/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql @@ -13,3 +13,14 @@ ALTER TABLE `ospos_customers` INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('enforce_privacy', '0'); + + +-- Add print receipt autoreturn delay + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('print_delay_autoreturn', '0'); + + +-- Insure that the receiving quantity is not zero + +UPDATE ospos_receivings_items SET receiving_quantity = 1 WHERE receiving_quantity = 0; diff --git a/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql b/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql new file mode 100644 index 000000000..eb39e4595 --- /dev/null +++ b/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql @@ -0,0 +1,153 @@ +-- +-- Add support for Multi-Package Items +-- + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('multi_pack_enabled', '0'); + +ALTER TABLE `ospos_items` + ADD COLUMN `qty_per_pack` decimal(15,3) NOT NULL DEFAULT 1 AFTER `tax_category_id`, + ADD COLUMN `pack_name` varchar(8) DEFAULT 'Each' AFTER `qty_per_pack`, + ADD COLUMN `low_sell_item_id` int(10) DEFAULT 0 AFTER `pack_name`; + +UPDATE `ospos_items` + SET `low_sell_item_id` = `item_id` + WHERE `low_sell_item_id` = 0; + +-- +-- Add support for Discount on Sales Fixed +-- + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('default_sales_discount_type', '0'); + +ALTER TABLE `ospos_item_kits` + CHANGE COLUMN `kit_discount_percent` `kit_discount` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `item_id`, + ADD COLUMN `kit_discount_type` TINYINT(2) NOT NULL DEFAULT '0' AFTER `kit_discount`; + +ALTER TABLE `ospos_customers` + CHANGE COLUMN `discount_percent` `discount` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `sales_tax_code`, + ADD COLUMN `discount_type` TINYINT(2) NOT NULL DEFAULT '0' AFTER `discount`; + +ALTER TABLE `ospos_sales_items` + CHANGE COLUMN `discount_percent` `discount` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `item_unit_price`, + ADD COLUMN `discount_type` TINYINT(2) NOT NULL DEFAULT '0' AFTER `discount`; + +ALTER TABLE `ospos_receivings_items` + CHANGE COLUMN `discount_percent` `discount` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `item_unit_price`, + ADD COLUMN `discount_type` TINYINT(2) NOT NULL DEFAULT '0' AFTER `discount`; + +-- +-- Add support for module cashups +-- + +-- Set config module sort number to one of the latest + +UPDATE `ospos_modules` +SET `sort` = 900 +WHERE `name_lang_key` = 'module_config'; + +-- Add cashup module + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES +('module_cashups', 'module_cashups_desc', 110, 'cashups'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES +('cashups', 'cashups'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES +('cashups', 1); + +-- Table structure for table `ospos_cash_up` + +CREATE TABLE `ospos_cash_up` ( + `cashup_id` int(10) NOT NULL, + `open_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `close_date` timestamp NULL, + `open_amount_cash` decimal(15,2) NOT NULL, + `transfer_amount_cash` decimal(15,2) NOT NULL, + `note` int(1) NOT NULL, + `closed_amount_cash` decimal(15,2) NOT NULL, + `closed_amount_card` decimal(15,2) NOT NULL, + `closed_amount_check` decimal(15,2) NOT NULL, + `closed_amount_total` decimal(15,2) NOT NULL, + `description` varchar(255) NOT NULL, + `open_employee_id` int(10) NOT NULL, + `close_employee_id` int(10) NOT NULL, + `deleted` int(1) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Indexes for table `ospos_cash_up` + +ALTER TABLE `ospos_cash_up` + ADD PRIMARY KEY (`cashup_id`), + ADD KEY `open_employee_id` (`open_employee_id`), + ADD KEY `close_employee_id` (`close_employee_id`), + ADD CONSTRAINT `ospos_cash_up_ibfk_1` FOREIGN KEY (`open_employee_id`) REFERENCES `ospos_employees` (`person_id`), + ADD CONSTRAINT `ospos_cash_up_ibfk_2` FOREIGN KEY (`close_employee_id`) REFERENCES `ospos_employees` (`person_id`); + +-- AUTO_INCREMENT for table `ospos_cash_up` + +ALTER TABLE `ospos_cash_up` + MODIFY `cashup_id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1; + +-- Change collation on columns to be utf8_general_ci + +ALTER TABLE ospos_cash_up CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; +ALTER TABLE ospos_expense_categories CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; +ALTER TABLE ospos_expenses CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; + +-- Add amount due + +ALTER TABLE `ospos_cash_up` + ADD `closed_amount_due` decimal(15,2) NOT NULL; + +-- +-- Add Suppliers category +-- + +ALTER TABLE `ospos_suppliers` + ADD COLUMN `category` TINYINT NOT NULL; + +UPDATE `ospos_suppliers` + SET `category` = 0; + + +-- +-- Link Expenses with Suppliers +-- + +-- Add supplier id + +ALTER TABLE `ospos_expenses` + ADD COLUMN `supplier_id` int(10) NULL; + +-- Link suppliers + +UPDATE `ospos_expenses` + INNER JOIN `ospos_suppliers` + ON `ospos_expenses`.`supplier_name` = `ospos_suppliers`.`company_name` +SET `ospos_expenses`.`supplier_id` = `ospos_suppliers`.`person_id`; + +-- Save name in description for those expenses whose supplier isn't registered + +UPDATE `ospos_expenses` + SET `description` = CONCAT(`description`, CONCAT('\nSupplier name: ', `supplier_name`)) + WHERE `supplier_id` is NULL; + +-- Add foreign key + +ALTER TABLE `ospos_expenses` + ADD CONSTRAINT `ospos_expenses_ibfk_3` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`); + +-- Delete supplier name + +ALTER TABLE `ospos_expenses` + DROP COLUMN `supplier_name`; + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES + ('default_receivings_discount_type', '0'), + ('default_receivings_discount', '0'); + +ALTER TABLE `ospos_suppliers` + CHANGE COLUMN `tax_id` `tax_id` VARCHAR(32) NULL; \ No newline at end of file diff --git a/application/migrations/sqlscripts/3.3.0_indiagst.sql b/application/migrations/sqlscripts/3.3.0_indiagst.sql new file mode 100644 index 000000000..f17bb2ea8 --- /dev/null +++ b/application/migrations/sqlscripts/3.3.0_indiagst.sql @@ -0,0 +1,100 @@ +-- -------------------------------- +-- Start of India GST Tax Changes +-- -------------------------------- + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('include_hsn', '0'), +('invoice_type', 'invoice'), +('default_tax_jurisdiction', ''), +('tax_id', ''); + +UPDATE `ospos_app_config` + SET `key` = 'use_destination_based_tax' + WHERE `key` = 'customer_sales_tax_support'; + +UPDATE `ospos_app_config` + SET `key` = 'default_tax_code' + WHERE `key` = 'default_origin_tax_code'; + +RENAME TABLE `ospos_tax_codes` TO `ospos_tax_codes_backup`; + +CREATE TABLE IF NOT EXISTS `ospos_tax_codes` ( + `tax_code_id` int(11) NOT NULL AUTO_INCREMENT, + `tax_code` varchar(32) NOT NULL, + `tax_code_name` varchar(255) NOT NULL DEFAULT '', + `city` varchar(255) NOT NULL DEFAULT '', + `state` varchar(255) NOT NULL DEFAULT '', + `deleted` int(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`tax_code_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `ospos_customers` + ADD COLUMN `tax_id` varchar(32) NOT NULL DEFAULT '' AFTER `taxable`, + ADD COLUMN `sales_tax_code_id` int(11) DEFAULT NULL AFTER `tax_id`; + +ALTER TABLE `ospos_items` + ADD COLUMN `hsn_code` varchar(32) NOT NULL DEFAULT '' AFTER `low_sell_item_id`; + +ALTER TABLE `ospos_sales_items_taxes` + ADD COLUMN `sales_tax_code_id` int(11) DEFAULT NULL AFTER `item_tax_amount`, + ADD COLUMN `jurisdiction_id` int(11) DEFAULT NULL AFTER `sales_tax_code_id`, + ADD COLUMN `tax_category_id` int(11) DEFAULT NULL AFTER `jurisdiction_id`, + DROP COLUMN `cascade_tax`; + +RENAME TABLE `ospos_sales_taxes` TO `ospos_sales_taxes_backup`; + +CREATE TABLE `ospos_sales_taxes` ( + `sales_taxes_id` int(11) NOT NULL AUTO_INCREMENT, + `sale_id` int(10) NOT NULL, + `jurisdiction_id` int(11) DEFAULT NULL, + `tax_category_id` int(11) DEFAULT NULL, + `tax_type` smallint(2) NOT NULL, + `tax_group` varchar(32) NOT NULL, + `sale_tax_basis` decimal(15,4) NOT NULL, + `sale_tax_amount` decimal(15,4) NOT NULL, + `print_sequence` tinyint(2) NOT NULL DEFAULT 0, + `name` varchar(255) NOT NULL, + `tax_rate` decimal(15,4) NOT NULL, + `sales_tax_code_id` int(11) DEFAULT NULL, + `rounding_code` tinyint(2) NOT NULL DEFAULT 0, + PRIMARY KEY (`sales_taxes_id`), + KEY `print_sequence` (`sale_id`,`print_sequence`,`tax_group`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `ospos_tax_jurisdictions` ( + `jurisdiction_id` int(11) NOT NULL AUTO_INCREMENT, + `jurisdiction_name` varchar(255) DEFAULT NULL, + `tax_group` varchar(32) NOT NULL, + `tax_type` smallint(2) NOT NULL, + `reporting_authority` varchar(255) DEFAULT NULL, + `tax_group_sequence` tinyint(2) NOT NULL DEFAULT 0, + `cascade_sequence` tinyint(2) NOT NULL DEFAULT 0, + `deleted` int(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`jurisdiction_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; + +ALTER TABLE `ospos_suppliers` + ADD COLUMN `tax_id` varchar(32) NOT NULL DEFAULT '' AFTER `account_number`; + +ALTER TABLE `ospos_tax_categories` + ADD COLUMN `deleted` int(1) NOT NULL DEFAULT 0 AFTER `tax_group_sequence`; + +RENAME TABLE `ospos_tax_code_rates` TO `ospos_tax_code_rates_backup`; + +CREATE TABLE IF NOT EXISTS `ospos_tax_rates` ( + `tax_rate_id` int(11) NOT NULL AUTO_INCREMENT, + `rate_tax_code_id` int(11) NOT NULL, + `rate_tax_category_id` int(10) NOT NULL, + `rate_jurisdiction_id` int(11) NOT NULL, + `tax_rate` decimal(15,4) NOT NULL DEFAULT 0.0000, + `tax_rounding_code` tinyint(2) NOT NULL DEFAULT 0, + PRIMARY KEY (`tax_rate_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Add support for sales tax report + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES +('reports_sales_taxes', 'reports'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES +('reports_sales_taxes', 1, 'home'); diff --git a/application/migrations/sqlscripts/attributes.sql b/application/migrations/sqlscripts/attributes.sql new file mode 100644 index 000000000..66641d298 --- /dev/null +++ b/application/migrations/sqlscripts/attributes.sql @@ -0,0 +1,184 @@ + +CREATE TABLE IF NOT EXISTS `ospos_attribute_definitions` ( + `definition_id` INT(10) NOT NULL AUTO_INCREMENT, + `definition_name` VARCHAR(255) NOT NULL, + `definition_type` VARCHAR(45) NOT NULL, + `definition_flags` TINYINT(4) NOT NULL, + `definition_fk` INT(10) NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`definition_id`), + KEY `definition_fk` (`definition_fk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_values` ( + `attribute_id` INT NOT NULL AUTO_INCREMENT, + `attribute_value` VARCHAR(255) UNIQUE NULL, + `attribute_datetime` DATETIME NULL, + PRIMARY KEY (`attribute_id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_links` ( + `attribute_id` INT NULL, + `definition_id` INT NOT NULL, + `item_id` INT NULL, + `sale_id` INT NULL, + `receiving_id` INT NULL, + KEY `attribute_id` (`attribute_id`), + KEY `definition_id` (`definition_id`), + KEY `item_id` (`item_id`), + KEY `sale_id` (`sale_id`), + KEY `receiving_id` (`receiving_id`), + UNIQUE `attribute_links_uq1` (`attribute_id`, `definition_id`, `item_id`, `sale_id`, `receiving_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + + +ALTER TABLE `ospos_attribute_definitions` + ADD CONSTRAINT `fk_ospos_attribute_definitions_ibfk_1` FOREIGN KEY (`definition_fk`) REFERENCES `ospos_attribute_definitions` (`definition_id`); + + +ALTER TABLE `ospos_attribute_links` + ADD CONSTRAINT `ospos_attribute_links_ibfk_1` FOREIGN KEY (`definition_id`) REFERENCES `ospos_attribute_definitions` (`definition_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `ospos_attribute_values` (`attribute_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_4` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_5` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES + ('module_attributes', 'module_attributes_desc', 107, 'attributes'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES + ('attributes', 'attributes'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES + ('attributes', 1, 'office'); + +-- migrate custom fields to text attributes +-- NOTE: items with custom attributes won't keep their selected category!! +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom1_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom2_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom3_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom4_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom5_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom6_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom7_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom8_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom9_name' AND `value` <> ''; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type, definition_flags) SELECT `value`, 'TEXT', 1 FROM ospos_app_config WHERE `key` = 'custom10_name' AND `value` <> ''; + +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom1_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom1 IS NOT NULL AND custom1 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom2_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom2 IS NOT NULL AND custom2 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom3_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom3 IS NOT NULL AND custom3 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom4_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom4 IS NOT NULL AND custom4 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom5_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom5 IS NOT NULL AND custom5 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom6_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom6 IS NOT NULL AND custom6 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom7_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom7 IS NOT NULL AND custom7 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom8_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom8 IS NOT NULL AND custom8 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom9_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom9 IS NOT NULL AND custom9 != ''; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom10_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom10 IS NOT NULL AND custom10 != ''; + +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom1 FROM ospos_items WHERE custom1 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom1_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom2 FROM ospos_items WHERE custom2 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom2_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom3 FROM ospos_items WHERE custom3 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom3_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom4 FROM ospos_items WHERE custom4 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom4_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom5 FROM ospos_items WHERE custom5 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom5_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom6 FROM ospos_items WHERE custom6 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom6_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom7 FROM ospos_items WHERE custom7 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom7_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom8 FROM ospos_items WHERE custom8 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom8_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom9 FROM ospos_items WHERE custom9 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom9_name'); +INSERT IGNORE INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom10 FROM ospos_items WHERE custom10 <> '' AND '' <> (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom10_name'); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom1 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom1_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom2 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom2_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom3 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom3_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom4 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom4_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom5 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom5_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom6 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom6_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom7 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom7_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom8 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom8_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom9 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom9_name' AND `value` IS NOT NULL)); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom10 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom10_name' AND `value` IS NOT NULL)); + +ALTER TABLE `ospos_items` + DROP COLUMN `custom1`, + DROP COLUMN `custom2`, + DROP COLUMN `custom3`, + DROP COLUMN `custom4`, + DROP COLUMN `custom5`, + DROP COLUMN `custom6`, + DROP COLUMN `custom7`, + DROP COLUMN `custom8`, + DROP COLUMN `custom9`, + DROP COLUMN `custom10`; + + DELETE FROM `ospos_app_config` WHERE `key` IN ('custom1_name','custom2_name','custom3_name','custom4_name','custom5_name','custom6_name','custom7_name','custom8_name','custom9_name','custom10_name'); diff --git a/application/models/Appconfig.php b/application/models/Appconfig.php index 09cfef6ef..373c4a842 100644 --- a/application/models/Appconfig.php +++ b/application/models/Appconfig.php @@ -22,7 +22,7 @@ class Appconfig extends CI_Model return $this->db->get(); } - public function get($key) + public function get($key, $default = '') { $query = $this->db->get_where('app_config', array('key' => $key), 1); @@ -31,7 +31,7 @@ class Appconfig extends CI_Model return $query->row()->value; } - return ''; + return $default; } public function save($key, $value) diff --git a/application/models/Attribute.php b/application/models/Attribute.php new file mode 100644 index 000000000..c2edfe9b7 --- /dev/null +++ b/application/models/Attribute.php @@ -0,0 +1,466 @@ +getConstants()); + } + + /* + Determines if a given definition_id is an attribute + */ + public function exists($definition_id, $deleted = FALSE) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_id', $definition_id); + $this->db->where('deleted', $deleted); + + return ($this->db->get()->num_rows() == 1); + } + + public function link_exists($item_id, $definition_id = FALSE) + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->from('attribute_links'); + if(empty($definition_id)) + { + $this->db->where('definition_id <>'); + $this->db->where('attribute_id'); + } + else + { + $this->db->where('definition_id', $definition_id); + + } + $this->db->where('item_id', $item_id); + + return ($this->db->get()->num_rows() > 0); + } + + /* + Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does + */ + public function value_exists($attribute_value) + { + $this->db->distinct('attribute_id'); + $this->db->from('attribute_values'); + $this->db->where('attribute_value', $attribute_value); + + return $this->db->get()->row()->attribute_id; + } + + /* + Gets information about a particular attribute definition + */ + public function get_info($definition_id) + { + $this->db->select('parent_definition.definition_name AS definition_group, definition.*'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left'); + $this->db->where('definition.definition_id', $definition_id); + + $query = $this->db->get(); + + if($query->num_rows() == 1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $item_id is NOT an item + $item_obj = new stdClass(); + + //Get all the fields from items table + foreach($this->db->list_fields('attribute_definitions') as $field) + { + $item_obj->$field = ''; + } + + return $item_obj; + } + } + + /* + Performs a search on attribute definitions + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'definition.definition_name', $order = 'asc') + { + $this->db->select('definition_group.definition_name AS definition_group, definition.*'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_definitions AS definition_group', 'definition_group.definition_id = definition.definition_fk', 'left'); + + $this->db->group_start(); + $this->db->like('definition.definition_name', $search); + $this->db->or_like('definition.definition_type', $search); + $this->db->group_end(); + $this->db->where('definition.deleted', 0); + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + public function get_attributes_by_item($item_id) + { + $this->db->from('attribute_definitions'); + $this->db->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id'); + $this->db->where('item_id', $item_id); + $this->db->where('receiving_id'); + $this->db->where('sale_id'); + $this->db->where('deleted', 0); + + $results = $this->db->get()->result_array(); + + return $this->_to_array($results, 'definition_id'); + } + + public function get_values_by_definitions($definition_ids) + { + if(count($definition_ids ? : [])) + { + $this->db->from('attribute_definitions'); + + $this->db->group_start(); + $this->db->where_in('definition_fk', array_keys($definition_ids)); + $this->db->or_where_in('definition_id', array_keys($definition_ids)); + $this->db->where('definition_type !=', GROUP); + $this->db->group_end(); + + $this->db->where('deleted', 0); + + $results = $this->db->get()->result_array(); + + return $this->_to_array($results, 'definition_id'); + } + + return array(); + } + + public function get_definitions_by_type($attribute_type, $definition_id = -1) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_type', $attribute_type); + $this->db->where('deleted', 0); + + if($definition_id != -1) + { + $this->db->where('definition_id != ', $definition_id); + } + + $this->db->where('definition_fk'); + $results = $this->db->get()->result_array(); + + return $this->_to_array($results, 'definition_id', 'definition_name'); + } + + public function get_definitions_by_flags($definition_flags) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_flags &', $definition_flags); + $this->db->where('deleted', 0); + $this->db->where('definition_type <>', GROUP); + $this->db->order_by('definition_id'); + $results = $this->db->get()->result_array(); + + return $this->_to_array($results, 'definition_id', 'definition_name'); + } + + public function get_definition_names() + { + $this->db->from('attribute_definitions'); + $this->db->where('deleted', 0); + $results = $this->db->get()->result_array(); + + $definition_name = array(-1 => $this->lang->line('common_none_selected_text')); + + return $definition_name + $this->_to_array($results, 'definition_id', 'definition_name'); + } + + public function get_definition_values($definition_id) + { + $attribute_values = []; + + if($definition_id > -1) + { + $this->db->from('attribute_links'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->where('definition_id', $definition_id); + $this->db->where('item_id'); + + $results = $this->db->get()->result_array(); + + return $this->_to_array($results, 'attribute_id', 'attribute_value'); + } + + return $attribute_values; + } + + private function _to_array($results, $key, $value = '') + { + return array_column(array_map(function($result) use ($key, $value) { + return [$result[$key], empty($value) ? $result : $result[$value]]; + }, $results), 1, 0); + } + + /* + Gets total of rows + */ + public function get_total_rows() + { + $this->db->from('attribute_definitions'); + $this->db->where('deleted', 0); + + return $this->db->count_all_results(); + } + + /* + Get number of rows + */ + public function get_found_rows($search) + { + return $this->search($search)->num_rows(); + } + + /* + Inserts or updates a definition + */ + public function save_definition(&$definition_data, $definition_id = -1) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + if($definition_id === -1 || !$this->exists($definition_id)) + { + $success = $this->db->insert('attribute_definitions', $definition_data); + $definition_data['definition_id'] = $this->db->insert_id(); + } + else + { + $this->db->where('definition_id', $definition_id); + $success = $this->db->update('attribute_definitions', $definition_data); + $definition_data['definition_id'] = $definition_id; + } + + $this->db->trans_complete(); + + $success &= $this->db->trans_status(); + + return $success; + } + + public function get_definition_by_name($definition_name, $definition_type) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_name', $definition_name); + $this->db->where('definition_type', $definition_type); + + return $this->db->get()->row_object(); + } + + public function save_link($item_id, $definition_id, $attribute_id) + { + $this->db->trans_start(); + + if($this->link_exists($item_id, $definition_id)) + { + $this->db->where('definition_id', $definition_id); + $this->db->where('item_id', $item_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->update('attribute_links', array('attribute_id' => $attribute_id)); + } + else + { + $this->db->insert('attribute_links', array('attribute_id' => $attribute_id, 'item_id' => $item_id, 'definition_id' => $definition_id)); + } + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } + + public function delete_link($item_id) + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + + return $this->db->delete('attribute_links', array('item_id' => $item_id)); + } + + public function get_link_value($item_id, $definition_id) + { + $this->db->where('item_id', $item_id); + $this->db->where('definition_id', $definition_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + + return $this->db->get('attribute_links')->row_object(); + } + + public function get_link_values($item_id, $sale_receiving_fk, $id, $definition_flags) + { + $this->db->select('GROUP_CONCAT(attribute_value SEPARATOR ", ") AS attribute_values, GROUP_CONCAT(attribute_datetime SEPARATOR ", ") AS attribute_datetimevalues'); + $this->db->from('attribute_links'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->where('definition_type <>', GROUP); + $this->db->where('deleted', 0); + + if(!empty($id)) + { + $this->db->where($sale_receiving_fk, $id); + } + else + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + } + $this->db->where('item_id', (int) $item_id); + $this->db->where('definition_flags & ', $definition_flags); + + $results = $this->db->get(); + + if ($results->num_rows() > 0) + { + $row_object = $results->row_object(); + + $datetime_values = explode(', ', $row_object->attribute_datetimevalues); + $attribute_values = array(); + + foreach (array_filter($datetime_values) as $datetime_value) + { + $attribute_values[] = to_datetime(strtotime($datetime_value)); + } + + return implode(',', $attribute_values) . $row_object->attribute_values; + } + return ""; + } + + public function get_attribute_value($item_id, $definition_id) + { + $this->db->from('attribute_values'); + $this->db->join('attribute_links', 'attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->where('definition_id', $definition_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->where('item_id', (int) $item_id); + + return $this->db->get()->row_object(); + } + + public function copy_attribute_links($item_id, $sale_receiving_fk, $id) + { + $this->db->query( + 'INSERT INTO ospos_attribute_links (item_id, definition_id, attribute_id, ' . $sale_receiving_fk . ') + SELECT ' . $this->db->escape($item_id) . ', definition_id, attribute_id, ' . $this->db->escape($id) . ' + FROM ' . $this->db->dbprefix('attribute_links') . ' + WHERE item_id = ' . $this->db->escape($item_id) . ' AND sale_id IS NULL AND receiving_id IS NULL' + ); + } + + public function get_suggestions($definition_id, $term) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('attribute_value, attribute_values.attribute_id'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_links', 'attribute_links.definition_id = definition.definition_id'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->like('attribute_value', $term); + $this->db->where('deleted', 0); + $this->db->where('definition.definition_id', $definition_id); + $this->db->order_by('attribute_value'); + foreach($this->db->get()->result() as $row) + { + $row_array = (array) $row; + $suggestions[] = array('value' => $row_array['attribute_id'], 'label' => $row_array['attribute_value']); + } + + return $suggestions; + } + + public function save_value($attribute_value, $definition_id, $item_id = FALSE, $attribute_id = FALSE, $definition_type = DROPDOWN) + { + $this->db->trans_start(); + + if(empty($attribute_id) || empty($item_id)) + { + if($definition_type != DATETIME) + { + $attribute_id_check = $this->value_exists($attribute_value); + if(empty($attribute_id_check)) + { + $this->db->insert('attribute_values', array('attribute_value' => $attribute_value)); + $attribute_id = $this->db->insert_id(); + } + else + { + $attribute_id = $attribute_id_check; + } + } + else + { + $this->db->insert('attribute_values', array('attribute_datetime' => date('Y-m-d H:i:s', strtotime($attribute_value)))); + $attribute_id = $this->db->insert_id(); + } + + $this->db->insert('attribute_links', array( + 'attribute_id' => empty($attribute_id) ? NULL : $attribute_id, + 'item_id' => empty($item_id) ? NULL : $item_id, + 'definition_id' => $definition_id)); + } + else + { + $this->db->where('attribute_id', $attribute_id); + $this->db->update('attribute_values', array('attribute_value' => $attribute_value)); + } + + $this->db->trans_complete(); + + return $attribute_id; + } + + public function delete_value($attribute_value, $definition_id) + { + return $this->db->query("DELETE atrv, atrl FROM " . $this->db->dbprefix('attribute_values') . " atrv, " . $this->db->dbprefix('attribute_links') . " atrl " . + "WHERE atrl.attribute_id = atrv.attribute_id AND atrv.attribute_value = " . $this->db->escape($attribute_value) . " AND atrl.definition_id = " . $this->db->escape($definition_id)); + } + + public function delete_definition($definition_id) + { + $this->db->where('definition_id', $definition_id); + + return $this->db->update('attribute_definitions', array('deleted' => 1)); + } + + public function delete_definition_list($definition_ids) + { + $this->db->where_in('definition_id', $definition_ids); + + return $this->db->update('attribute_definitions', array('deleted' => 1)); + } +} diff --git a/application/models/Cashup.php b/application/models/Cashup.php new file mode 100644 index 000000000..de03509b9 --- /dev/null +++ b/application/models/Cashup.php @@ -0,0 +1,212 @@ +db->from('cash_up'); + $this->db->where('cashup_id', $cashup_id); + + return ($this->db->get()->num_rows() == 1); + } + + /* + Gets employee info + */ + public function get_employee($cashup_id) + { + $this->db->from('cash_up'); + $this->db->where('cashup_id', $cashup_id); + + return $this->Employee->get_info($this->db->get()->row()->employee_id); + } + + public function get_multiple_info($cash_up_ids) + { + $this->db->from('cash_up'); + $this->db->where_in('cashup_id', $cashup_ids); + $this->db->order_by('cashup_id', 'asc'); + + return $this->db->get(); + } + + /* + Gets rows + */ + public function get_found_rows($search, $filters) + { + return $this->search($search, $filters, 0, 0, 'cashup_id', 'asc', TRUE); + } + + /* + Searches cashups + */ + public function search($search, $filters, $rows = 0, $limit_from = 0, $sort = 'cashup_id', $order = 'asc', $count_only = FALSE) + { + // get_found_rows case + if($count_only == TRUE) + { + $this->db->select('COUNT(cash_up.cashup_id) as count'); + } + + $this->db->select(' + cash_up.cashup_id, + MAX(cash_up.open_date) AS open_date, + MAX(cash_up.close_date) AS close_date, + MAX(cash_up.open_amount_cash) AS open_amount_cash, + MAX(cash_up.transfer_amount_cash) AS transfer_amount_cash, + MAX(cash_up.closed_amount_cash) AS closed_amount_cash, + MAX(cash_up.closed_amount_due) AS closed_amount_due, + MAX(cash_up.closed_amount_card) AS closed_amount_card, + MAX(cash_up.closed_amount_check) AS closed_amount_check, + MAX(cash_up.closed_amount_total) AS closed_amount_total, + MAX(cash_up.description) AS description, + MAX(cash_up.note) AS note, + MAX(cash_up.open_employee_id) AS open_employee_id, + MAX(cash_up.close_employee_id) AS close_employee_id, + MAX(open_employees.first_name) AS open_first_name, + MAX(open_employees.last_name) AS open_last_name, + MAX(close_employees.first_name) AS close_first_name, + MAX(close_employees.last_name) AS close_last_name + '); + $this->db->from('cash_up AS cash_up'); + $this->db->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT'); + $this->db->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT'); + + $this->db->group_start(); + $this->db->like('cash_up.open_date', $search); + $this->db->or_like('open_employees.first_name', $search); + $this->db->or_like('open_employees.last_name', $search); + $this->db->or_like('close_employees.first_name', $search); + $this->db->or_like('close_employees.last_name', $search); + $this->db->or_like('cash_up.closed_amount_total', $search); + $this->db->or_like('CONCAT(open_employees.first_name, " ", open_employees.last_name)', $search); + $this->db->or_like('CONCAT(close_employees.first_name, " ", close_employees.last_name)', $search); + $this->db->group_end(); + + $this->db->where('cash_up.deleted', $filters['is_deleted']); + + if(empty($this->config->item('date_or_time_format'))) + { + $this->db->where('DATE_FORMAT(cash_up.open_date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date'])); + } + else + { + $this->db->where('cash_up.open_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']))); + } + + $this->db->group_by('cashup_id'); + + // get_found_rows case + if($count_only == TRUE) + { + return $this->db->get()->row_array()['count']; + } + + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + /* + Gets information about a particular cashup + */ + public function get_info($cashup_id) + { + $this->db->select(' + cash_up.cashup_id AS cashup_id, + cash_up.open_date AS open_date, + cash_up.close_date AS close_date, + cash_up.open_amount_cash AS open_amount_cash, + cash_up.transfer_amount_cash AS transfer_amount_cash, + cash_up.closed_amount_cash AS closed_amount_cash, + cash_up.closed_amount_due AS closed_amount_due, + cash_up.closed_amount_card AS closed_amount_card, + cash_up.closed_amount_check AS closed_amount_check, + cash_up.closed_amount_total AS closed_amount_total, + cash_up.description AS description, + cash_up.note AS note, + cash_up.open_employee_id AS open_employee_id, + cash_up.close_employee_id AS close_employee_id, + cash_up.deleted AS deleted, + open_employees.first_name AS open_first_name, + open_employees.last_name AS open_last_name, + close_employees.first_name AS close_first_name, + close_employees.last_name AS close_last_name + '); + $this->db->from('cash_up AS cash_up'); + $this->db->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT'); + $this->db->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT'); + $this->db->where('cashup_id', $cashup_id); + + $query = $this->db->get(); + if($query->num_rows() == 1) + { + return $query->row(); + } + else + { + //Get empty base parent object + $cash_up_obj = new stdClass(); + + //Get all the fields from cashup table + foreach($this->db->list_fields('cash_up') as $field) + { + $cash_up_obj->$field = ''; + } + + return $cash_up_obj; + } + } + + /* + Inserts or updates an cashup + */ + public function save(&$cash_up_data, $cashup_id = FALSE) + { + if(!$cashup_id == -1 || !$this->exists($cashup_id)) + { + if($this->db->insert('cash_up', $cash_up_data)) + { + $cash_up_data['cashup_id'] = $this->db->insert_id(); + + return TRUE; + } + + return FALSE; + } + + $this->db->where('cashup_id', $cashup_id); + + return $this->db->update('cash_up', $cash_up_data); + } + + /* + Deletes a list of cashups + */ + public function delete_list($cashup_ids) + { + $success = FALSE; + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + $this->db->where_in('cashup_id', $cashup_ids); + $success = $this->db->update('cash_up', array('deleted'=>1)); + $this->db->trans_complete(); + + return $success; + } +} +?> diff --git a/application/models/Customer.php b/application/models/Customer.php index 7f1f647f2..983e2c6b5 100644 --- a/application/models/Customer.php +++ b/application/models/Customer.php @@ -104,7 +104,7 @@ class Customer extends Person ( SELECT sales.sale_id AS sale_id, - AVG(sales_items.discount_percent) AS avg_discount, + AVG(sales_items.discount) AS avg_discount, SUM(sales_items.quantity_purchased) AS quantity FROM ' . $this->db->dbprefix('sales') . ' AS sales INNER JOIN ' . $this->db->dbprefix('sales_items') . ' AS sales_items @@ -223,17 +223,52 @@ class Customer extends Person */ public function delete($customer_id) { + $result = TRUE; + // if privacy enforcement is selected scramble customer data if($this->config->item('enforce_privacy')) { $this->db->where('person_id', $customer_id); - return $this->db->update('people', array('first_name' => $customer_id, 'last_name' => $customer_id, 'phone_number' => '', 'email' => '')); + $result &= $this->db->update('people', array( + 'first_name' => $customer_id, + 'last_name' => $customer_id, + 'phone_number' => '', + 'email' => '', + 'gender' => NULL, + 'address_1' => '', + 'address_2' => '', + 'city' => '', + 'state' => '', + 'zip' => '', + 'country' => '', + 'comments' => '' + )); + + $this->db->where('person_id', $customer_id); + + $result &= $this->db->update('customers', array( + 'consent' => 0, + 'company_name' => NULL, + 'account_number' => NULL, + 'tax_id' => '', + 'taxable' => 0, + 'discount' => 0.00, + 'discount_type' => 0, + 'package_id' => NULL, + 'points' => NULL, + 'sales_tax_code' => 1, + 'deleted' => 1 + )); + } + else + { + $this->db->where('person_id', $customer_id); + + $result &= $this->db->update('customers', array('deleted' => 1)); } - $this->db->where('person_id', $customer_id); - - return $this->db->update('customers', array('deleted' => 1)); + return $result; } /* @@ -316,7 +351,7 @@ class Customer extends Person } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } diff --git a/application/models/Employee.php b/application/models/Employee.php index 0387d951f..c9d5f5582 100644 --- a/application/models/Employee.php +++ b/application/models/Employee.php @@ -97,7 +97,7 @@ class Employee extends Person //Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - if(parent::save($person_data, $employee_id)) + if(ENVIRONMENT != 'testing' && parent::save($person_data, $employee_id)) { if(!$employee_id || !$this->exists($employee_id)) { @@ -119,11 +119,9 @@ class Employee extends Person //Now insert the new grants if($success) { - $count = 0; foreach($grants_data as $grant) { $success = $this->db->insert('grants', array('permission_id' => $grant['permission_id'], 'person_id' => $employee_id, 'menu_group' => $grant['menu_group'])); - $count = $count+ 1; } } } @@ -246,7 +244,7 @@ class Employee extends Person } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } @@ -366,7 +364,7 @@ class Employee extends Person /* Determines whether the employee has access to at least one submodule - */ + */ public function has_module_grant($permission_id, $person_id) { $this->db->from('grants'); @@ -433,8 +431,8 @@ class Employee extends Person } /* - Gets employee permission grants - */ + Gets employee permission grants + */ public function get_employee_grants($person_id) { $this->db->from('grants'); @@ -443,7 +441,6 @@ class Employee extends Person return $this->db->get()->result_array(); } - /* Attempts to login employee and set session. Returns boolean based on outcome. */ @@ -473,15 +470,18 @@ class Employee extends Person { $success = FALSE; - //Run these queries as a transaction, we want to make sure we do all or nothing - $this->db->trans_start(); + if(ENVIRONMENT != 'testing') + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); - $this->db->where('person_id', $employee_id); - $success = $this->db->update('employees', $employee_data); + $this->db->where('person_id', $employee_id); + $success = $this->db->update('employees', $employee_data); - $this->db->trans_complete(); + $this->db->trans_complete(); - $success &= $this->db->trans_status(); + $success &= $this->db->trans_status(); + } return $success; } diff --git a/application/models/Expense.php b/application/models/Expense.php index b962f50be..035e256c5 100644 --- a/application/models/Expense.php +++ b/application/models/Expense.php @@ -71,7 +71,7 @@ class Expense extends CI_Model $this->db->select(' expenses.expense_id, MAX(expenses.date) AS date, - MAX(expenses.supplier_name) AS supplier_name, + MAX(suppliers.company_name) AS supplier_name, MAX(expenses.supplier_tax_code) AS supplier_tax_code, MAX(expenses.amount) AS amount, MAX(expenses.tax_amount) AS tax_amount, @@ -86,6 +86,7 @@ class Expense extends CI_Model $this->db->from('expenses AS expenses'); $this->db->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT'); $this->db->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT'); + $this->db->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT'); $this->db->group_start(); $this->db->like('employees.first_name', $search); @@ -162,7 +163,8 @@ class Expense extends CI_Model $this->db->select(' expenses.expense_id AS expense_id, expenses.date AS date, - expenses.supplier_name AS supplier_name, + suppliers.company_name AS supplier_name, + expenses.supplier_id AS supplier_id, expenses.supplier_tax_code AS supplier_tax_code, expenses.amount AS amount, expenses.tax_amount AS tax_amount, @@ -178,6 +180,7 @@ class Expense extends CI_Model $this->db->from('expenses AS expenses'); $this->db->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT'); $this->db->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT'); + $this->db->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT'); $this->db->where('expense_id', $expense_id); $query = $this->db->get(); @@ -196,6 +199,8 @@ class Expense extends CI_Model $expenses_obj->$field = ''; } + $expenses_obj->supplier_name = ''; + return $expenses_obj; } } @@ -294,31 +299,7 @@ class Expense extends CI_Model */ public function get_payment_options() { - $payments = array(); - - if($this->config->item('payment_options_order') == 'debitcreditcash') - { - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - } - elseif($this->config->item('payment_options_order') == 'debitcashcredit') - { - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - } - else // default: if($this->config->item('payment_options_order') == 'cashdebitcredit') - { - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - } - - $payments[$this->lang->line('sales_due')] = $this->lang->line('sales_due'); - $payments[$this->lang->line('sales_check')] = $this->lang->line('sales_check'); - - return $payments; + return get_payment_options(); } /* diff --git a/application/models/Giftcard.php b/application/models/Giftcard.php index 898bfedd6..281ed5219 100644 --- a/application/models/Giftcard.php +++ b/application/models/Giftcard.php @@ -190,7 +190,7 @@ class Giftcard extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } diff --git a/application/models/Item.php b/application/models/Item.php index 48589a28d..d7b469b37 100644 --- a/application/models/Item.php +++ b/application/models/Item.php @@ -6,6 +6,7 @@ define('HAS_NO_STOCK', 1); define('ITEM', 0); define('ITEM_KIT', 1); define('ITEM_AMOUNT_ENTRY', 2); +define('ITEM_TEMP', 3); define('PRINT_ALL', 0); define('PRINT_PRICED', 1); @@ -22,6 +23,8 @@ define('PRICE_OPTION_ALL', 0); define('PRICE_OPTION_KIT', 1); define('PRICE_OPTION_KIT_STOCK', 2); +define('NAME_SEPARATOR', ' | '); + /** * Item class @@ -108,64 +111,56 @@ class Item extends CI_Model // get_found_rows case if($count_only == TRUE) { - $this->db->select('COUNT(DISTINCT items.item_id) as count'); + $this->db->select('COUNT(DISTINCT items.item_id) AS count'); } else { - $this->db->select('items.item_id as item_id'); - $this->db->select('MAX(items.name) as name'); - $this->db->select('MAX(items.category) as category'); - $this->db->select('MAX(items.supplier_id) as supplier_id'); - $this->db->select('MAX(items.item_number) as item_number'); - $this->db->select('MAX(items.description) as description'); - $this->db->select('MAX(items.cost_price) as cost_price'); - $this->db->select('MAX(items.unit_price) as unit_price'); - $this->db->select('MAX(items.reorder_level) as reorder_level'); - $this->db->select('MAX(items.receiving_quantity) as receiving_quantity'); - $this->db->select('MAX(items.pic_filename) as pic_filename'); - $this->db->select('MAX(items.allow_alt_description) as allow_alt_description'); - $this->db->select('MAX(items.is_serialized) as is_serialized'); - $this->db->select('MAX(items.deleted) as deleted'); - $this->db->select('MAX(items.custom1) as custom1'); - $this->db->select('MAX(items.custom2) as custom2'); - $this->db->select('MAX(items.custom3) as custom3'); - $this->db->select('MAX(items.custom4) as custom4'); - $this->db->select('MAX(items.custom5) as custom5'); - $this->db->select('MAX(items.custom6) as custom6'); - $this->db->select('MAX(items.custom7) as custom7'); - $this->db->select('MAX(items.custom8) as custom8'); - $this->db->select('MAX(items.custom9) as custom9'); - $this->db->select('MAX(items.custom10) as custom10'); + $this->db->select('items.item_id AS item_id'); + $this->db->select('MAX(items.name) AS name'); + $this->db->select('MAX(items.category) AS category'); + $this->db->select('MAX(items.supplier_id) AS supplier_id'); + $this->db->select('MAX(items.item_number) AS item_number'); + $this->db->select('MAX(items.description) AS description'); + $this->db->select('MAX(items.cost_price) AS cost_price'); + $this->db->select('MAX(items.unit_price) AS unit_price'); + $this->db->select('MAX(items.reorder_level) AS reorder_level'); + $this->db->select('MAX(items.receiving_quantity) AS receiving_quantity'); + $this->db->select('MAX(items.pic_filename) AS pic_filename'); + $this->db->select('MAX(items.allow_alt_description) AS allow_alt_description'); + $this->db->select('MAX(items.is_serialized) AS is_serialized'); + $this->db->select('MAX(items.pack_name) AS pack_name'); + $this->db->select('MAX(items.tax_category_id) AS tax_category_id'); + $this->db->select('MAX(items.deleted) AS deleted'); - $this->db->select('MAX(suppliers.person_id) as person_id'); - $this->db->select('MAX(suppliers.company_name) as company_name'); - $this->db->select('MAX(suppliers.agency_name) as agency_name'); - $this->db->select('MAX(suppliers.account_number) as account_number'); - $this->db->select('MAX(suppliers.deleted) as deleted'); + $this->db->select('MAX(suppliers.person_id) AS person_id'); + $this->db->select('MAX(suppliers.company_name) AS company_name'); + $this->db->select('MAX(suppliers.agency_name) AS agency_name'); + $this->db->select('MAX(suppliers.account_number) AS account_number'); + $this->db->select('MAX(suppliers.deleted) AS deleted'); - $this->db->select('MAX(inventory.trans_id) as trans_id'); - $this->db->select('MAX(inventory.trans_items) as trans_items'); - $this->db->select('MAX(inventory.trans_user) as trans_user'); - $this->db->select('MAX(inventory.trans_date) as trans_date'); - $this->db->select('MAX(inventory.trans_comment) as trans_comment'); - $this->db->select('MAX(inventory.trans_location) as trans_location'); - $this->db->select('MAX(inventory.trans_inventory) as trans_inventory'); + $this->db->select('MAX(inventory.trans_id) AS trans_id'); + $this->db->select('MAX(inventory.trans_items) AS trans_items'); + $this->db->select('MAX(inventory.trans_user) AS trans_user'); + $this->db->select('MAX(inventory.trans_date) AS trans_date'); + $this->db->select('MAX(inventory.trans_comment) AS trans_comment'); + $this->db->select('MAX(inventory.trans_location) AS trans_location'); + $this->db->select('MAX(inventory.trans_inventory) AS trans_inventory'); if($filters['stock_location_id'] > -1) { - $this->db->select('MAX(item_quantities.item_id) as qty_item_id'); - $this->db->select('MAX(item_quantities.location_id) as location_id'); - $this->db->select('MAX(item_quantities.quantity) as quantity'); + $this->db->select('MAX(item_quantities.item_id) AS qty_item_id'); + $this->db->select('MAX(item_quantities.location_id) AS location_id'); + $this->db->select('MAX(item_quantities.quantity) AS quantity'); } } - $this->db->from('items as items'); - $this->db->join('suppliers as suppliers', 'suppliers.person_id = items.supplier_id', 'left'); - $this->db->join('inventory as inventory', 'inventory.trans_items = items.item_id'); + $this->db->from('items AS items'); + $this->db->join('suppliers AS suppliers', 'suppliers.person_id = items.supplier_id', 'left'); + $this->db->join('inventory AS inventory', 'inventory.trans_items = items.item_id'); if($filters['stock_location_id'] > -1) { - $this->db->join('item_quantities as item_quantities', 'item_quantities.item_id = items.item_id'); + $this->db->join('item_quantities AS item_quantities', 'item_quantities.item_id = items.item_id'); $this->db->where('location_id', $filters['stock_location_id']); } @@ -178,33 +173,28 @@ class Item extends CI_Model $this->db->where('trans_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']))); } + $attributes_enabled = count($filters['definition_ids']) > 0; + if(!empty($search)) { - if($filters['search_custom'] == FALSE) - { - $this->db->group_start(); - $this->db->like('name', $search); - $this->db->or_like('item_number', $search); - $this->db->or_like('items.item_id', $search); - $this->db->or_like('company_name', $search); - $this->db->or_like('category', $search); - $this->db->group_end(); - } - else - { - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); - } + $this->db->group_start(); + $this->db->like('name', $search); + $this->db->or_like('item_number', $search); + $this->db->or_like('items.item_id', $search); + $this->db->or_like('company_name', $search); + $this->db->or_like('items.category', $search); + if ($filters['search_custom'] && $attributes_enabled) + { + $this->db->or_like('attribute_value', $search); + } + $this->db->group_end(); + } + + if ($attributes_enabled) + { + $this->db->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\':\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values'); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id IS NULL AND attribute_links.sale_id IS NULL AND definition_id IN (' . implode(',', $filters['definition_ids']) . ')', 'left'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left'); } $this->db->where('items.deleted', $filters['is_deleted']); @@ -225,6 +215,15 @@ class Item extends CI_Model { $this->db->where('items.description', ''); } + if($filters['temporary'] != FALSE) + { + $this->db->where('items.item_type', ITEM_TEMP); + } + else + { + $non_temp = array(ITEM, ITEM_KIT, ITEM_AMOUNT_ENTRY); + $this->db->where_in('items.item_type', $non_temp); + } // get_found_rows case if($count_only == TRUE) @@ -279,10 +278,13 @@ class Item extends CI_Model public function get_info($item_id) { $this->db->select('items.*'); + $this->db->select('GROUP_CONCAT(attribute_value SEPARATOR \'|\') AS attribute_values'); $this->db->select('suppliers.company_name'); $this->db->from('items'); $this->db->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left'); - $this->db->where('item_id', $item_id); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id', 'left'); + $this->db->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left'); + $this->db->where('items.item_id', $item_id); $query = $this->db->get(); @@ -308,7 +310,7 @@ class Item extends CI_Model /* Gets information about a particular item by item id or number */ - public function get_info_by_id_or_number($item_id) + public function get_info_by_id_or_number($item_id, $include_deleted = TRUE) { $this->db->from('items'); @@ -325,9 +327,12 @@ class Item extends CI_Model $this->db->group_end(); - $this->db->where('items.deleted', 0); + if(!$include_deleted) + { + $this->db->where("items.deleted = '0'"); + } - // limit to only 1 so there is a result in case two are returned + // limit to only 1 so there is a result in case two are returned // due to barcode and item_id clash $this->db->limit(1); @@ -369,11 +374,19 @@ class Item extends CI_Model */ public function get_multiple_info($item_ids, $location_id) { + $this->db->select('items.*'); + $this->db->select('company_name'); + $this->db->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\':\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values'); + $this->db->select('items.category'); + $this->db->select('quantity'); $this->db->from('items'); $this->db->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left'); $this->db->join('item_quantities', 'item_quantities.item_id = items.item_id', 'left'); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id AND sale_id IS NULL AND receiving_id IS NULL', 'left'); + $this->db->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left'); $this->db->where('location_id', $location_id); $this->db->where_in('items.item_id', $item_ids); + $this->db->group_by('items.item_id'); return $this->db->get(); } @@ -388,10 +401,13 @@ class Item extends CI_Model if($this->db->insert('items', $item_data)) { $item_data['item_id'] = $this->db->insert_id(); - + if($item_data['low_sell_item_id'] == -1) + { + $this->db->where('item_id', $item_data['item_id']); + $this->db->update('items', array('low_sell_item_id'=>$item_data['item_id'])); + } return TRUE; } - return FALSE; } @@ -469,7 +485,7 @@ class Item extends CI_Model function get_search_suggestion_format($seed = NULL) { $seed .= ',' . $this->config->item('suggestions_first_column'); - + if($this->config->item('suggestions_second_column') !== '') { $seed .= ',' . $this->config->item('suggestions_second_column'); @@ -479,37 +495,77 @@ class Item extends CI_Model { $seed .= ',' . $this->config->item('suggestions_third_column'); } - + return $seed; } function get_search_suggestion_label($result_row) { + $label = ''; $label1 = $this->config->item('suggestions_first_column'); $label2 = $this->config->item('suggestions_second_column'); $label3 = $this->config->item('suggestions_third_column'); - $label = $result_row->$label1; - - if($label2 !== '') + // If multi_pack enabled then if "name" is part of the search suggestions then append pack + if($this->config->item('multi_pack_enabled') == '1') { - $label .= ' | '. $result_row->$label2; + $this->append_label($label, $label1, $result_row); + $this->append_label($label, $label2, $result_row); + $this->append_label($label, $label3, $result_row); } - - if($label3 !== '') + else { - $label .= ' | '. $result_row->$label3; - } - + $label = $result_row->$label1; + + if($label2 !== '') + { + $label .= NAME_SEPARATOR . $result_row->$label2; + } + + if($label3 !== '') + { + $label .= NAME_SEPARATOR . $result_row->$label3; + } + } + return $label; - } + } + + private function append_label(&$label, $item_field_name, $item_info) + { + if($item_field_name !== '') + { + if($label == '') + { + if($item_field_name == 'name') + { + $label .= implode(NAME_SEPARATOR, array($item_info->name, $item_info->pack_name)); + } + else + { + $label .= $item_info->$item_field_name; + } + } + else + { + if($item_field_name == 'name') + { + $label .= implode(NAME_SEPARATOR, array('', $item_info->name, $item_info->pack_name)); + } + else + { + $label .= NAME_SEPARATOR . $item_info->$item_field_name; + } + } + } + } public function get_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25) { $suggestions = array(); $non_kit = array(ITEM, ITEM_AMOUNT_ENTRY); - $this->db->select($this->get_search_suggestion_format('item_id, name')); + $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later @@ -520,7 +576,7 @@ class Item extends CI_Model $suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)); } - $this->db->select($this->get_search_suggestion_format('item_id, item_number')); + $this->db->select($this->get_search_suggestion_format('item_id, item_number, pack_name')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later @@ -561,7 +617,7 @@ class Item extends CI_Model } //Search by description - $this->db->select($this->get_search_suggestion_format('item_id, name, description')); + $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name, description')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later @@ -579,19 +635,11 @@ class Item extends CI_Model //Search by custom fields if($filters['search_custom'] != FALSE) { - $this->db->from('items'); - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); + $this->db->from('attribute_links'); + $this->db->join('attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->like('attribute_value', $search); + $this->db->where('definition_type', TEXT); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later foreach($this->db->get()->result() as $row) @@ -602,12 +650,12 @@ class Item extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } - return $suggestions; + return array_unique($suggestions, SORT_REGULAR); } @@ -616,11 +664,11 @@ class Item extends CI_Model $suggestions = array(); $non_kit = array(ITEM, ITEM_AMOUNT_ENTRY); - $this->db->select($this->get_search_suggestion_format('item_id, name')); + $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later - $this->db->where("stock_type = '0'"); // stocked items only + $this->db->where('stock_type', '0'); // stocked items only $this->db->like('name', $search); $this->db->order_by('name', 'asc'); foreach($this->db->get()->result() as $row) @@ -628,11 +676,11 @@ class Item extends CI_Model $suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)); } - $this->db->select($this->get_search_suggestion_format('item_id, item_number')); + $this->db->select($this->get_search_suggestion_format('item_id, item_number, pack_name')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later - $this->db->where("stock_type = '0'"); // stocked items only + $this->db->where('stock_type', '0'); // stocked items only $this->db->like('item_number', $search); $this->db->order_by('item_number', 'asc'); foreach($this->db->get()->result() as $row) @@ -647,7 +695,7 @@ class Item extends CI_Model $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later - $this->db->where("stock_type = '0'"); // stocked items only + $this->db->where('stock_type', '0'); // stocked items only $this->db->distinct(); $this->db->like('category', $search); $this->db->order_by('category', 'asc'); @@ -670,11 +718,11 @@ class Item extends CI_Model } //Search by description - $this->db->select($this->get_search_suggestion_format('item_id, name, description')); + $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name, description')); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later - $this->db->where("stock_type = '0'"); // stocked items only + $this->db->where('stock_type', '0'); // stocked items only $this->db->like('description', $search); $this->db->order_by('description', 'asc'); foreach($this->db->get()->result() as $row) @@ -689,21 +737,12 @@ class Item extends CI_Model //Search by custom fields if($filters['search_custom'] != FALSE) { - $this->db->from('items'); - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); - $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later - $this->db->where("stock_type = '0'"); // stocked items only + $this->db->from('attribute_links'); + $this->db->join('attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->like('attribute_value', $search); + $this->db->where('definition_type', TEXT); + $this->db->where('stock_type', '0'); // stocked items only $this->db->where('deleted', $filters['is_deleted']); foreach($this->db->get()->result() as $row) { @@ -713,12 +752,12 @@ class Item extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } - return $suggestions; + return array_unique($suggestions, SORT_REGULAR); } public function get_kit_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25) @@ -818,11 +857,29 @@ class Item extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } + return array_unique($suggestions, SORT_REGULAR); + } + + public function get_low_sell_suggestions($search) + { + $suggestions = array(); + + $this->db->select($this->get_search_suggestion_format('item_id, pack_name')); + $this->db->from('items'); + $this->db->where('deleted', '0'); + $this->db->where('stock_type', '0'); // stocked items only + $this->db->like('name', $search); + $this->db->order_by('name', 'asc'); + foreach($this->db->get()->result() as $row) + { + $suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)); + } + return $suggestions; } @@ -860,24 +917,6 @@ class Item extends CI_Model return $suggestions; } - public function get_custom_suggestions($search, $field_no) - { - $suggestions = array(); - $this->db->distinct(); - $this->db->select('custom'.$field_no); - $this->db->from('items'); - $this->db->like('custom'.$field_no, $search); - $this->db->where('deleted', 0); - $this->db->order_by('custom'.$field_no, 'asc'); - foreach($this->db->get()->result() as $row) - { - $row_array = (array) $row; - $suggestions[] = array('label' => $row_array['custom'.$field_no]); - } - - return $suggestions; - } - public function get_categories() { $this->db->select('category'); @@ -923,5 +962,50 @@ class Item extends CI_Model return $this->save($data, $item_id); } + + public function update_item_number($item_id, $item_number) + { + $this->db->where('item_id', $item_id); + $this->db->update('items', array('item_number'=>$item_number)); + } + + public function update_item_name($item_id, $item_name) + { + $this->db->where('item_id', $item_id); + $this->db->update('items', array('name'=>$item_name)); + } + + public function update_item_description($item_id, $item_description) + { + $this->db->where('item_id', $item_id); + $this->db->update('items', array('description'=>$item_description)); + } + + /** + * Determine the item name to use taking into consideration that + * for a multipack environment then the item name should have the + * pack appended to it + */ + function get_item_name($as_name = NULL) + { + if($as_name == NULL) + { + $as_name = ''; + } + else + { + $as_name = ' AS ' . $as_name; + } + + if($this->config->item('multi_pack_enabled') == '1') + { + $item_name = "concat(items.name,'" . NAME_SEPARATOR . '\', items.pack_name)' . $as_name; + } + else + { + $item_name = 'items.name' . $as_name; + } + return $item_name; + } } ?> diff --git a/application/models/Item_kit.php b/application/models/Item_kit.php index 6de74b7c4..c0e76212f 100644 --- a/application/models/Item_kit.php +++ b/application/models/Item_kit.php @@ -58,7 +58,8 @@ class Item_kit extends CI_Model item_kits.description, items.description as item_description, item_kits.item_id as kit_item_id, - kit_discount_percent, + kit_discount, + kit_discount_type, price_option, print_option, category, @@ -72,16 +73,6 @@ class Item_kit extends CI_Model allow_alt_description, is_serialized, items.deleted, - custom1, - custom2, - custom3, - custom4, - custom5, - custom6, - custom7, - custom8, - custom9, - custom10, item_type, stock_type'); @@ -191,7 +182,7 @@ class Item_kit extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } diff --git a/application/models/Person.php b/application/models/Person.php index f5cee9260..cf5c773ae 100644 --- a/application/models/Person.php +++ b/application/models/Person.php @@ -158,7 +158,7 @@ class Person extends CI_Model } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } diff --git a/application/models/Receiving.php b/application/models/Receiving.php index c875796e1..29958d52f 100644 --- a/application/models/Receiving.php +++ b/application/models/Receiving.php @@ -93,7 +93,8 @@ class Receiving extends CI_Model 'serialnumber' => $item['serialnumber'], 'quantity_purchased' => $item['quantity'], 'receiving_quantity' => $item['receiving_quantity'], - 'discount_percent' => $item['discount'], + 'discount' => $item['discount'], + 'discount_type' => $item['discount_type'], 'item_cost_price' => $cur_item_info->cost_price, 'item_unit_price' => $item['price'], 'item_location' => $item['item_location'] @@ -126,6 +127,8 @@ class Receiving extends CI_Model $this->Inventory->insert($inv_data); + $this->Attribute->copy_attribute_links($item['item_id'], 'receiving_id', $receiving_id); + $supplier = $this->Supplier->get_info($supplier_id); } @@ -221,7 +224,8 @@ class Receiving extends CI_Model $this->lang->line('sales_cash') => $this->lang->line('sales_cash'), $this->lang->line('sales_check') => $this->lang->line('sales_check'), $this->lang->line('sales_debit') => $this->lang->line('sales_debit'), - $this->lang->line('sales_credit') => $this->lang->line('sales_credit') + $this->lang->line('sales_credit') => $this->lang->line('sales_credit'), + $this->lang->line('sales_due') => $this->lang->line('sales_due') ); } @@ -264,13 +268,14 @@ class Receiving extends CI_Model MAX(receivings_items.receiving_quantity) AS receiving_quantity, MAX(item_cost_price) AS item_cost_price, MAX(item_unit_price) AS item_unit_price, - MAX(discount_percent) AS discount_percent, + MAX(discount) AS discount, + discount_type as discount_type, receivings_items.line, MAX(serialnumber) AS serialnumber, MAX(receivings_items.description) AS description, - MAX(item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount_percent / 100) AS subtotal, - MAX(item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount_percent / 100) AS total, - MAX((item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount_percent / 100) - (item_cost_price * quantity_purchased)) AS profit, + MAX(CASE WHEN receivings_items.discount_type = ' . PERCENT . ' THEN item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount / 100 ELSE item_unit_price * quantity_purchased * receivings_items.receiving_quantity - discount END) AS subtotal, + MAX(CASE WHEN receivings_items.discount_type = ' . PERCENT . ' THEN item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount / 100 ELSE item_unit_price * quantity_purchased * receivings_items.receiving_quantity - discount END) AS total, + MAX((CASE WHEN receivings_items.discount_type = ' . PERCENT . ' THEN item_unit_price * quantity_purchased * receivings_items.receiving_quantity - item_unit_price * quantity_purchased * receivings_items.receiving_quantity * discount / 100 ELSE item_unit_price * quantity_purchased * receivings_items.receiving_quantity - discount END) - (item_cost_price * quantity_purchased)) AS profit, MAX(item_cost_price * quantity_purchased * receivings_items.receiving_quantity ) AS cost FROM ' . $this->db->dbprefix('receivings_items') . ' AS receivings_items INNER JOIN ' . $this->db->dbprefix('receivings') . ' AS receivings diff --git a/application/models/Sale.php b/application/models/Sale.php index ad02c2b83..44c20abfd 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -10,6 +10,8 @@ define('SALE_TYPE_WORK_ORDER', 2); define('SALE_TYPE_QUOTE', 3); define('SALE_TYPE_RETURN', 4); +define('PERCENT', 0); +define('FIXED', 1); /** * Sale class */ @@ -38,7 +40,7 @@ class Sale extends CI_Model $decimals = totals_decimals(); - $sale_price = 'sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100)'; + $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END'; $tax = 'ROUND(IFNULL(SUM(sales_items_taxes.tax), 0), ' . $decimals . ')'; if($this->config->item('tax_included')) @@ -152,7 +154,7 @@ class Sale extends CI_Model $decimals = totals_decimals(); - $sale_price = 'sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100)'; + $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END'; $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)'; $tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)'; @@ -174,7 +176,7 @@ class Sale extends CI_Model SELECT sales_items_taxes.sale_id AS sale_id, sales_items_taxes.item_id AS item_id, sales_items_taxes.line AS line, - SUM(sales_items_taxes.item_tax_amount) as tax + SUM(sales_items_taxes.item_tax_amount) AS tax FROM ' . $this->db->dbprefix('sales_items_taxes') . ' AS sales_items_taxes INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales ON sales.sale_id = sales_items_taxes.sale_id @@ -188,7 +190,7 @@ class Sale extends CI_Model // get_found_rows case if($count_only == TRUE) { - $this->db->select('COUNT(DISTINCT sales.sale_id) as count'); + $this->db->select('COUNT(DISTINCT sales.sale_id) AS count'); } else { @@ -384,7 +386,7 @@ class Sale extends CI_Model $gift_card_amount = 0; foreach($payments as $key=>$payment) { - if( strstr($payment['payment_type'], $this->lang->line('sales_giftcard')) != FALSE ) + if(strstr($payment['payment_type'], $this->lang->line('sales_giftcard')) != FALSE) { $gift_card_count += $payment['count']; $gift_card_amount += $payment['payment_amount']; @@ -563,7 +565,8 @@ class Sale extends CI_Model * Save the sale information after the sales is complete but before the final document is printed * The sales_taxes variable needs to be initialized to an empty array before calling */ - public function save($sale_id, &$sale_status, &$items, $customer_id, $employee_id, $comment, $invoice_number, $work_order_number, $quote_number, $sale_type, $payments, $dinner_table, &$sales_taxes) + public function save($sale_id, &$sale_status, &$items, $customer_id, $employee_id, $comment, $invoice_number, + $work_order_number, $quote_number, $sale_type, $payments, $dinner_table, &$sales_taxes) { if($sale_id != -1) { @@ -639,12 +642,15 @@ class Sale extends CI_Model $customer = $this->Customer->get_info($customer_id); - $sales_taxes = array(); - foreach($items as $line=>$item) { $cur_item_info = $this->Item->get_info($item['item_id']); + if($item['price'] == 0.00) + { + $item['discount'] = 0.00; + } + $sales_items_data = array( 'sale_id' => $sale_id, 'item_id' => $item['item_id'], @@ -652,7 +658,8 @@ class Sale extends CI_Model 'description' => character_limiter($item['description'], 255), 'serialnumber' => character_limiter($item['serialnumber'], 30), 'quantity_purchased'=> $item['quantity'], - 'discount_percent' => $item['discount'], + 'discount' => $item['discount'], + 'discount_type' => $item['discount_type'], 'item_cost_price' => $item['cost_price'], 'item_unit_price' => $item['price'], 'item_location' => $item['item_location'], @@ -689,80 +696,13 @@ class Sale extends CI_Model $this->Inventory->insert($inv_data); } - // Calculate taxes and save the tax information for the sale. Return the result for printing - - if($customer_id == -1 || $customer->taxable) - { - if($this->config->item('tax_included')) - { - $tax_type = Tax_lib::TAX_TYPE_VAT; - } - else - { - $tax_type = Tax_lib::TAX_TYPE_SALES; - } - $rounding_code = Rounding_mode::HALF_UP; // half adjust - $tax_group_sequence = 0; - $item_total = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], TRUE); - $tax_basis = $item_total; - $item_tax_amount = 0; - - foreach($this->Item_taxes->get_info($item['item_id']) as $row) - { - - $sales_items_taxes = array( - 'sale_id' => $sale_id, - 'item_id' => $item['item_id'], - 'line' => $item['line'], - 'name' => character_limiter($row['name'], 255), - 'percent' => $row['percent'], - 'tax_type' => $tax_type, - 'rounding_code' => $rounding_code, - 'cascade_tax' => 0, - 'cascade_sequence' => 0, - 'item_tax_amount' => 0 - ); - - // This computes tax for each line item and adds it to the tax type total - $tax_group = (float)$row['percent'] . '% ' . $row['name']; - $tax_basis = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], TRUE); - - if($this->config->item('tax_included')) - { - $tax_type = Tax_lib::TAX_TYPE_VAT; - $item_tax_amount = $this->sale_lib->get_item_tax($item['quantity'], $item['price'], $item['discount'],$row['percent']); - } - elseif($this->config->item('customer_sales_tax_support') == '0') - { - $tax_type = Tax_lib::TAX_TYPE_SALES; - $item_tax_amount = $this->tax_lib->get_sales_tax_for_amount($tax_basis, $row['percent'], '0', $tax_decimals); - } - else - { - $tax_type = Tax_lib::TAX_TYPE_SALES; - } - - $sales_items_taxes['item_tax_amount'] = $item_tax_amount; - if($item_tax_amount != 0) - { - $this->db->insert('sales_items_taxes', $sales_items_taxes); - $this->tax_lib->update_sales_taxes($sales_taxes, $tax_type, $tax_group, $row['percent'], $tax_basis, $item_tax_amount, $tax_group_sequence, $rounding_code, $sale_id, $row['name'], ''); - $tax_group_sequence += 1; - } - - } - - if($this->config->item('customer_sales_tax_support') == '1') - { - $this->save_sales_item_tax($customer, $sale_id, $item, $item_total, $sales_taxes, $sequence, $cur_item_info->tax_category_id); - } - } + $this->Attribute->copy_attribute_links($item['item_id'], 'sale_id', $sale_id); } if($customer_id == -1 || $customer->taxable) { - $this->tax_lib->round_sales_taxes($sales_taxes); - $this->save_sales_tax($sales_taxes); + $this->save_sales_tax($sale_id, $sales_taxes[0]); + $this->save_sales_items_taxes($sale_id, $sales_taxes[1]); } $dinner_table_data = array( @@ -782,6 +722,19 @@ class Sale extends CI_Model return $sale_id; } + /** + * Saves sale tax + */ + public function save_sales_tax($sale_id, $sales_taxes) + { + foreach($sales_taxes as $line=>$sales_tax) + { + $sales_tax['tax_group'] = (float)$sales_tax['tax_rate'] . '% ' . $sales_tax['tax_group']; + $sales_tax['sale_id'] = $sale_id; + $this->db->insert('sales_taxes', $sales_tax); + } + } + /** * Apply customer sales tax if the customer sales tax is enabledl * The original tax is still supported if the user configures it, @@ -789,25 +742,24 @@ class Sale extends CI_Model * of VAT tax which becomes a price component. VAT taxes must still be reported * as a separate tax entry on the invoice. */ - public function save_sales_item_tax(&$customer, &$sale_id, &$item, $tax_basis, &$sales_taxes, &$sequence, $tax_category_id) + public function save_sales_items_taxes($sale_id, $sales_item_taxes) { - // if customer sales tax is enabled then update sales_items_taxes with the - if($this->config->item('customer_sales_tax_support') == '1') + foreach($sales_item_taxes as $line => $tax_item) { - $register_mode = $this->config->item('default_register_mode'); - $tax_details = $this->tax_lib->apply_sales_tax($item, $customer->city, $customer->state, $customer->sales_tax_code, $register_mode, $sale_id, $sales_taxes); - $sales_items_taxes = array( - 'sale_id' => $sale_id, - 'item_id' => $item['item_id'], - 'line' => $item['line'], - 'name' => $tax_details['tax_name'], - 'percent' => $tax_details['tax_rate'], - 'tax_type' => Tax_lib::TAX_TYPE_SALES, - 'rounding_code' => $tax_details['rounding_code'], - 'cascade_tax' => 0, - 'cascade_sequence' => 0, - 'item_tax_amount' => $tax_details['item_tax_amount'] + 'sale_id' => $sale_id, + 'item_id' => $tax_item['item_id'], + 'line' => $tax_item['line'], + 'name' => $tax_item['name'], + 'percent' => $tax_item['percent'], + 'tax_type' => $tax_item['tax_type'], + 'rounding_code' => $tax_item['rounding_code'], + 'cascade_sequence' => $tax_item['cascade_sequence'], + 'item_tax_amount' => $tax_item['item_tax_amount'], + 'sales_tax_code_id' => $tax_item['sales_tax_code_id'], + 'tax_category_id' => $tax_item['tax_category_id'], + 'jurisdiction_id' => $tax_item['jurisdiction_id'], + 'tax_category_id' => $tax_item['tax_category_id'] ); $this->db->insert('sales_items_taxes', $sales_items_taxes); @@ -815,14 +767,17 @@ class Sale extends CI_Model } /** - * Saves sale tax + * Return the taxes that were charged */ - public function save_sales_tax(&$sales_taxes) + public function get_sales_taxes($sale_id) { - foreach($sales_taxes as $line=>$sales_tax) - { - $this->db->insert('sales_taxes', $sales_tax); - } + $this->db->from('sales_taxes'); + $this->db->where('sale_id', $sale_id); + $this->db->order_by('print_sequence', 'asc'); + + $query = $this->db->get(); + + return $query->result_array(); } /** @@ -927,15 +882,16 @@ class Sale extends CI_Model quantity_purchased, item_cost_price, item_unit_price, - discount_percent, + discount, + discount_type, item_location, print_option, - items.name as name, + ' . $this->Item->get_item_name('name') . ', category, item_type, stock_type'); - $this->db->from('sales_items as sales_items'); - $this->db->join('items as items', 'sales_items.item_id = items.item_id'); + $this->db->from('sales_items AS sales_items'); + $this->db->join('items AS items', 'sales_items.item_id = items.item_id'); $this->db->where('sales_items.sale_id', $sale_id); // Entry sequence (this will render kits in the expected sequence) @@ -949,6 +905,7 @@ class Sale extends CI_Model $this->db->order_by('stock_type', 'desc'); $this->db->order_by('sales_items.description', 'asc'); $this->db->order_by('items.name', 'asc'); + $this->db->order_by('items.qty_per_pack', 'asc'); } // Group by Item Category elseif($this->config->item('line_sequence') == '2') @@ -956,6 +913,7 @@ class Sale extends CI_Model $this->db->order_by('category', 'asc'); $this->db->order_by('sales_items.description', 'asc'); $this->db->order_by('items.name', 'asc'); + $this->db->order_by('items.qty_per_pack', 'asc'); } // Group by entry sequence in descending sequence (the Standard) else @@ -982,36 +940,14 @@ class Sale extends CI_Model */ public function get_payment_options($giftcard = TRUE, $reward_points = FALSE) { - $payments = array(); + $payments = get_payment_options(); - if($this->config->item('payment_options_order') == 'debitcreditcash') - { - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - } - elseif($this->config->item('payment_options_order') == 'debitcashcredit') - { - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - } - else // default: if($this->config->item('payment_options_order') == 'cashdebitcredit') - { - $payments[$this->lang->line('sales_cash')] = $this->lang->line('sales_cash'); - $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); - $payments[$this->lang->line('sales_credit')] = $this->lang->line('sales_credit'); - } - - $payments[$this->lang->line('sales_due')] = $this->lang->line('sales_due'); - $payments[$this->lang->line('sales_check')] = $this->lang->line('sales_check'); - - if($giftcard) + if($giftcard == TRUE) { $payments[$this->lang->line('sales_giftcard')] = $this->lang->line('sales_giftcard'); } - if($reward_points) + if($reward_points == TRUE) { $payments[$this->lang->line('sales_rewards')] = $this->lang->line('sales_rewards'); } @@ -1133,7 +1069,7 @@ class Sale extends CI_Model $decimals = totals_decimals(); - $sale_price = 'sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100)'; + $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END'; $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)'; $tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)'; @@ -1155,7 +1091,7 @@ class Sale extends CI_Model SELECT sales_items_taxes.sale_id AS sale_id, sales_items_taxes.item_id AS item_id, sales_items_taxes.line AS line, - SUM(sales_items_taxes.item_tax_amount) as tax + SUM(sales_items_taxes.item_tax_amount) AS tax FROM ' . $this->db->dbprefix('sales_items_taxes') . ' AS sales_items_taxes INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales ON sales.sale_id = sales_items_taxes.sale_id @@ -1203,14 +1139,15 @@ class Sale extends CI_Model MAX(sales.employee_id) AS employee_id, MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name, items.item_id AS item_id, - MAX(items.name) AS name, + MAX(' . $this->Item->get_item_name() . ') AS name, MAX(items.item_number) AS item_number, MAX(items.category) AS category, MAX(items.supplier_id) AS supplier_id, MAX(sales_items.quantity_purchased) AS quantity_purchased, MAX(sales_items.item_cost_price) AS item_cost_price, MAX(sales_items.item_unit_price) AS item_unit_price, - MAX(sales_items.discount_percent) AS discount_percent, + MAX(sales_items.discount) AS discount, + sales_items.discount_type AS discount_type, sales_items.line AS line, MAX(sales_items.serialnumber) AS serialnumber, MAX(sales_items.item_location) AS item_location, @@ -1314,7 +1251,6 @@ class Sale extends CI_Model $this->db->update('sales', array('sale_status'=>$sale_status)); } - /** * Gets the quote_number for the selected sale */ @@ -1329,10 +1265,8 @@ class Sale extends CI_Model { return $row->quote_number; } - else - { - return NULL; - } + + return NULL; } /** @@ -1349,10 +1283,8 @@ class Sale extends CI_Model { return $row->work_order_number; } - else - { - return NULL; - } + + return NULL; } /** @@ -1369,10 +1301,8 @@ class Sale extends CI_Model { return $row->comment; } - else - { - return NULL; - } + + return NULL; } /** @@ -1487,6 +1417,7 @@ class Sale extends CI_Model { return SUSPENDED; } + return COMPLETED; } } diff --git a/application/models/Stock_location.php b/application/models/Stock_location.php index b35b4647a..239e3937c 100644 --- a/application/models/Stock_location.php +++ b/application/models/Stock_location.php @@ -149,7 +149,7 @@ class Stock_location extends CI_Model private function _insert_new_permission($module, $location_id, $location_name) { // insert new permission for stock location - $permission_id = $module . '_' . $location_name; + $permission_id = $module . '_' . str_replace(' ', '_', $location_name); $permission_data = array('permission_id' => $permission_id, 'module_id' => $module, 'location_id' => $location_id); $this->db->insert('permissions', $permission_data); diff --git a/application/models/Supplier.php b/application/models/Supplier.php index ea08fa887..05ef4d458 100644 --- a/application/models/Supplier.php +++ b/application/models/Supplier.php @@ -5,7 +5,10 @@ */ class Supplier extends Person -{ +{ + const GOODS_SUPPLIER = 0; + const COST_SUPPLIER = 1; + /* Determines if a given person_id is a customer */ @@ -32,10 +35,11 @@ class Supplier extends Person /* Returns all the suppliers */ - public function get_all($limit_from = 0, $rows = 0) + public function get_all($category = self::GOODS_SUPPLIER, $limit_from = 0, $rows = 0) { $this->db->from('suppliers'); - $this->db->join('people', 'suppliers.person_id = people.person_id'); + $this->db->join('people', 'suppliers.person_id = people.person_id'); + $this->db->where('category', $category); $this->db->where('deleted', 0); $this->db->order_by('company_name', 'asc'); if($rows > 0) @@ -217,7 +221,7 @@ class Supplier extends Person } //only return $limit suggestions - if(count($suggestions > $limit)) + if(count($suggestions) > $limit) { $suggestions = array_slice($suggestions, 0, $limit); } @@ -273,5 +277,31 @@ class Supplier extends Person return $this->db->get(); } + + /* + Return supplier categories + */ + public function get_categories() + { + return array( + self::GOODS_SUPPLIER => $this->lang->line('suppliers_goods'), + self::COST_SUPPLIER => $this->lang->line('suppliers_cost') + ); + } + + /* + Return a category name given its id + */ + public function get_category_name($id) + { + if($id == self::GOODS_SUPPLIER) + { + return $this->lang->line('suppliers_goods'); + } + elseif($id == self::COST_SUPPLIER) + { + return $this->lang->line('suppliers_cost'); + } + } } ?> diff --git a/application/models/Tax.php b/application/models/Tax.php index ab6b7bb3b..92391aa8a 100644 --- a/application/models/Tax.php +++ b/application/models/Tax.php @@ -7,62 +7,60 @@ class Tax extends CI_Model { /** - Determines if a given tax_code is on file - */ - public function exists($tax_code) + * Determines if a given row is on file + */ + public function exists($tax_rate_id) { - $this->db->from('tax_codes'); - $this->db->where('tax_code', $tax_code); - - return ($this->db->get()->num_rows() == 1); - } - - public function tax_rate_exists($tax_code, $tax_category_id) - { - $this->db->from('tax_code_rates'); - $this->db->where('rate_tax_code', $tax_code); - $this->db->where('rate_tax_category_id', $tax_category_id); - - return ($this->db->get()->num_rows() == 1); - } - - public function tax_category_exists($tax_category_id) - { - $this->db->from('tax_categories'); - $this->db->where('tax_category_id', $tax_category_id); + $this->db->from('tax_rates'); + $this->db->where('tax_rate_id', $tax_rate_id); return ($this->db->get()->num_rows() == 1); } /** - Gets total of rows - */ + * Gets total of rows + */ public function get_total_rows() { - $this->db->from('tax_codes'); + $this->db->from('tax_rates'); return $this->db->count_all_results(); } + /** + * Gets list of tax rates that are assigned to a particular tax category + */ public function get_tax_category_usage($tax_category_id) { - $this->db->from('tax_code_rates'); + $this->db->from('tax_rates'); $this->db->where('rate_tax_category_id', $tax_category_id); return $this->db->count_all_results(); } /** - Gets information about a particular tax_code - */ - public function get_info($tax_code) + * Gets the row for a particular id + */ + public function get_info($tax_rate_id) { - $this->db->from('tax_codes'); - $this->db->join('tax_code_rates', - 'tax_code = rate_tax_code and rate_tax_category_id = 1', 'LEFT'); + $this->db->select('tax_rate_id'); + $this->db->select('rate_tax_code_id'); + $this->db->select('tax_code'); + $this->db->select('tax_code_name'); + $this->db->select('rate_jurisdiction_id'); + $this->db->select('jurisdiction_name'); + $this->db->select('rate_tax_category_id'); + $this->db->select('tax_category'); + $this->db->select('tax_rate'); + $this->db->select('tax_rounding_code'); + $this->db->from('tax_rates'); + $this->db->join('tax_codes', + 'rate_tax_code_id = tax_code_id', 'LEFT'); $this->db->join('tax_categories', - 'rate_tax_category_id = tax_category_id'); - $this->db->where('tax_code', $tax_code); + 'rate_tax_category_id = tax_category_id', 'LEFT'); + $this->db->join('tax_jurisdictions', + 'rate_jurisdiction_id = jurisdiction_id', 'LEFT'); + $this->db->where('tax_rate_id', $tax_rate_id); $query = $this->db->get(); @@ -73,30 +71,49 @@ class Tax extends CI_Model else { //Get empty base parent object - $tax_code_obj = new stdClass(); + $tax_rate_obj = new stdClass(); + $tax_rate_obj->tax_rate_id = NULL; + $tax_rate_obj->rate_tax_code_id = NULL; + $tax_rate_obj->tax_code = ''; + $tax_rate_obj->tax_code_name = ''; + $tax_rate_obj->rate_tax_category_id = NULL; + $tax_rate_obj->tax_category = ''; + $tax_rate_obj->tax_rate = 0.0; + $tax_rate_obj->tax_rounding_code = '0'; + $tax_rate_obj->rate_jurisdiction_id = NULL; + $tax_rate_obj->jurisdiction_name = ''; //Get all the fields from tax_codes table - foreach($this->db->list_fields('tax_codes') as $field) - { - $tax_code_obj->$field = ''; - } - foreach($this->db->list_fields('tax_code_rates') as $field) - { - $tax_code_obj->$field = ''; - } - return $tax_code_obj; + return $tax_rate_obj; } } /** - Gets information about a particular tax_code - */ - public function get_rate_info($tax_code, $tax_category_id) + * Get taxes to be collected for a given tax code + */ + public function get_taxes($tax_code_id, $tax_category_id) { - $this->db->from('tax_code_rates'); + $query = $this->db->query('select tax_rate_id, rate_tax_code_id, tax_code, tax_code_name, tax_type, cascade_sequence, rate_tax_category_id, tax_category, + rate_jurisdiction_id, jurisdiction_name, tax_group, tax_rate, tax_rounding_code,tax_categories.tax_group_sequence + tax_jurisdictions.tax_group_sequence as tax_group_sequence + from ' . $this->db->dbprefix('tax_rates') . ' + left outer join ' . $this->db->dbprefix('tax_codes') . ' on rate_tax_code_id = tax_code_id + left outer join ' . $this->db->dbprefix('tax_categories') . ' as tax_categories on rate_tax_category_id = tax_category_id + left outer join ' . $this->db->dbprefix('tax_jurisdictions') . ' as tax_jurisdictions on rate_jurisdiction_id = jurisdiction_id + where rate_tax_code_id = ' . $this->db->escape($tax_code_id) . ' and rate_tax_category_id = ' . $this->db->escape($tax_category_id) . ' + order by cascade_sequence, tax_group, jurisdiction_name, tax_jurisdictions.tax_group_sequence + tax_categories.tax_group_sequence'); + + return $query->result_array(); + } + + /** + * Gets information about a particular tax_code + */ + public function get_rate_info($tax_code_id, $tax_category_id) + { + $this->db->from('tax_rates'); $this->db->join('tax_categories', 'rate_tax_category_id = tax_category_id'); - $this->db->where('rate_tax_code', $tax_code); + $this->db->where('rate_tax_code_id', $tax_code_id); $this->db->where('rate_tax_category_id', $tax_category_id); $query = $this->db->get(); @@ -111,11 +128,11 @@ class Tax extends CI_Model $tax_rate_obj = new stdClass(); //Get all the fields from tax_codes table - foreach($this->db->list_fields('tax_code_rates') as $field) + foreach($this->db->list_fields('tax_rates') as $field) { $tax_rate_obj->$field = ''; } - //Get all the fields from tax_code_rates table + //Get all the fields from tax_rates table foreach($this->db->list_fields('tax_categories') as $field) { $tax_rate_obj->$field = ''; @@ -126,67 +143,25 @@ class Tax extends CI_Model } /** - Gets the tax code to use for a given customer + Inserts or updates a tax_rates entry */ - public function get_sales_tax_code($city = '', $state = '') + public function save(&$tax_rate_data, $tax_rate_id = -1) { - // if tax code using both city and state cannot be found then try again using just the state - // if the state tax code cannot be found then try again using blanks for both - $this->db->from('tax_codes'); - $this->db->where('city', $city); - $this->db->where('state', $state); - $this->db->where('tax_code_type', '0'); // sales tax - - $query = $this->db->get(); - - if($query->num_rows() == 1) + if(!$this->exists($tax_rate_id)) { - return $query->row()->tax_code; - } - else - { - $this->db->from('tax_codes'); - $this->db->where('city', ''); - $this->db->where('state', $state); - $this->db->where('tax_code_type', '0'); // sales tax - - $query = $this->db->get(); - - if($query->num_rows() == 1) + if($this->db->insert('tax_rates', $tax_rate_data)) { - return $query->row()->tax_code; - } - else - { - return $this->config->item('default_origin_tax_code'); - } - } - - return FALSE; - } - - /** - Inserts or updates a tax_codes entry - */ - public function save(&$tax_code_data, $tax_rate_data, $tax_code = -1) - { - if(!$this->exists($tax_code)) - { - if($this->db->insert('tax_codes', $tax_code_data)) - { - $this->save_tax_rates($tax_rate_data, $tax_code); + $tax_rate_data['tax_rate_id'] = $this->db->insert_id(); return TRUE; } } else { - $this->db->where('tax_code', $tax_code); + $this->db->where('tax_rate_id', $tax_rate_id); - if($this->db->update('tax_codes', $tax_code_data)) + if($this->db->update('tax_rates', $tax_rate_data)) { - $this->save_tax_rates($tax_rate_data, $tax_code); - return TRUE; } } @@ -195,132 +170,65 @@ class Tax extends CI_Model } /** - * Inserts or updates a tax_category + * Deletes a single tax rate entry */ - public function save_tax_category(&$tax_category_data, &$tax_category_id) + public function delete($tax_rate_id) { - if(!$this->tax_category_exists($tax_category_id)) - { - $result = $this->db->insert('tax_categories', $tax_category_data); - - $tax_category_id = $this->db->insert_id(); - - return $result; - } - - $this->db->where('tax_category_id', $tax_category_id); - - return $this->db->update('tax_categories', $tax_category_data); + return $this->db->delete('tax_tax_rates', array('tax_rate_id' => $tax_rate_id)); } /** - * Inserts or updates a tax_rate + * Deletes a list of tax rates */ - public function save_tax_rates(&$tax_rate_data, $tax_code) + public function delete_list($tax_rate_ids) { - if(!$this->tax_rate_exists($tax_code, $tax_rate_data['rate_tax_category_id'])) - { - return $this->db->insert('tax_code_rates', $tax_rate_data); - } + $this->db->where_in('tax_rate_id', $tax_rate_ids); - $this->db->where('rate_tax_code', $tax_code); - $this->db->where('rate_tax_category_id', $tax_rate_data['rate_tax_category_id']); - - return $this->db->update('tax_code_rates', $tax_rate_data); + return $this->db->delete('tax_rates'); } /** - Inserts or updates an item kit's items - */ - public function save_tax_rate_exceptions(&$tax_rate_data, $tax_code) - { - $success = TRUE; - - //Run these queries as a transaction, we want to make sure we do all or nothing - - $this->db->trans_start(); - - // Delete all exceptions for the given tax_code - $this->delete_tax_rate_exceptions($tax_code); - - if($tax_rate_data != NULL) - { - foreach($tax_rate_data as $row) - { - $row['rate_tax_code'] = $tax_code; - $success &= $this->db->insert('tax_code_rates', $row); - } - } - - $this->db->trans_complete(); - - $success &= $this->db->trans_status(); - - return $success; - } - - /** - Deletes one tax_codes entry - */ - public function delete($tax_code) - { - return $this->db->delete('tax_codes', array('tax_code' => $tax_code)); - } - - /** - Deletes one tax_codes entry - */ - public function delete_tax_category($tax_category_id) - { - return $this->db->delete('tax_categories', array('tax_category_id' => $tax_category_id)); - } - - /** - Deletes a list of tax codes - */ - public function delete_list($tax_codes) - { - $this->db->where_in('tax_code', $tax_codes); - - return $this->db->delete('tax_codes'); - } - - /** - Deletes all tax_rate_exceptions for given tax codes - */ - public function delete_tax_rate_exceptions($tax_code) - { - $this->db->where('rate_tax_code', $tax_code); - $this->db->where('rate_tax_category_id !=', 1); - - return $this->db->delete('tax_code_rates'); - } - - /** - Gets tax_codes - */ + * Gets tax_codes + */ public function get_found_rows($search) { - return $this->search($search, 0, 0, 'tax_code', 'asc', TRUE); + return $this->search($search, 0, 0, 'tax_code_name', 'asc', TRUE); } /** - Performs a search on tax_codes - */ - public function search($search, $rows = 0, $limit_from = 0, $sort = 'tax_code', $order = 'asc', $count_only = FALSE) + * Performs a search on tax_rates + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'tax_code_name', $order = 'asc', $count_only = FALSE) { // get_found_rows case + if($count_only == TRUE) { - $this->db->select('COUNT(tax_code) as count'); + $this->db->select('COUNT(tax_rate_id) as count'); + } else + { + $this->db->select('tax_rate_id'); + $this->db->select('tax_code'); + $this->db->select('rate_tax_code_id'); + $this->db->select('tax_code_name'); + $this->db->select('rate_jurisdiction_id'); + $this->db->select('jurisdiction_name'); + $this->db->select('rate_tax_category_id'); + $this->db->select('tax_category'); + $this->db->select('tax_rate'); + $this->db->select('tax_rounding_code'); } - - $this->db->from('tax_codes'); - $this->db->join('tax_code_rates', 'tax_code = rate_tax_code AND rate_tax_category_id = 1', 'LEFT'); + $this->db->from('tax_rates'); + $this->db->join('tax_codes', + 'rate_tax_code_id = tax_code_id', 'LEFT'); + $this->db->join('tax_categories', + 'rate_tax_category_id = tax_category_id', 'LEFT'); + $this->db->join('tax_jurisdictions', + 'rate_jurisdiction_id = jurisdiction_id', 'LEFT'); if(!empty($search)) { - $this->db->like('tax_code', $search); + $this->db->like('rate_tax_code', $search); $this->db->or_like('tax_code_name', $search); } @@ -344,60 +252,14 @@ class Tax extends CI_Model { if($tax_code_type == '0') { - return $this->lang->line('taxes_sales_tax'); + return $this->lang->line('taxes_tax_included'); } else { - return $this->lang->line('taxes_vat_tax'); + return $this->lang->line('taxes_tax_excluded'); } } - public function get_sales_tax_codes_search_suggestions($search, $limit = 25) - { - $suggestions = array(); - - $this->db->from('tax_codes'); - if(!empty($search)) - { - $this->db->like('tax_code', $search); - $this->db->or_like('tax_code_name', $search); - } - $this->db->order_by('tax_code_name', 'asc'); - - foreach($this->db->get()->result() as $row) - { - $suggestions[] = array('value' => $row->tax_code, 'label' => ($row->tax_code . ' ' . $row->tax_code_name)); - } - - //only return $limit suggestions - if(count($suggestions > $limit)) - { - $suggestions = array_slice($suggestions, 0,$limit); - } - - return $suggestions; - } - - public function get_tax_category_suggestions($search) - { - $suggestions = array(); - - $this->db->from('tax_categories'); - $this->db->where('tax_category_id !=', 1); - if(!empty($search)) - { - $this->db->like('tax_category', '%'.$search.'%'); - } - $this->db->order_by('tax_category', 'asc'); - - foreach($this->db->get()->result() as $row) - { - $suggestions[] = array('value' => $row->tax_category_id, 'label' => $row->tax_category); - } - - return $suggestions; - } - public function get_tax_category($tax_category_id) { $this->db->select('tax_category'); @@ -415,15 +277,6 @@ class Tax extends CI_Model return $this->db->get(); } - public function get_all_tax_codes() - { - $this->db->select('tax_code, tax_code_name'); - $this->db->from('tax_codes'); - $this->db->order_by('tax_code_name'); - - return $this->db->get(); - } - public function get_tax_category_id($tax_category) { $this->db->select('tax_category_id'); @@ -432,15 +285,5 @@ class Tax extends CI_Model return $this->db->get()->row()->tax_category_id; } - public function get_tax_code_rate_exceptions($tax_code) - { - $this->db->from('tax_code_rates'); - $this->db->join('tax_categories', 'rate_tax_category_id = tax_category_id'); - $this->db->where('rate_tax_code', $tax_code); - $this->db->where('rate_tax_category_id !=', 1); - $this->db->order_by('tax_category', 'asc'); - - return $this->db->get()->result_array(); - } } ?> diff --git a/application/models/Tax_category.php b/application/models/Tax_category.php new file mode 100644 index 000000000..76939609b --- /dev/null +++ b/application/models/Tax_category.php @@ -0,0 +1,243 @@ +db->from('tax_categories'); + $this->db->where('tax_category_id', $tax_category_id); + + return ($this->db->get()->num_rows() == 1); + } + + /** + * Gets total of rows + */ + public function get_total_rows() + { + $this->db->from('tax_categories'); + $this->db->where('deleted', 0); + + return $this->db->count_all_results(); + } + + /** + * Gets information about the particular record + */ + public function get_info($tax_category_id) + { + $this->db->from('tax_categories'); + $this->db->where('tax_category_id', $tax_category_id); + $this->db->where('deleted', 0); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object + $tax_category_obj = new stdClass(); + + //Get all the fields from the table + foreach($this->db->list_fields('tax_categories') as $field) + { + $tax_category_obj->$field = ''; + } + return $tax_category_obj; + } + } + + /** + * Returns all rows from the table + */ + public function get_all($rows = 0, $limit_from = 0, $no_deleted = TRUE) + { + $this->db->from('tax_categories'); + if($no_deleted == TRUE) + { + $this->db->where('deleted', 0); + } + + $this->db->order_by('tax_group_sequence', 'asc'); + $this->db->order_by('tax_category', 'asc'); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + /** + * Returns multiple rows + */ + public function get_multiple_info($tax_category_ids) + { + $this->db->from('tax_categories'); + $this->db->where_in('tax_category_id', $tax_category_ids); + $this->db->order_by('tax_category', 'asc'); + + return $this->db->get(); + } + + /** + * Inserts or updates a row + */ + public function save(&$tax_category_data, $tax_category_id = FALSE) + { + if(!$tax_category_id || !$this->exists($tax_category_id)) + { + if($this->db->insert('tax_categories', $tax_category_data)) + { + $tax_category_data['tax_category_id'] = $this->db->insert_id(); + + return TRUE; + } + + return FALSE; + } + + $this->db->where('tax_category_id', $tax_category_id); + + return $this->db->update('tax_categories', $tax_category_data); + } + + /** + * Saves changes to the tax categories table + */ + public function save_categories($array_save) + { + $this->db->trans_start(); + + $not_to_delete = array(); + + foreach($array_save as $key => $value) + { + // save or update + $tax_category_data = array('tax_category' => $value['tax_category'], 'tax_group_sequence' => $value['tax_group_sequence'], 'deleted' => '0'); + $this->save($tax_category_data, $value['tax_category_id']); + if($value['tax_category_id'] == -1) + { + $not_to_delete[] = $tax_category_data['tax_category_id']; + } + else + { + $not_to_delete[] = $value['tax_category_id']; + } + } + + // all entries not available in post will be deleted now + $deleted_tax_categories = $this->get_all()->result_array(); + + foreach($deleted_tax_categories as $key => $tax_category_data) + { + if(!in_array($tax_category_data['tax_category_id'], $not_to_delete)) + { + $this->delete($tax_category_data['tax_category_id']); + } + } + + $this->db->trans_complete(); + return $this->db->trans_status(); + } + + /** + * Soft delete a specific row + */ + public function delete($tax_category_id) + { + $this->db->where('tax_category_id', $tax_category_id); + + return $this->db->update('tax_categories', array('deleted' => 1)); + } + + /** + * Deletes a list of rows + */ + public function delete_list($tax_category_ids) + { + $this->db->where_in('tax_category_id', $tax_category_ids); + + return $this->db->update('tax_categories', array('deleted' => 1)); + } + + /** + * Gets rows + */ + public function get_found_rows($search) + { + return $this->search($search, 0, 0, 'tax_category', 'asc', TRUE); + } + + /** + * Perform a search for a set of rows + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'tax_category', $order='asc', $count_only = FALSE) + { + // get_found_rows case + if($count_only == TRUE) + { + $this->db->select('COUNT(tax_categories.tax_category_id) as count'); + } + + $this->db->from('tax_categories AS tax_categories'); + $this->db->like('tax_category', $search); + $this->db->where('deleted', 0); + + // get_found_rows case + if($count_only == TRUE) + { + return $this->db->get()->row()->count; + } + + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + public function get_tax_category_suggestions($search) + { + $suggestions = array(); + + $this->db->from('tax_categories'); + $this->db->where('deleted', 0); + if(!empty($search)) + { + $this->db->like('tax_category', '%'.$search.'%'); + } + $this->db->order_by('tax_category', 'asc'); + + foreach($this->db->get()->result() as $row) + { + $suggestions[] = array('value' => $row->tax_category_id, 'label' => $row->tax_category); + } + + return $suggestions; + } + + public function get_empty_row() + { + return array('0' => array( + 'tax_category_id' => -1, + 'tax_category' => '', + 'tax_group_sequence' => 0, + 'deleted' => 0)); + } + +} +?> diff --git a/application/models/Tax_code.php b/application/models/Tax_code.php new file mode 100644 index 000000000..16b09b025 --- /dev/null +++ b/application/models/Tax_code.php @@ -0,0 +1,283 @@ +db->from('tax_codes'); + $this->db->where('tax_code', $tax_code); + + return ($this->db->get()->num_rows() == 1); + } + + /** + * Gets total of rows + */ + public function get_total_rows() + { + $this->db->from('tax_codes'); + $this->db->where('deleted', 0); + + return $this->db->count_all_results(); + } + + /** + * Gets information about the particular record + */ + public function get_info($tax_code_id) + { + $this->db->from('tax_codes'); + $this->db->where('tax_code_id', $tax_code_id); + $this->db->where('deleted', 0); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object + $tax_code_obj = new stdClass(); + + //Get all the fields from the table + foreach($this->db->list_fields('tax_codes') as $field) + { + $tax_code_obj->$field = ''; + } + return $tax_code_obj; + } + } + + /** + * Returns all rows from the table + */ + public function get_all($rows = 0, $limit_from = 0, $no_deleted = TRUE) + { + $this->db->from('tax_codes'); + if($no_deleted == TRUE) + { + $this->db->where('deleted', 0); + } + + $this->db->order_by('tax_code_name', 'asc'); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + /** + * Returns multiple rows + */ + public function get_multiple_info($tax_codes) + { + $this->db->from('tax_codes'); + $this->db->where_in('tax_code', $tax_codes); + $this->db->order_by('tax_code_name', 'asc'); + + return $this->db->get(); + } + + /** + * Inserts or updates a row + */ + public function save(&$tax_code_data) + { + if(!$this->exists($tax_code_data['tax_code'])) + { + if($this->db->insert('tax_codes', $tax_code_data)) + { + return TRUE; + } + return FALSE; + } + + $this->db->where('tax_code', $tax_code_data['tax_code']); + + return $this->db->update('tax_codes', $tax_code_data); + } + + /** + * Saves changes to the tax codes table + */ + public function save_tax_codes($array_save) + { + $this->db->trans_start(); + + $not_to_delete = array(); + + foreach($array_save as $key => $value) + { + // save or update + $tax_code_data = array('tax_code' => $value['tax_code'], 'tax_code_name' => $value['tax_code_name'], 'city' => $value['city'], 'state' => $value['state'], 'deleted' => '0'); + $this->save($tax_code_data); + $not_to_delete[] = $tax_code_data['tax_code']; + } + + // all entries not available in post will be deleted now + $deleted_tax_codes = $this->get_all()->result_array(); + + foreach($deleted_tax_codes as $key => $tax_code_data) + { + if(!in_array($tax_code_data['tax_code'], $not_to_delete)) + { + $this->delete($tax_code_data['tax_code']); + } + } + + $this->db->trans_complete(); + return $this->db->trans_status(); + } + + /** + * Deletes a specific tax code + */ + public function delete($tax_code) + { + $this->db->where('tax_code', $tax_code); + + return $this->db->update('tax_codes', array('deleted' => 1)); + } + + /** + * Deletes a list of rows + */ + public function delete_list($tax_codes) + { + $this->db->where_in('tax_code', $tax_codes); + + return $this->db->update('tax_codes', array('deleted' => 1)); + } + + /** + * Gets rows + */ + public function get_found_rows($search) + { + return $this->search($search, 0, 0, 'tax_code_name', 'asc', TRUE); + } + + /** + * Perform a search for a set of rows + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'tax_code_name', $order='asc', $count_only = FALSE) + { + // get_found_rows case + if($count_only == TRUE) + { + $this->db->select('COUNT(tax_codes.tax_code) as count'); + } + + $this->db->from('tax_codes AS tax_codes'); + $this->db->group_start(); + $this->db->like('tax_code_name', $search); + $this->db->or_like('tax_code', $search); + $this->db->group_end(); + $this->db->where('deleted', 0); + + // get_found_rows case + if($count_only == TRUE) + { + return $this->db->get()->row()->count; + } + + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + /** + * Gets the tax code to use for a given customer + */ + public function get_sales_tax_code($city = '', $state = '') + { + // if tax code using both city and state cannot be found then try again using just the state + // if the state tax code cannot be found then try again using blanks for both + $this->db->from('tax_codes'); + $this->db->where('city', $city); + $this->db->where('state', $state); + $this->db->where('deleted', 0); + + + $query = $this->db->get(); + + if($query->num_rows() == 1) + { + return $query->row()->tax_code_id; + } + else + { + $this->db->from('tax_codes'); + $this->db->where('city', ''); + $this->db->where('state', $state); + $this->db->where('deleted', 0); + + $query = $this->db->get(); + + if($query->num_rows() == 1) + { + return $query->row()->tax_code_id; + } + else + { + return $this->config->item('default_tax_code'); + } + } + return FALSE; + } + + public function get_tax_codes_search_suggestions($search, $limit = 25) + { + $suggestions = array(); + + $this->db->from('tax_codes'); + if(!empty($search)) + { + $this->db->like('tax_code', $search); + $this->db->or_like('tax_code_name', $search); + } + $this->db->where('deleted', 0); + $this->db->order_by('tax_code_name', 'asc'); + + foreach($this->db->get()->result() as $row) + { + $suggestions[] = array('value' => $row->tax_code_id, 'label' => ($row->tax_code . ' ' . $row->tax_code_name)); + } + + //only return $limit suggestions + if(count($suggestions) > $limit) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + + return $suggestions; + } + + public function get_empty_row() + { + return array('0' => array( + 'tax_code_id' => -1, + 'tax_code' => '', + 'tax_code_name' => '', + 'city' => '', + 'state' => '', + 'deleted' => 0)); + } +} +?> diff --git a/application/models/Tax_jurisdiction.php b/application/models/Tax_jurisdiction.php new file mode 100644 index 000000000..e27ba46b4 --- /dev/null +++ b/application/models/Tax_jurisdiction.php @@ -0,0 +1,228 @@ +db->from('tax_jurisdictions'); + $this->db->where('jurisdiction_id', $jurisdiction_id); + + return ($this->db->get()->num_rows() == 1); + } + + /** + * Gets total of rows + */ + public function get_total_rows() + { + $this->db->from('tax_jurisdictions'); + $this->db->where('deleted', 0); + + return $this->db->count_all_results(); + } + + /** + * Gets information about the particular record + */ + public function get_info($jurisdiction_id) + { + $this->db->from('tax_jurisdictions'); + $this->db->where('jurisdiction_id', $jurisdiction_id); + $this->db->where('deleted', 0); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object + $tax_jurisdiction_obj = new stdClass(); + + //Get all the fields from the table + foreach($this->db->list_fields('tax_jurisdictions') as $field) + { + $tax_jurisdiction_obj->$field = ''; + } + return $tax_jurisdiction_obj; + } + } + + /** + * Returns all rows from the table + */ + public function get_all($rows = 0, $limit_from = 0, $no_deleted = TRUE) + { + $this->db->from('tax_jurisdictions'); + if($no_deleted == TRUE) + { + $this->db->where('deleted', 0); + } + + $this->db->order_by('jurisdiction_name', 'asc'); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + /** + * Returns multiple rows + */ + public function get_multiple_info($jurisdiction_ids) + { + $this->db->from('tax_jurisdictions'); + $this->db->where_in('jurisdiction_id', $jurisdiction_ids); + $this->db->order_by('jurisdiction_name', 'asc'); + + return $this->db->get(); + } + + /** + * Inserts or updates a row + */ + public function save(&$jurisdiction_data, $jurisdiction_id = FALSE) + { + if(!$jurisdiction_id || !$this->exists($jurisdiction_id)) + { + if($this->db->insert('tax_jurisdictions', $jurisdiction_data)) + { + $jurisdiction_data['jurisdiction_id'] = $this->db->insert_id(); + return TRUE; + } + + return FALSE; + } + + $this->db->where('jurisdiction_id', $jurisdiction_id); + + return $this->db->update('tax_jurisdictions', $jurisdiction_data); + } + + /** + * Saves changes to the tax jurisdictions table + */ + public function save_jurisdictions($array_save) + { + $this->db->trans_start(); + + $not_to_delete = array(); + + foreach($array_save as $key => $value) + { + // save or update + $tax_jurisdiction_data = array('jurisdiction_name' => $value['jurisdiction_name'], 'tax_group' => $value['tax_group'], 'tax_type' => $value['tax_type'], 'reporting_authority' => $value['reporting_authority'], 'tax_group_sequence' => $value['tax_group_sequence'], 'cascade_sequence' => $value['cascade_sequence'], 'deleted' => '0'); + $this->save($tax_jurisdiction_data, $value['jurisdiction_id']); + if($value['jurisdiction_id'] == -1) + { + $not_to_delete[] = $tax_jurisdiction_data['jurisdiction_id']; + } + else + { + $not_to_delete[] = $value['jurisdiction_id']; + } + } + + // all entries not available in post will be deleted now + $deleted_tax_jurisdictions = $this->get_all()->result_array(); + + foreach($deleted_tax_jurisdictions as $key => $tax_jurisdiction_data) + { + if(!in_array($tax_jurisdiction_data['jurisdiction_id'], $not_to_delete)) + { + $this->delete($tax_jurisdiction_data['jurisdiction_id']); + } + } + + $this->db->trans_complete(); + return $this->db->trans_status(); + } + + /** + * Soft deletes a specific tax jurisdiction + */ + public function delete($jurisdiction_id) + { + $this->db->where('jurisdiction_id', $jurisdiction_id); + + return $this->db->update('tax_jurisdictions', array('deleted' => 1)); + } + + /** + * Soft deletes a list of rows + */ + public function delete_list($jurisdiction_ids) + { + $this->db->where_in('jurisdiction_id', $jurisdiction_ids); + + return $this->db->update('tax_jurisdictions', array('deleted' => 1)); + } + + /** + * Gets rows + */ + public function get_found_rows($search) + { + return $this->search($search, 0, 0, 'jurisdiction_name', 'asc', TRUE); + } + + /** + * Perform a search for a set of rows + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'jurisdiction_name', $order='asc', $count_only = FALSE) + { + // get_found_rows case + if($count_only == TRUE) + { + $this->db->select('COUNT(tax_jurisdictions.jurisdiction_id) as count'); + } + + $this->db->from('tax_jurisdictions AS tax_jurisdictions'); + $this->db->group_start(); + $this->db->like('jurisdiction_name', $search); + $this->db->or_like('reporting_authority', $search); + $this->db->group_end(); + $this->db->where('deleted', 0); + + // get_found_rows case + if($count_only == TRUE) + { + return $this->db->get()->row()->count; + } + + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + public function get_empty_row() + { + return array('0' => array( + 'jurisdiction_id' => -1, + 'jurisdiction_name' => '', + 'tax_group' => '', + 'tax_type' => '1', + 'reporting_authority' => '', + 'tax_group_sequence' => 0, + 'cascade_sequence' => 0, + 'deleted' => 0)); + } + +} +?> diff --git a/application/models/reports/Detailed_receivings.php b/application/models/reports/Detailed_receivings.php index 3941da25b..c2f3f795b 100644 --- a/application/models/reports/Detailed_receivings.php +++ b/application/models/reports/Detailed_receivings.php @@ -12,7 +12,7 @@ class Detailed_receivings extends Report public function getDataColumns() { - $columns = array( + return array( 'summary' => array( array('id' => $this->lang->line('reports_receiving_id')), array('receiving_date' => $this->lang->line('reports_date'), 'sortable' => FALSE), @@ -31,8 +31,6 @@ class Detailed_receivings extends Report $this->lang->line('reports_total'), $this->lang->line('reports_discount')) ); - - return $columns; } public function getDataByReceivingId($receiving_id) @@ -99,10 +97,17 @@ class Detailed_receivings extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, item_number, category, quantity_purchased, serialnumber,total, discount_percent, item_location, receivings_items_temp.receiving_quantity'); + $this->db->select('name, item_number, category, quantity_purchased, serialnumber, total, discount, discount_type, item_location, receivings_items_temp.receiving_quantity'); $this->db->from('receivings_items_temp'); $this->db->join('items', 'receivings_items_temp.item_id = items.item_id'); - $this->db->where('receiving_id = '.$value['receiving_id']); + if (count($inputs['definition_ids']) > 0) + { + $this->db->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\':\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values'); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id = receivings_items_temp.receiving_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left'); + $this->db->group_by('receivings_items_temp.receiving_id, receivings_items_temp.item_id'); + } + $this->db->where('receivings_items_temp.receiving_id', $value['receiving_id']); $data['details'][$key] = $this->db->get()->result_array(); } diff --git a/application/models/reports/Detailed_sales.php b/application/models/reports/Detailed_sales.php index 79645af2c..a63655fa1 100644 --- a/application/models/reports/Detailed_sales.php +++ b/application/models/reports/Detailed_sales.php @@ -144,10 +144,18 @@ class Detailed_sales extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, category, quantity_purchased, item_location, serialnumber, description, subtotal, tax, total, cost, profit, discount_percent, sale_status'); + $this->db->select('name, category, quantity_purchased, item_location, serialnumber, description, subtotal, tax, total, cost, profit, discount, discount_type, sale_status'); $this->db->from('sales_items_temp'); - $this->db->where('sale_id', $value['sale_id']); + if (count($inputs['definition_ids']) > 0) + { + $this->db->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\':\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values'); + $this->db->join('attribute_links', 'attribute_links.item_id = sales_items_temp.item_id AND attribute_links.sale_id = sales_items_temp.sale_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left'); + $this->db->group_by('sales_items_temp.sale_id, sales_items_temp.item_id'); + } + $this->db->where('sales_items_temp.sale_id', $value['sale_id']); $data['details'][$key] = $this->db->get()->result_array(); + $this->db->select('used, earned'); $this->db->from('sales_reward_points'); $this->db->where('sale_id', $value['sale_id']); diff --git a/application/models/reports/Inventory_low.php b/application/models/reports/Inventory_low.php index 2cca4519f..35842f700 100644 --- a/application/models/reports/Inventory_low.php +++ b/application/models/reports/Inventory_low.php @@ -16,17 +16,20 @@ class Inventory_low extends Report public function getData(array $inputs) { - $this->db->select('items.name, items.item_number, item_quantities.quantity, items.reorder_level, stock_locations.location_name'); - $this->db->from('items'); - $this->db->join('item_quantities', 'items.item_id = item_quantities.item_id'); - $this->db->join('stock_locations', 'item_quantities.location_id = stock_locations.location_id'); - $this->db->where('items.deleted', 0); - $this->db->where('stock_locations.deleted', 0); - $this->db->where('items.stock_type', 0); - $this->db->where('item_quantities.quantity <= items.reorder_level'); - $this->db->order_by('items.name'); + $query = $this->db->query("SELECT " . $this->Item->get_item_name('name') . ", + items.item_number, + item_quantities.quantity, + items.reorder_level, + stock_locations.location_name + FROM " . $this->db->dbprefix('items') . " AS items + JOIN " . $this->db->dbprefix('item_quantities') . " AS item_quantities ON items.item_id = item_quantities.item_id + JOIN " . $this->db->dbprefix('stock_locations') . " AS stock_locations ON item_quantities.location_id = stock_locations.location_id + WHERE items.deleted = 0 + AND items.stock_type = 0 + AND item_quantities.quantity <= items.reorder_level + ORDER BY items.name"); - return $this->db->get()->result_array(); + return $query->result_array(); } public function getSummaryData(array $inputs) diff --git a/application/models/reports/Inventory_summary.php b/application/models/reports/Inventory_summary.php index 51c4e2004..37736df9d 100644 --- a/application/models/reports/Inventory_summary.php +++ b/application/models/reports/Inventory_summary.php @@ -9,6 +9,7 @@ class Inventory_summary extends Report return array(array('item_name' => $this->lang->line('reports_item_name')), array('item_number' => $this->lang->line('reports_item_number')), array('quantity' => $this->lang->line('reports_quantity')), + array('low_sell_quantity' => $this->lang->line('reports_low_sell_quantity')), array('reorder_level' => $this->lang->line('reports_reorder_level')), array('location_name' => $this->lang->line('reports_stock_location')), array('cost_price' => $this->lang->line('reports_cost_price'), 'sorter' => 'number_sorter'), @@ -18,7 +19,7 @@ class Inventory_summary extends Report public function getData(array $inputs) { - $this->db->select('items.name, items.item_number, item_quantities.quantity, items.reorder_level, stock_locations.location_name, items.cost_price, items.unit_price, (items.cost_price * item_quantities.quantity) AS sub_total_value'); + $this->db->select($this->Item->get_item_name('name') . ', items.item_number, item_quantities.quantity, (item_quantities.quantity * items.qty_per_pack) as low_sell_quantity, items.reorder_level, stock_locations.location_name, items.cost_price, items.unit_price, (items.cost_price * item_quantities.quantity) AS sub_total_value'); $this->db->from('items AS items'); $this->db->join('item_quantities AS item_quantities', 'items.item_id = item_quantities.item_id'); $this->db->join('stock_locations AS stock_locations', 'item_quantities.location_id = stock_locations.location_id'); @@ -42,6 +43,7 @@ class Inventory_summary extends Report } $this->db->order_by('items.name'); + $this->db->order_by('items.qty_per_pack'); return $this->db->get()->result_array(); } @@ -54,12 +56,13 @@ class Inventory_summary extends Report */ public function getSummaryData(array $inputs) { - $return = array('total_inventory_value' => 0, 'total_quantity' => 0, 'total_retail' => 0); + $return = array('total_inventory_value' => 0, 'total_quantity' => 0, 'total_low_sell_quantity' => 0, 'total_retail' => 0); foreach($inputs as $input) { $return['total_inventory_value'] += $input['sub_total_value']; $return['total_quantity'] += $input['quantity']; + $return['total_low_sell_quantity'] += $input['low_sell_quantity']; $return['total_retail'] += $input['unit_price'] * $input['quantity']; } diff --git a/application/models/reports/Specific_customer.php b/application/models/reports/Specific_customer.php index 54623489c..1184f351c 100644 --- a/application/models/reports/Specific_customer.php +++ b/application/models/reports/Specific_customer.php @@ -127,7 +127,7 @@ class Specific_customer extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); + $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type'); $this->db->from('sales_items_temp'); $this->db->where('sale_id', $value['sale_id']); $data['details'][$key] = $this->db->get()->result_array(); diff --git a/application/models/reports/Specific_discount.php b/application/models/reports/Specific_discount.php index 91bc2be3c..03f05623d 100755 --- a/application/models/reports/Specific_discount.php +++ b/application/models/reports/Specific_discount.php @@ -70,7 +70,9 @@ class Specific_discount extends Report MAX(payment_type) AS payment_type, MAX(comment) AS comment'); $this->db->from('sales_items_temp'); - $this->db->where('discount_percent >=', $inputs['discount']); + + $this->db->where('discount >=', $inputs['discount']); + $this->db->where('discount_type',$inputs['discount_type']); if($inputs['sale_type'] == 'complete') { @@ -119,7 +121,7 @@ class Specific_discount extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); + $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type'); $this->db->from('sales_items_temp'); $this->db->where('sale_id', $value['sale_id']); $data['details'][$key] = $this->db->get()->result_array(); @@ -136,7 +138,9 @@ class Specific_discount extends Report { $this->db->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit'); $this->db->from('sales_items_temp'); - $this->db->where('discount_percent >=', $inputs['discount']); + + $this->db->where('discount >=', $inputs['discount']); + $this->db->where('discount_type',$inputs['discount_type']); if($inputs['sale_type'] == 'complete') { diff --git a/application/models/reports/Specific_employee.php b/application/models/reports/Specific_employee.php index 1b4484227..36bdc0957 100644 --- a/application/models/reports/Specific_employee.php +++ b/application/models/reports/Specific_employee.php @@ -117,7 +117,7 @@ class Specific_employee extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); + $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type'); $this->db->from('sales_items_temp'); $this->db->where('sale_id', $value['sale_id']); $data['details'][$key] = $this->db->get()->result_array(); diff --git a/application/models/reports/Summary_discounts.php b/application/models/reports/Summary_discounts.php index e94119f6d..02b3970ff 100644 --- a/application/models/reports/Summary_discounts.php +++ b/application/models/reports/Summary_discounts.php @@ -7,23 +7,34 @@ class Summary_discounts extends Summary_report protected function _get_data_columns() { return array( - array('discount' => $this->lang->line('reports_discount_percent'), 'sorter' => 'number_sorter'), - array('count' => $this->lang->line('reports_count'))); + array('discount' => $this->lang->line('reports_discount'), 'sorter' => 'number_sorter'), + array('count' => $this->lang->line('reports_count')), + array('total' => $this->lang->line('reports_total'))); } public function getData(array $inputs) { - $this->db->select('MAX(CONCAT(sales_items.discount_percent, "%")) AS discount_percent, count(*) AS count'); + if($inputs['discount_type'] == FIXED) + { + $this->db->select('SUM(sales_items.discount) AS total, MAX(CONCAT("'.$this->config->item('currency_symbol').'",sales_items.discount)) AS discount, count(*) AS count'); + $this->db->where('discount_type',FIXED); + } + elseif($inputs['discount_type'] == PERCENT) + { + $this->db->select('SUM(item_unit_price) * sales_items.discount / 100.0 AS total, MAX(CONCAT(sales_items.discount, "%")) AS discount, count(*) AS count'); + $this->db->where('discount_type',PERCENT); + } + + $this->db->where('discount > 0'); + $this->db->group_by('sales_items.discount'); + $this->db->order_by('sales_items.discount'); + + $this->db->from('sales_items AS sales_items'); $this->db->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner'); - $this->db->where('discount_percent > 0'); - $this->_where($inputs); - $this->db->group_by('sales_items.discount_percent'); - $this->db->order_by('sales_items.discount_percent'); - return $this->db->get()->result_array(); } } diff --git a/application/models/reports/Summary_payments.php b/application/models/reports/Summary_payments.php index 043cc8a43..79e82a03c 100644 --- a/application/models/reports/Summary_payments.php +++ b/application/models/reports/Summary_payments.php @@ -9,15 +9,15 @@ class Summary_payments extends Summary_report return array( array('payment_type' => $this->lang->line('reports_payment_type')), array('report_count' => $this->lang->line('reports_count')), - array('amount_tendered' => $this->lang->line('sales_amount_tendered'), 'sorter' => 'number_sorter')); + array('amount_due' => $this->lang->line('sales_amount_due'), 'sorter' => 'number_sorter')); } public function getData(array $inputs) { - $this->db->select('sales_payments.payment_type, COUNT(sales_payments.sale_id) AS count, SUM(sales_payments.payment_amount) AS payment_amount'); + $this->db->select('sales_payments.payment_type, COUNT(DISTINCT sales_payments.sale_id) AS count, SUM(CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END) AS payment_amount'); $this->db->from('sales_payments AS sales_payments'); $this->db->join('sales AS sales', 'sales.sale_id = sales_payments.sale_id'); - $this->db->join('sales_items AS sales_items', 'sales_items.sale_id = sales_payments.sale_id AND sales_items.line = 1'); + $this->db->join('sales_items AS sales_items', 'sales_items.sale_id = sales_payments.sale_id', 'left'); $this->_where($inputs); diff --git a/application/models/reports/Summary_report.php b/application/models/reports/Summary_report.php index a974336e4..2511f85bd 100644 --- a/application/models/reports/Summary_report.php +++ b/application/models/reports/Summary_report.php @@ -23,7 +23,7 @@ abstract class Summary_report extends Report $decimals = totals_decimals(); - $sale_price = 'sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100)'; + $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END'; $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)'; $tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)'; diff --git a/application/models/reports/Summary_sales_taxes.php b/application/models/reports/Summary_sales_taxes.php new file mode 100644 index 000000000..84087ee86 --- /dev/null +++ b/application/models/reports/Summary_sales_taxes.php @@ -0,0 +1,56 @@ + $this->lang->line('reports_authority')), + array('jurisdiction_name' => $this->lang->line('reports_jurisdiction')), + array('tax_category' => $this->lang->line('reports_tax_category')), + array('tax_rate' => $this->lang->line('reports_tax_rate'), 'sorter' => 'number_sorter'), + array('tax' => $this->lang->line('reports_tax'), 'sorter' => 'number_sorter')); + } + + protected function _where(array $inputs) + { + if(empty($this->config->item('date_or_time_format'))) + { + $this->db->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date'])); + } + else + { + $this->db->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']))); + } + } + + public function getData(array $inputs) + { + $where = ''; + + + + if(empty($this->config->item('date_or_time_format'))) + { + $where .= 'WHERE DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']); + } + else + { + $where .= 'WHERE sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])); + } + + $query = $this->db->query("SELECT reporting_authority, jurisdiction_name, tax_category, tax_rate, + SUM(sale_tax_amount) AS tax + FROM " . $this->db->dbprefix('sales_taxes') . " AS sales_taxes + JOIN " . $this->db->dbprefix('sales') . " AS sales ON sales_taxes.sale_id = sales.sale_id + JOIN " . $this->db->dbprefix('tax_categories') . " AS tax_categories ON sales_taxes.tax_category_id = tax_categories.tax_category_id + JOIN " . $this->db->dbprefix('tax_jurisdictions') . " AS tax_jurisdictions ON sales_taxes.jurisdiction_id = tax_jurisdictions.jurisdiction_id " + . $where . + "GROUP BY reporting_authority, jurisdiction_name, tax_category; "); + + return $query->result_array(); + } +} +?> diff --git a/application/models/reports/Summary_taxes.php b/application/models/reports/Summary_taxes.php index d57a61510..11ab9f343 100644 --- a/application/models/reports/Summary_taxes.php +++ b/application/models/reports/Summary_taxes.php @@ -41,13 +41,13 @@ class Summary_taxes extends Summary_report if($this->config->item('tax_included')) { - $sale_total = '(sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100))'; - $sale_subtotal = '(sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100) * (100 / (100 + sales_items_taxes.percent)))'; + $sale_total = '(CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END)'; + $sale_subtotal = '(CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END * (100 / (100 + sales_items_taxes.percent)))'; } else { - $sale_total = '(sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100) * (1 + (sales_items_taxes.percent / 100)))'; - $sale_subtotal = '(sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount_percent / 100))'; + $sale_total = '(CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END * (1 + (sales_items_taxes.percent / 100)))'; + $sale_subtotal = '(CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END)'; } $decimals = totals_decimals(); diff --git a/application/views/attributes/form.php b/application/views/attributes/form.php new file mode 100644 index 000000000..8cda67c92 --- /dev/null +++ b/application/views/attributes/form.php @@ -0,0 +1,187 @@ +
lang->line('common_fields_required_message'); ?>
+ + + +'attribute_form', 'class'=>'form-horizontal')); ?> +
+ +
+ lang->line('attributes_definition_name'), 'definition_name', array('class' => 'control-label col-xs-3')); ?> +
+ 'definition_name', + 'class'=>'form-control input-sm', + 'value'=>$definition_info->definition_name) + );?> +
+
+ +
+ lang->line('attributes_definition_type'), 'definition_type', array('class'=>'control-label col-xs-3')); ?> +
+ definition_type, DEFINITION_TYPES), 'id="definition_type" class="form-control" ' . ($definition_id != -1 ? 'disabled="disabled"' : ''));?> +
+
+ +
+ lang->line('attributes_definition_group'), 'definition_group', array('class' => 'control-label col-xs-3')); ?> +
+ definition_fk, 'id="definition_group" class="form-control" ' . (empty($definition_group) ? 'disabled="disabled"' : ''));?> +
+
+ + + + + + + +
+ + + diff --git a/application/views/attributes/item.php b/application/views/attributes/item.php new file mode 100644 index 000000000..7d42fff7f --- /dev/null +++ b/application/views/attributes/item.php @@ -0,0 +1,106 @@ + +
+ lang->line("attributes_definition_name"), "definition_name_label", array('class' => 'control-label col-xs-3')); ?> +
+ 'definition_name', 'class' => 'form-control')); ?> +
+ +
+ + $definition_value) +{ +?> + +
+ 'control-label col-xs-3')); ?> +
+
+ + attribute_datetime)) ? DEFAULT_DATETIME : strtotime($attribute_value->attribute_datetime); + echo form_input(array( + 'name' => "attribute_links[$definition_id]", + 'value' => to_datetime($value), + 'class' => 'form-control input-sm datetime', + 'data-definition-id' => $definition_id, + 'readonly' => 'true')); + } + else if ($definition_value['definition_type'] == DROPDOWN) + { + $selected_value = $definition_value['selected_value']; + echo form_dropdown("attribute_links[$definition_id]", $definition_value['values'], $selected_value, "class='form-control' data-definition-id='$definition_id'"); + } + else if ($definition_value['definition_type'] == TEXT) + { + $value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value; + echo form_input("attribute_links[$definition_id]", $value, "class='form-control valid_chars' data-definition-id='$definition_id'"); + } + ?> + +
+
+
+ + + + diff --git a/application/views/attributes/manage.php b/application/views/attributes/manage.php new file mode 100644 index 000000000..d36f32bda --- /dev/null +++ b/application/views/attributes/manage.php @@ -0,0 +1,37 @@ +load->view("partial/header"); ?> + + + + + +
+ +
+ +
+
+
+ +load->view("partial/footer"); ?> diff --git a/application/views/cashups/form.php b/application/views/cashups/form.php new file mode 100644 index 000000000..ede1c42e8 --- /dev/null +++ b/application/views/cashups/form.php @@ -0,0 +1,361 @@ +
lang->line('common_fields_required_message'); ?>
+ + + +cashup_id, array('id'=>'cashups_edit_form', 'class'=>'form-horizontal')); ?> +
+
+ lang->line('cashups_info'), 'cash_ups_info', array('class'=>'control-label col-xs-3')); ?> + cashup_id) ? $this->lang->line('cashups_id') . ' ' . $cash_ups_info->cashup_id : '', 'cashup_id', array('class'=>'control-label col-xs-8', 'style'=>'text-align:left')); ?> +
+ +
+ lang->line('cashups_open_date'), 'open_date', array('class'=>'required control-label col-xs-3')); ?> +
+
+ + 'open_date', + 'id'=>'open_date', + 'class'=>'form-control input-sm datepicker', + 'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($cash_ups_info->open_date))) + );?> +
+
+
+ +
+ lang->line('cashups_open_employee'), 'open_employee', array('class'=>'control-label col-xs-3')); ?> +
+ open_employee_id, 'id="open_employee_id" class="form-control"');?> +
+
+ +
+ lang->line('cashups_open_amount_cash'), 'open_amount_cash', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'open_amount_cash', + 'id'=>'open_amount_cash', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->open_amount_cash)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_transfer_amount_cash'), 'transfer_amount_cash', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'transfer_amount_cash', + 'id'=>'transfer_amount_cash', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->transfer_amount_cash)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_close_date'), 'close_date', array('class'=>'required control-label col-xs-3')); ?> +
+
+ + 'close_date', + 'id'=>'close_date', + 'class'=>'form-control input-sm datepicker', + 'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($cash_ups_info->close_date))) + );?> +
+
+
+ +
+ lang->line('cashups_close_employee'), 'close_employee', array('class'=>'control-label col-xs-3')); ?> +
+ close_employee_id, 'id="close_employee_id" class="form-control"');?> +
+
+ +
+ lang->line('cashups_closed_amount_cash'), 'closed_amount_cash', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'closed_amount_cash', + 'id'=>'closed_amount_cash', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->closed_amount_cash)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_note'), 'note', array('class'=>'control-label col-xs-3')); ?> +
+ 'note', + 'id'=>'note', + 'value'=>0, + 'checked'=>($cash_ups_info->note) ? 1 : 0) + );?> +
+
+ +
+ lang->line('cashups_closed_amount_due'), 'closed_amount_due', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'closed_amount_due', + 'id'=>'closed_amount_due', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->closed_amount_due)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_closed_amount_card'), 'closed_amount_card', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'closed_amount_card', + 'id'=>'closed_amount_card', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->closed_amount_card)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_closed_amount_check'), 'closed_amount_check', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'closed_amount_check', + 'id'=>'closed_amount_check', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->closed_amount_check)) + );?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_closed_amount_total'), 'closed_amount_total', array('class'=>'control-label col-xs-3')); ?> +
+
+ + config->item('currency_symbol'); ?> + + 'closed_amount_total', + 'id'=>'closed_amount_total', + 'readonly'=>'true', + 'class'=>'form-control input-sm', + 'value'=>to_currency_no_money($cash_ups_info->closed_amount_total) + ));?> + + config->item('currency_symbol'); ?> + +
+
+
+ +
+ lang->line('cashups_description'), 'description', array('class'=>'control-label col-xs-3')); ?> +
+ 'description', + 'id'=>'description', + 'class'=>'form-control input-sm', + 'value'=>$cash_ups_info->description) + );?> +
+
+ + cashup_id)) + { + ?> +
+ lang->line('cashups_is_deleted').':', 'deleted', array('class'=>'control-label col-xs-3')); ?> +
+ 'deleted', + 'id'=>'deleted', + 'value'=>1, + 'checked'=>($cash_ups_info->deleted) ? 1 : 0) + );?> +
+
+ +
+ + + diff --git a/application/views/cashups/manage.php b/application/views/cashups/manage.php new file mode 100644 index 000000000..0cb3f7a7a --- /dev/null +++ b/application/views/cashups/manage.php @@ -0,0 +1,63 @@ +load->view("partial/header"); ?> + + + +load->view('partial/print_receipt', array('print_after_sale'=>false, 'selected_printer'=>'takings_printer')); ?> + + + +
+ +
+ +
+
+
+ +load->view("partial/footer"); ?> diff --git a/application/views/configs/email_config.php b/application/views/configs/email_config.php index a1519f4f8..a066e2466 100644 --- a/application/views/configs/email_config.php +++ b/application/views/configs/email_config.php @@ -116,29 +116,29 @@ $(document).ready(function() { var check_protocol = function() { - if($("#protocol").val() == 'sendmail') + if($('#protocol').val() == 'sendmail') { - $("#mailpath").prop('disabled', false); - $("#smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto").prop('disabled', true); + $('#mailpath').prop('disabled', false); + $('#smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto').prop('disabled', true); } - else if($("#protocol").val() == 'smtp') + else if($('#protocol').val() == 'smtp') { - $("#smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto").prop('disabled', false); - $("#mailpath").prop('disabled', true); + $('#smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto').prop('disabled', false); + $('#mailpath').prop('disabled', true); } else { - $("#mailpath, #smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto").prop('disabled', true); + $('#mailpath, #smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto').prop('disabled', true); } }; - $("#protocol").change(check_protocol).ready(check_protocol); + $('#protocol').change(check_protocol).ready(check_protocol); $('#email_config_form').validate($.extend(form_support.handler, { submitHandler: function(form) { $(form).ajaxSubmit({ beforeSerialize: function(arr, $form, options) { - $("#mailpath, #smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto").prop("disabled", false); + $('#mailpath, #smtp_host, #smtp_user, #smtp_pass, #smtp_port, #smtp_timeout, #smtp_crypto').prop('disabled', false); return true; }, success: function(response) { @@ -146,11 +146,11 @@ $(document).ready(function() // set back disabled state check_protocol(); }, - dataType:'json' + dataType: 'json' }); }, - errorLabelContainer: "#email_error_message_box" + errorLabelContainer: '#email_error_message_box' })); }); diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php index cf910dfaf..e84edcfc7 100644 --- a/application/views/configs/general_config.php +++ b/application/views/configs/general_config.php @@ -23,7 +23,46 @@ 'min' => 0, 'max' => 100, 'value' => $this->config->item('default_sales_discount'))); ?> - % + + 'default_sales_discount_type', + 'name' => 'default_sales_discount_type', + 'value' => 1, + 'data-toggle' => 'toggle', + 'data-size' => 'normal', + 'data-onstyle' => 'success', + 'data-on' => ''.$this->config->item('currency_symbol').'', + 'data-off' => '%', + 'checked' => $this->config->item('default_sales_discount_type'))); ?> + + + + + +
+ lang->line('config_default_receivings_discount'), 'default_receivings_discount', array('class' => 'control-label col-xs-2 required')); ?> +
+
+ 'default_receivings_discount', + 'id' => 'default_receivings_discount', + 'class' => 'form-control input-sm required', + 'type' => 'number', + 'min' => 0, + 'max' => 100, + 'value' => $this->config->item('default_receivings_discount'))); ?> + + 'default_receivings_discount_type', + 'name' => 'default_receivings_discount_type', + 'value' => 1, + 'data-toggle' => 'toggle', + 'data-size' => 'normal', + 'data-onstyle' => 'success', + 'data-on' => ''.$this->config->item('currency_symbol').'', + 'data-off' => '%', + 'checked' => $this->config->item('default_receivings_discount_type'))); ?> +
@@ -74,17 +113,17 @@
$this->lang->line('config_top'), - 'bottom' => $this->lang->line('config_bottom') - ), + 'top' => $this->lang->line('config_top'), + 'bottom' => $this->lang->line('config_bottom') + ), $this->config->item('notify_vertical_position'), array('class' => 'form-control input-sm')); ?>
$this->lang->line('config_left'), - 'center' => $this->lang->line('config_center'), - 'right' => $this->lang->line('config_right') - ), + 'left' => $this->lang->line('config_left'), + 'center' => $this->lang->line('config_center'), + 'right' => $this->lang->line('config_right') + ), $this->config->item('notify_horizontal_position'), array('class' => 'form-control input-sm')); ?>
@@ -160,7 +199,7 @@ 'name' => $this->lang->line('items_name'), 'item_number' => $this->lang->line('items_number_information'), 'unit_price' => $this->lang->line('items_unit_price') - ), + ), $this->config->item('suggestions_third_column'), array('class' => 'form-control input-sm')); ?> @@ -214,112 +253,24 @@
- lang->line('config_custom1'), 'config_custom1', array('class' => 'control-label col-xs-2')); ?> -
- 'custom1_name', - 'id' => 'custom1_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom1_name'))); ?> + lang->line('config_multi_pack_enabled'), 'multi_pack_enabled', array('class' => 'control-label col-xs-2')); ?> +
+ 'multi_pack_enabled', + 'id' => 'multi_pack_enabled', + 'value' => 'multi_pack_enabled', + 'checked' => $this->config->item('multi_pack_enabled'))); ?>
- lang->line('config_custom2'), 'config_custom2', array('class' => 'control-label col-xs-2')); ?> -
- 'custom2_name', - 'id' => 'custom2_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom2_name'))); ?> -
-
- -
- lang->line('config_custom3'), 'config_custom3', array('class' => 'control-label col-xs-2')); ?> -
- 'custom3_name', - 'id' => 'custom3_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom3_name'))); ?> -
-
- -
- lang->line('config_custom4'), 'config_custom4', array('class' => 'control-label col-xs-2')); ?> -
- 'custom4_name', - 'id' => 'custom4_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom4_name'))); ?> -
-
- -
- lang->line('config_custom5'), 'config_custom5', array('class' => 'control-label col-xs-2')); ?> -
- 'custom5_name', - 'id' => 'custom5_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom5_name'))); ?> -
-
- -
- lang->line('config_custom6'), 'config_custom6', array('class' => 'control-label col-xs-2')); ?> -
- 'custom6_name', - 'id' => 'custom6_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom6_name'))); ?> -
-
- -
- lang->line('config_custom7'), 'config_custom7', array('class' => 'control-label col-xs-2')); ?> -
- 'custom7_name', - 'id' => 'custom7_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom7_name'))); ?> -
-
- -
- lang->line('config_custom8'), 'config_custom8', array('class' => 'control-label col-xs-2')); ?> -
- 'custom8_name', - 'id' => 'custom8_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom8_name'))); ?> -
-
- -
- lang->line('config_custom9'), 'config_custom9', array('class' => 'control-label col-xs-2')); ?> -
- 'custom9_name', - 'id' => 'custom9_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom9_name'))); ?> -
-
- -
- lang->line('config_custom10'), 'config_custom10', array('class' => 'control-label col-xs-2')); ?> -
- 'custom10_name', - 'id' => 'custom10_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom10_name'))); ?> + lang->line('config_include_hsn'), 'include_hsn', array('class' => 'control-label col-xs-2')); ?> +
+ 'include_hsn', + 'id' => 'include_hsn', + 'value' => 'include_hsn', + 'checked' => $this->config->item('include_hsn'))); ?>
@@ -367,7 +318,6 @@ $(document).ready(function() window.location=''; }); - $('#general_config_form').validate($.extend(form_support.handler, { errorLabelContainer: "#general_error_message_box", @@ -427,7 +377,7 @@ $(document).ready(function() // set back disabled state enable_disable_gcaptcha_enable(); }, - dataType:'json' + dataType: 'json' }); } })); diff --git a/application/views/configs/info_config.php b/application/views/configs/info_config.php index 6b42fc667..016f14872 100644 --- a/application/views/configs/info_config.php +++ b/application/views/configs/info_config.php @@ -134,9 +134,9 @@ $(document).ready(function() { $("a.fileinput-exists").click(function() { $.ajax({ - type: "GET", - url: "", - dataType: "json" + type: 'GET', + url: '', + dataType: 'json' }) }); diff --git a/application/views/configs/mailchimp_config.php b/application/views/configs/integrations_config.php similarity index 92% rename from application/views/configs/mailchimp_config.php rename to application/views/configs/integrations_config.php index 6753e9532..d2b85259d 100644 --- a/application/views/configs/mailchimp_config.php +++ b/application/views/configs/integrations_config.php @@ -2,6 +2,7 @@
lang->line('common_fields_required_message'); ?>
+
lang->line('config_mailchimp_configuration')?>
    @@ -50,18 +51,18 @@ $(document).ready(function() { $('#mailchimp_api_key').change(function() { - $.post("", - $.extend(csrf_form_base(), { + $.post("", { 'mailchimp_api_key': $('#mailchimp_api_key').val() - }), + }, function(response) { - $.notify(response.message, { type: response.success ? 'success' : 'danger'} ); + $.notify(response.message, {type: response.success ? 'success' : 'danger'} ); $('#mailchimp_list_id').empty(); $.each(response.mailchimp_lists, function(val, text) { $('#mailchimp_list_id').append(new Option(text, val)); }); $('#mailchimp_list_id').prop('selectedIndex', 0); - } + }, + 'json' ); }); diff --git a/application/views/configs/invoice_config.php b/application/views/configs/invoice_config.php index 04ea971b6..3e95273a0 100644 --- a/application/views/configs/invoice_config.php +++ b/application/views/configs/invoice_config.php @@ -15,6 +15,13 @@
    +
    + lang->line('config_invoice_type'), 'invoice_type', array('class' => 'control-label col-xs-2')); ?> +
    + config->item('invoice_type'), array('class' => 'form-control input-sm')); ?> +
    +
    +
    lang->line('config_register_mode_default'), 'default_register_mode', array('class' => 'control-label col-xs-2')); ?>
    @@ -169,7 +176,7 @@ $(document).ready(function() var enable_disable_invoice_enable = (function() { var invoice_enabled = $("#invoice_enable").is(":checked"); var work_order_enabled = $("#work_order_enable").is(":checked"); - $("#sales_invoice_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, select[name='default_register_mode'], #sales_quote_format, select[name='line_sequence'], #last_used_invoice_number, #last_used_quote_number, #quote_default_comments, #work_order_enable, #work_order_format, #last_used_work_order_number").prop("disabled", !invoice_enabled); + $("#sales_invoice_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, select[name='default_register_mode'], select[name='invoice_type'], #sales_quote_format, select[name='line_sequence'], #last_used_invoice_number, #last_used_quote_number, #quote_default_comments, #work_order_enable, #work_order_format, #last_used_work_order_number").prop("disabled", !invoice_enabled); if(invoice_enabled) { $("#work_order_format, #last_used_work_order_number").prop("disabled", !work_order_enabled); } else { @@ -207,7 +214,7 @@ $(document).ready(function() enable_disable_invoice_enable(); enable_disable_work_order_enable(); }, - dataType:'json' + dataType: 'json' }); } })); diff --git a/application/views/configs/locale_config.php b/application/views/configs/locale_config.php index eae39c363..3e872c19b 100644 --- a/application/views/configs/locale_config.php +++ b/application/views/configs/locale_config.php @@ -91,6 +91,7 @@ lang->line('config_cash_decimals'), 'cash_decimals', array('class' => 'control-label col-xs-2')); ?>
    '-1', '0' => '0', '1' => '1', '2' => '2' @@ -119,7 +120,9 @@ $this->lang->line('sales_cash') . ' / ' . $this->lang->line('sales_debit') . ' / ' . $this->lang->line('sales_credit'), 'debitcreditcash' => $this->lang->line('sales_debit') . ' / ' . $this->lang->line('sales_credit') . ' / ' . $this->lang->line('sales_cash'), - 'debitcashcredit' => $this->lang->line('sales_debit') . ' / ' . $this->lang->line('sales_cash') . ' / ' . $this->lang->line('sales_credit') + 'debitcashcredit' => $this->lang->line('sales_debit') . ' / ' . $this->lang->line('sales_cash') . ' / ' . $this->lang->line('sales_credit'), + 'creditdebitcash' => $this->lang->line('sales_credit') . ' / ' . $this->lang->line('sales_debit') . ' / ' . $this->lang->line('sales_cash'), + 'creditcashdebit' => $this->lang->line('sales_credit') . ' / ' . $this->lang->line('sales_cash') . ' / ' . $this->lang->line('sales_debit') ), $this->config->item('payment_options_order'), array('class' => 'form-control input-sm')); ?> @@ -144,34 +147,34 @@ 'form-control input-sm') ); ?>
    -
    +
    lang->line('config_timezone'), 'timezone', array('class' => 'control-label col-xs-2')); ?>
    config->item('timezone') ? $this->config->item('timezone') : date_default_timezone_get(), array('class' => 'form-control input-sm')); ?>
    -
    +
    lang->line('config_datetimeformat'), 'datetimeformat', array('class' => 'control-label col-xs-2')); ?>
    - config->item('dateformat'), array('class' => 'form-control input-sm')); ?>
    - config->item('timeformat'), array('class' => 'form-control input-sm')); ?> @@ -224,24 +227,23 @@ //validation and submit handling $(document).ready(function() { - $("span").tooltip(); + $('span').tooltip(); - $("#currency_symbol, #thousands_separator").change(function() { + $('#currency_symbol, #thousands_separator').change(function() { var field = $(this).attr('id'); - var value = $(this).is(":checkbox") ? $(this).is(":checked") : $(this).val(); - var data = { number_locale: $("#number_locale").val() }; + var value = $(this).is(':checkbox') ? $(this).is(':checked') : $(this).val(); + var data = { number_locale: $('#number_locale').val() }; data[field] = value; $.post("", - $.extend(csrf_form_base(), data), + data, function(response) { - $("#number_locale_example").text(response.number_locale_example); + $('#number_locale_example').text(response.number_locale_example); }, 'json' ); }); $('#locale_config_form').validate($.extend(form_support.handler, { - rules: { number_locale: @@ -250,17 +252,16 @@ $(document).ready(function() remote: { url: "", - type: 'post', - data: $.extend(csrf_form_base(), { - 'number_locale': $("#number_locale").val(), - 'thousands_separator': $("#thousands_separator").is(":checked") - }), + type: 'POST', + data: { + 'number_locale': $('#number_locale').val(), + 'thousands_separator': $('#thousands_separator').is(':checked') + }, dataFilter: function(data) { - setup_csrf_token(); var response = JSON.parse(data); - $("#number_locale_example").text(response.number_locale_example); - $("#currency_symbol").val(response.currency_symbol); - $("#thousands_separator").prop('checked', response.thousands_separator); + $('#number_locale_example').text(response.number_locale_example); + $('#currency_symbol').val(response.currency_symbol); + $('#thousands_separator').prop('checked', response.thousands_separator); return response.success; } } @@ -270,12 +271,12 @@ $(document).ready(function() messages: { number_locale: { - required: 'lang->line('config_number_locale_required') ?>', - number_locale: 'lang->line('config_number_locale_invalid') ?>' + required: "lang->line('config_number_locale_required') ?>", + number_locale: "lang->line('config_number_locale_invalid') ?>" } }, - errorLabelContainer: "#locale_error_message_box" + errorLabelContainer: '#locale_error_message_box' })); }); diff --git a/application/views/configs/manage.php b/application/views/configs/manage.php index 55200a6db..f767c5dbe 100644 --- a/application/views/configs/manage.php +++ b/application/views/configs/manage.php @@ -42,7 +42,7 @@ lang->line('config_message'); ?>
  • - lang->line('config_mailchimp'); ?> + lang->line('config_integrations'); ?>
  • lang->line('config_license'); ?> @@ -86,8 +86,8 @@
    load->view("configs/message_config"); ?>
    -
    - load->view("configs/mailchimp_config"); ?> +
    + load->view("configs/integrations_config"); ?>
    load->view("configs/license_config"); ?> diff --git a/application/views/configs/receipt_config.php b/application/views/configs/receipt_config.php index d7e665ebe..8c7bad56c 100644 --- a/application/views/configs/receipt_config.php +++ b/application/views/configs/receipt_config.php @@ -27,12 +27,29 @@ 'name' => 'receipt_font_size', 'id' => 'receipt_font_size', 'class' => 'form-control input-sm required', - 'value'=>$this->config->item('receipt_font_size'))); ?> + 'value' => $this->config->item('receipt_font_size'))); ?> px
  • +
    + lang->line('config_print_delay_autoreturn'), 'print_delay_autoreturn', array('class' => 'control-label col-xs-2 required')); ?> +
    +
    + 'number', + 'min' => '0', + 'max' => '30', + 'name' => 'print_delay_autoreturn', + 'id' => 'print_delay_autoreturn', + 'class' => 'form-control input-sm required', + 'value' => $this->config->item('print_delay_autoreturn'))); ?> + s +
    +
    +
    +
    lang->line('config_email_receipt_check_behaviour'), 'email_receipt_check_behaviour', array('class' => 'control-label col-xs-2')); ?>
    @@ -94,7 +111,7 @@ 'name' => 'receipt_show_company_name', 'value' => 'receipt_show_company_name', 'id' => 'receipt_show_company_name', - 'checked'=>$this->config->item('receipt_show_company_name'))); ?> + 'checked' => $this->config->item('receipt_show_company_name'))); ?>
    @@ -105,7 +122,7 @@ 'name' => 'receipt_show_taxes', 'value' => 'receipt_show_taxes', 'id' => 'receipt_show_taxes', - 'checked'=>$this->config->item('receipt_show_taxes'))); ?> + 'checked' => $this->config->item('receipt_show_taxes'))); ?>
    @@ -116,7 +133,7 @@ 'name' => 'receipt_show_total_discount', 'value' => 'receipt_show_total_discount', 'id' => 'receipt_show_total_discount', - 'checked'=>$this->config->item('receipt_show_total_discount'))); ?> + 'checked' => $this->config->item('receipt_show_total_discount'))); ?>
    @@ -127,7 +144,7 @@ 'name' => 'receipt_show_description', 'value' => 'receipt_show_description', 'id' => 'receipt_show_description', - 'checked'=>$this->config->item('receipt_show_description'))); ?> + 'checked' => $this->config->item('receipt_show_description'))); ?>
    @@ -138,7 +155,7 @@ 'name' => 'receipt_show_serialnumber', 'value' => 'receipt_show_serialnumber', 'id' => 'receipt_show_serialnumber', - 'checked'=>$this->config->item('receipt_show_serialnumber'))); ?> + 'checked' => $this->config->item('receipt_show_serialnumber'))); ?> @@ -149,7 +166,7 @@ 'name' => 'print_silently', 'id' => 'print_silently', 'value' => 'print_silently', - 'checked'=>$this->config->item('print_silently'))); ?> + 'checked' => $this->config->item('print_silently'))); ?> @@ -160,7 +177,7 @@ 'name' => 'print_header', 'id' => 'print_header', 'value' => 'print_header', - 'checked'=>$this->config->item('print_header'))); ?> + 'checked' => $this->config->item('print_header'))); ?> @@ -171,7 +188,7 @@ 'name' => 'print_footer', 'id' => 'print_footer', 'value' => 'print_footer', - 'checked'=>$this->config->item('print_footer'))); ?> + 'checked' => $this->config->item('print_footer'))); ?> @@ -207,7 +224,7 @@ 'name' => 'print_top_margin', 'id' => 'print_top_margin', 'class' => 'form-control input-sm required', - 'value'=>$this->config->item('print_top_margin'))); ?> + 'value' => $this->config->item('print_top_margin'))); ?> px @@ -224,7 +241,7 @@ 'name' => 'print_left_margin', 'id' => 'print_left_margin', 'class' => 'form-control input-sm required', - 'value'=>$this->config->item('print_left_margin'))); ?> + 'value' => $this->config->item('print_left_margin'))); ?> px @@ -241,7 +258,7 @@ 'name' => 'print_bottom_margin', 'id' => 'print_bottom_margin', 'class' => 'form-control input-sm required', - 'value'=>$this->config->item('print_bottom_margin'))); ?> + 'value' => $this->config->item('print_bottom_margin'))); ?> px @@ -258,7 +275,7 @@ 'name' => 'print_right_margin', 'id' => 'print_right_margin', 'class' => 'form-control input-sm required', - 'value'=>$this->config->item('print_right_margin'))); ?> + 'value' => $this->config->item('print_right_margin'))); ?> px @@ -343,6 +360,11 @@ $(document).ready(function() number:true }, receipt_font_size: + { + required:true, + number:true + }, + print_delay_autoreturn: { required:true, number:true @@ -375,6 +397,11 @@ $(document).ready(function() { required:"lang->line('config_receipt_font_size_required'); ?>", number:"lang->line('config_receipt_font_size_number'); ?>" + }, + print_delay_autoreturn: + { + required:"lang->line('config_print_delay_autoreturn_required'); ?>", + number:"lang->line('config_print_delay_autoreturn_number'); ?>" } } })); diff --git a/application/views/configs/reward_config.php b/application/views/configs/reward_config.php index 7d6db5450..bc4922679 100644 --- a/application/views/configs/reward_config.php +++ b/application/views/configs/reward_config.php @@ -69,7 +69,6 @@ $(document).ready(function() var previous_id = 'customer_reward_' + id; var previous_id_next = 'reward_points_' + id; var block = $(this).parent().clone(true); - console.log(block); var new_block = block.insertAfter($(this).parent()); var new_block_id = 'customer_reward_' + ++id; var new_block_id_next = 'reward_points_' + id; diff --git a/application/views/configs/tax_config.php b/application/views/configs/tax_config.php index 86250aad1..d10e662d3 100644 --- a/application/views/configs/tax_config.php +++ b/application/views/configs/tax_config.php @@ -1,237 +1,164 @@ 'tax_config_form', 'class' => 'form-horizontal')); ?> -
    -
    -
    lang->line('common_fields_required_message'); ?>
    -
      +
      +
      +
      lang->line('common_fields_required_message'); ?>
      +
        -
        +
        + lang->line('config_tax_id'), 'tax_id', array('class' => 'control-label col-xs-2')); ?> +
        + 'tax_id', + 'id' => 'tax_id', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('tax_id'))); ?> +
        +
        + +
        lang->line('config_tax_included'), 'tax_included', array('class' => 'control-label col-xs-2')); ?> -
        +
        'tax_included', 'id' => 'tax_included', 'value' => 'tax_included', 'checked'=>$this->config->item('tax_included'))); ?> -
        -
        +
        +
        -
        +
        lang->line('config_default_tax_rate_1'), 'default_tax_1_rate', array('class' => 'control-label col-xs-2')); ?> -
        +
        'default_tax_1_name', 'id' => 'default_tax_1_name', 'class' => 'form-control input-sm', 'value'=>$this->config->item('default_tax_1_name')!==FALSE ? $this->config->item('default_tax_1_name') : $this->lang->line('items_sales_tax_1'))); ?> -
        -
        +
        +
        'default_tax_1_rate', 'id' => 'default_tax_1_rate', 'class' => 'form-control input-sm', 'value'=> to_tax_decimals($this->config->item('default_tax_1_rate')))); ?> - % -
        -
        + % +
        +
        -
        +
        lang->line('config_default_tax_rate_2'), 'default_tax_2_rate', array('class' => 'control-label col-xs-2')); ?> -
        +
        'default_tax_2_name', 'id' => 'default_tax_2_name', 'class' => 'form-control input-sm', 'value'=>$this->config->item('default_tax_2_name')!==FALSE ? $this->config->item('default_tax_2_name') : $this->lang->line('items_sales_tax_2'))); ?> -
        -
        +
        +
        'default_tax_2_rate', 'id' => 'default_tax_2_rate', 'class' => 'form-control input-sm', 'value'=> to_tax_decimals($this->config->item('default_tax_2_rate')))); ?> - % -
        -
        - -
        - lang->line('config_customer_sales_tax_support'), 'customer_sales_tax_support', array('class' => 'control-label col-xs-2')); ?> -
        - 'customer_sales_tax_support', - 'id' => 'customer_sales_tax_support', - 'value' => 'customer_sales_tax_support', - 'checked'=>$this->config->item('customer_sales_tax_support'))); ?> -
        -
        - -
        - lang->line('config_default_origin_tax_code'), 'default_origin_tax_code', array('class' => 'control-label col-xs-2')); ?> -
        - config->item('default_origin_tax_code'), array('class' => 'form-control input-sm')); ?> -
        -
        - - -
        - load->view('partial/tax_categories', array('tax_categories' => $tax_categories)); ?> + % +
        - - 'submit_tax', - 'id' => 'submit_tax', - 'value' => $this->lang->line('common_submit'), - 'class' => 'btn btn-primary btn-sm pull-right')); ?> -
        -
        + +
        + lang->line('config_use_destination_based_tax'), 'use_destination_based_tax', array('class' => 'control-label col-xs-2')); ?> +
        + 'use_destination_based_tax', + 'id' => 'use_destination_based_tax', + 'value' => 'use_destination_based_tax', + 'checked'=>$this->config->item('use_destination_based_tax'))); ?> +
        +
        + +
        + lang->line('config_default_tax_code'), 'default_tax_code', array('class' => 'control-label col-xs-2')); ?> +
        + config->item('default_tax_code'), array('class' => 'form-control input-sm')); ?> +
        +
        + +
        + lang->line('config_default_tax_category'), 'default_tax_category', array('class' => 'control-label col-xs-2')); ?> +
        + config->item('default_tax_category'), array('class' => 'form-control input-sm')); ?> +
        +
        + +
        + lang->line('config_default_tax_jurisdiction'), 'default_tax_jurisdiction', array('class' => 'control-label col-xs-2')); ?> +
        + config->item('default_tax_jurisdiction'), array('class' => 'form-control input-sm')); ?> +
        +
        + + 'submit_tax', + 'id' => 'submit_tax', + 'value' => $this->lang->line('common_submit'), + 'class' => 'btn btn-primary btn-sm pull-right')); ?> +
        +
        + diff --git a/application/views/customers/form.php b/application/views/customers/form.php index c6b534726..5ff8ff6b0 100644 --- a/application/views/customers/form.php +++ b/application/views/customers/form.php @@ -40,18 +40,41 @@ load->view("people/form_basic_info"); ?> + +
        + lang->line('customers_discount_type'), 'discount_type', array('class'=>'control-label col-xs-3')); ?> +
        + + +
        +
        - lang->line('customers_discount'), 'discount_percent', array('class' => 'control-label col-xs-3')); ?> + lang->line('customers_discount'), 'discount', array('class' => 'control-label col-xs-3')); ?>
        'discount_percent', - 'id'=>'discount_percent', + 'name'=>'discount', + 'id'=>'discount', 'class'=>'form-control input-sm', - 'value'=>$person_info->discount_percent) + 'value'=>$person_info->discount) ); ?> - %
        @@ -80,6 +103,18 @@ +
        + lang->line('customers_tax_id'), 'tax_id', array('class' => 'control-label col-xs-3')); ?> +
        + 'tax_id', + 'id'=>'tax_id', + 'class'=>'form-control input-sm', + 'value'=>$person_info->tax_id) + ); ?> +
        +
        + config->item('customer_reward_enable') == TRUE): ?>
        lang->line('rewards_package'), 'rewards', array('class'=>'control-label col-xs-3')); ?> @@ -110,7 +145,7 @@
        @@ -124,7 +159,7 @@ 'size'=>'50', 'value'=>$sales_tax_code_label) ); ?> - sales_tax_code); ?> + sales_tax_code_id); ?>
        @@ -141,7 +176,7 @@ 'name'=>'date', 'id'=>'datetime', 'class'=>'form-control input-sm', - 'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($person_info->date)), + 'value'=>to_datetime(strtotime($person_info->date)), 'readonly'=>'true') ); ?> @@ -416,18 +451,18 @@ $(document).ready(function() { $("input[name='sales_tax_code_name']").change(function() { if( ! $("input[name='sales_tax_code_name']").val() ) { - $("input[name='sales_tax_code']").val(''); + $("input[name='sales_tax_code_id']").val(''); } }); var fill_value = function(event, ui) { event.preventDefault(); - $("input[name='sales_tax_code']").val(ui.item.value); + $("input[name='sales_tax_code_id']").val(ui.item.value); $("input[name='sales_tax_code_name']").val(ui.item.label); }; - $("#sales_tax_code_name").autocomplete({ - source: '', + $('#sales_tax_code_name').autocomplete({ + source: "", minChars: 0, delay: 15, cacheLength: 1, @@ -437,57 +472,56 @@ $(document).ready(function() }); $('#customer_form').validate($.extend({ - submitHandler: function(form) - { + submitHandler: function(form) { $(form).ajaxSubmit({ success: function(response) { dialog_support.hide(); - table_support.handle_submit('', response); + table_support.handle_submit("", response); }, dataType: 'json' }); }, + errorLabelContainer: '#error_message_box', + rules: { - first_name: "required", - last_name: "required", - consent: "required", - email: + first_name: 'required', + last_name: 'required', + consent: 'required', + email: { remote: { - url: "", - type: "post", - data: $.extend(csrf_form_base(), - { - "person_id" : "person_id; ?>", + url: "", + type: 'POST', + data: { + 'person_id': "person_id; ?>" // email is posted by default - }) + } } }, - account_number: + account_number: { remote: { - url: "", - type: "post", - data: $.extend(csrf_form_base(), - { - "person_id" : "person_id; ?>" + url: "", + type: 'POST', + data: { + 'person_id': "person_id; ?>" // account_number is posted by default - }) + } } } - }, + }, - messages: + messages: { - first_name: "lang->line('common_first_name_required'); ?>", - last_name: "lang->line('common_last_name_required'); ?>", - consent: "lang->line('customers_consent_required'); ?>", - email: "lang->line('customers_email_duplicate'); ?>", + first_name: "lang->line('common_first_name_required'); ?>", + last_name: "lang->line('common_last_name_required'); ?>", + consent: "lang->line('customers_consent_required'); ?>", + email: "lang->line('customers_email_duplicate'); ?>", account_number: "lang->line('customers_account_number_duplicate'); ?>" } }, form_support.error)); diff --git a/application/views/customers/form_excel_import.php b/application/views/customers/form_excel_import.php index 5cdad9b6a..7de76791b 100644 --- a/application/views/customers/form_excel_import.php +++ b/application/views/customers/form_excel_import.php @@ -25,9 +25,9 @@ $(document).ready(function() { $('#excel_form').validate($.extend({ - submitHandler:function(form) { + submitHandler: function(form) { $(form).ajaxSubmit({ - success:function(response) + success: function(response) { dialog_support.hide(); $.notify(response.message, { type: response.success ? 'success' : 'danger'} ); @@ -35,12 +35,14 @@ $(document).ready(function() dataType: 'json' }); }, - errorLabelContainer: "#error_message_box", - wrapper: "li", + + errorLabelContainer: '#error_message_box', + rules: { - file_path: "required" + file_path: 'required' }, + messages: { file_path: "lang->line('common_import_full_path'); ?>" diff --git a/application/views/employees/form.php b/application/views/employees/form.php index d7872f747..9b7f05b7b 100644 --- a/application/views/employees/form.php +++ b/application/views/employees/form.php @@ -120,12 +120,12 @@ permission_id); + $exploded_permission = explode('_', $permission->permission_id, 2); if($permission->module_id == $module->module_id) { $lang_key = $module->module_id.'_'.$exploded_permission[1]; $lang_line = $this->lang->line($lang_key); - $lang_line = ($this->lang->line_tbd($lang_key) == $lang_line) ? $exploded_permission[1] : $lang_line; + $lang_line = ($this->lang->line_tbd($lang_key) == $lang_line) ? ucwords(str_replace("_", " ",$exploded_permission[1])) : $lang_line; if(!empty($lang_line)) { ?> @@ -157,67 +157,68 @@ $(document).ready(function() { $.validator.setDefaults({ ignore: [] }); - $.validator.addMethod("module", function (value, element) { - var result = $("#permission_list input").is(":checked"); - $(".module").each(function(index, element) + $.validator.addMethod('module', function (value, element) { + var result = $('#permission_list input').is(':checked'); + $('.module').each(function(index, element) { var parent = $(element).parent(); - var checked = $(element).is(":checked"); - if ($("ul", parent).length > 0 && result) + var checked = $(element).is(':checked'); + if($('ul', parent).length > 0 && result) { - result &= !checked || (checked && $("ul > li > input:checked", parent).length > 0); + result &= !checked || (checked && $('ul > li > input:checked', parent).length > 0); } }); return result; - }, 'lang->line('employees_subpermission_required'); ?>'); + }, "lang->line('employees_subpermission_required'); ?>"); - $("ul#permission_list > li > input.module").each(function() + $('ul#permission_list > li > input.module').each(function() { var $this = $(this); - $("ul > li > input,select", $this.parent()).each(function() + $('ul > li > input,select', $this.parent()).each(function() { var $that = $(this); var updateInputs = function (checked) { - $that.prop("disabled", !checked); - !checked && $that.prop("checked", false); + $that.prop('disabled', !checked); + !checked && $that.prop('checked', false); } $this.change(function() { - updateInputs($this.is(":checked")); + updateInputs($this.is(':checked')); }); - updateInputs($this.is(":checked")); + updateInputs($this.is(':checked')); }); }); $('#employee_form').validate($.extend({ - submitHandler:function(form) - { + submitHandler: function(form) { $(form).ajaxSubmit({ - success:function(response) + success: function(response) { dialog_support.hide(); - table_support.handle_submit('', response); + table_support.handle_submit("", response); }, - dataType:'json' + dataType: 'json' }); }, + + errorLabelContainer: '#error_message_box', + rules: { - first_name: "required", - last_name: "required", + first_name: 'required', + last_name: 'required', username: { - required:true, + required: true, minlength: 5 }, - password: { person_id == "") + if($person_info->person_id == '') { ?> - required:true, + required: true, @@ -225,10 +226,11 @@ $(document).ready(function() }, repeat_password: { - equalTo: "#password" + equalTo: '#password' }, - email: "email" + email: 'email' }, + messages: { first_name: "lang->line('common_first_name_required'); ?>", @@ -238,14 +240,13 @@ $(document).ready(function() required: "lang->line('employees_username_required'); ?>", minlength: "lang->line('employees_username_minlength'); ?>" }, - password: { person_id == "") { ?> - required:"lang->line('employees_password_required'); ?>", + required: "lang->line('employees_password_required'); ?>", diff --git a/application/views/expenses/form.php b/application/views/expenses/form.php index fdede11a7..6340355ba 100644 --- a/application/views/expenses/form.php +++ b/application/views/expenses/form.php @@ -16,9 +16,9 @@ 'date', - 'id'=>'datetime', - 'class'=>'form-control input-sm datepicker', - 'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($expenses_info->date))) + 'class'=>'form-control input-sm datetime', + 'value'=>to_datetime(strtotime($expenses_info->date)), + 'readonly'=>'readonly') );?> @@ -31,9 +31,19 @@ 'name'=>'supplier_name', 'id'=>'supplier_name', 'class'=>'form-control input-sm', - 'value'=>$expenses_info->supplier_name) + 'value'=>$this->lang->line('expenses_start_typing_supplier_name')) + ); + echo form_input(array( + 'type'=>'hidden', + 'name'=>'supplier_id', + 'id'=>'supplier_id') );?> +
        + + + +
        @@ -148,52 +158,74 @@ $(document).ready(function() { load->view('partial/datepicker_locale'); ?> - $('#datetime').datetimepicker({ - format: "config->item('dateformat')) . ' ' . dateformat_bootstrap($this->config->item('timeformat'));?>", - startDate: "config->item('dateformat') . ' ' . $this->config->item('timeformat'), mktime(0, 0, 0, 1, 1, 2010));?>", - config->item('timeformat'); - $m = $t[strlen($t)-1]; - if( strpos($this->config->item('timeformat'), 'a') !== false || strpos($this->config->item('timeformat'), 'A') !== false ) - { - ?> - showMeridian: true, - ", + type: 'POST', + dataFilter: function(data) { + var response = JSON.parse(data); + return response.success; + } } - else - { - ?> - showMeridian: false, - - minuteStep: 1, - autoclose: true, - todayBtn: true, - todayHighlight: true, - bootcssVer: 3, - language: '' + } + + $('#supplier_name').click(function() { + $(this).attr('value', ''); }); - var submit_form = function() - { - $(this).ajaxSubmit( - { - success: function(response) - { - dialog_support.hide(); - table_support.handle_submit('', response); - }, - dataType: 'json' - }); - }; + $('#supplier_name').autocomplete({ + source: '', + minChars:0, + delay:10, + select: function (event, ui) { + $('#supplier_id').val(ui.item.value); + $(this).val(ui.item.label); + $(this).attr('readonly', 'readonly'); + $('#remove_supplier_button').css('display', 'inline-block'); + return false; + } + }); - $('#expenses_edit_form').validate($.extend( + $('#supplier_name').blur(function() { + $(this).attr('value',"lang->line('expenses_start_typing_supplier_name'); ?>"); + }); + + $('#remove_supplier_button').css('display', 'none'); + + $('#remove_supplier_button').click(function() { + $('#supplier_id').val(''); + $('#supplier_name').removeAttr('readonly'); + $('#supplier_name').val(''); + $(this).css('display', 'none'); + }); + + expense_id)) { - submitHandler: function(form) - { - submit_form.call(form); + ?> + $('#supplier_id').val('supplier_id ?>'); + $('#supplier_name').val('supplier_name ?>').attr('readonly', 'readonly'); + $('#remove_supplier_button').css('display', 'inline-block'); + + + $('#expenses_edit_form').validate($.extend({ + submitHandler: function(form) { + $(form).ajaxSubmit({ + success: function(response) + { + dialog_support.hide(); + table_support.handle_submit("", response); + }, + dataType: 'json' + }); }, + + errorLabelContainer: '#error_message_box', + + ignore: '', + rules: { category: 'required', @@ -204,21 +236,30 @@ $(document).ready(function() amount: { required: true, - number: true + remote: amount_validator('#amount') + }, + tax_amount: + { + remote: amount_validator('#tax_amount') } }, + messages: { - category: 'lang->line('expenses_category_required'); ?>', + category: "lang->line('expenses_category_required'); ?>", date: { - required: 'lang->line('expenses_date_required'); ?>' + required: "lang->line('expenses_date_required'); ?>" }, amount: { - required: 'lang->line('expenses_amount_required'); ?>', - number: 'lang->line('expenses_amount_number'); ?>' + required: "lang->line('expenses_amount_required'); ?>", + remote: "lang->line('expenses_amount_number'); ?>" + }, + tax_amount: + { + remote: "lang->line('expenses_tax_amount_number'); ?>" } } }, form_support.error)); diff --git a/application/views/expenses_categories/form.php b/application/views/expenses_categories/form.php index e9a777938..21997b94f 100644 --- a/application/views/expenses_categories/form.php +++ b/application/views/expenses_categories/form.php @@ -35,32 +35,28 @@ //validation and submit handling $(document).ready(function() { - var submit_form = function() - { - $(this).ajaxSubmit( - { - success: function(response) - { - dialog_support.hide(); - table_support.handle_submit('', response); - }, - dataType: 'json' - }); - }; - - $('#expense_category_edit_form').validate($.extend( - { - submitHandler: function(form) - { - submit_form.call(form); + $('#expense_category_edit_form').validate($.extend({ + submitHandler: function(form) { + $(form).ajaxSubmit({ + success: function(response) + { + dialog_support.hide(); + table_support.handle_submit("", response); + }, + dataType: 'json' + }); }, + + errorLabelContainer: '#error_message_box', + rules: { category_name: 'required' }, + messages: { - category_name: 'lang->line('category_name_required'); ?>' + category_name: "lang->line('category_name_required'); ?>" } }, form_support.error)); }); diff --git a/application/views/giftcards/form.php b/application/views/giftcards/form.php index 5184be405..22285ea3a 100644 --- a/application/views/giftcards/form.php +++ b/application/views/giftcards/form.php @@ -72,8 +72,8 @@ $(document).ready(function() $("input[name='person_name']").val(ui.item.label); }; - var autocompleter = $("#person_name").autocomplete({ - source: '', + $('#person_name').autocomplete({ + source: "", minChars: 0, delay: 15, cacheLength: 1, @@ -81,66 +81,72 @@ $(document).ready(function() select: fill_value, focus: fill_value }); - - // declare submitHandler as an object.. will be reused - var submit_form = function() { - $(this).ajaxSubmit({ - success: function(response) - { - dialog_support.hide(); - table_support.handle_submit('', response); - }, - error: function(jqXHR, textStatus, errorThrown) - { - table_support.handle_submit('', {message: errorThrown}); - }, - dataType:'json' - }); - }; - $('#giftcard_form').validate($.extend(form_support.handler, - { - submitHandler:function(form) - { - submit_form.call(form) + $('#giftcard_form').validate($.extend({ + submitHandler: function(form) { + $(form).ajaxSubmit({ + success: function(response) + { + dialog_support.hide(); + table_support.handle_submit("", response); + }, + error: function(jqXHR, textStatus, errorThrown) + { + table_support.handle_submit("", {message: errorThrown}); + }, + dataType: 'json' + }); }, + + errorLabelContainer: '#error_message_box', + rules: { - config->item('giftcard_number') == "series") { ?> + config->item('giftcard_number') == 'series') + { + ?> giftcard_number: { required: true, number: true }, - + giftcard_amount: { required: true, remote: { url: "", - type: 'post', - data: $.extend(csrf_form_base(), { - 'amount': $("#giftcard_amount").val() - }), + type: 'POST', + data: { + 'amount': $('#giftcard_amount').val() + }, dataFilter: function(data) { - setup_csrf_token(); var response = JSON.parse(data); - $("#giftcard_amount").text(response.value); + $('#giftcard_amount').val(response.giftcard_amount); return response.success; } } } }, + messages: { - config->item('giftcard_number') == "series"){ ?> - giftcard_number: - { - required: "lang->line('giftcards_number_required'); ?>", - number: "lang->line('giftcards_number'); ?>" - }, - + config->item('giftcard_number') == 'series') + { + ?> + giftcard_number: + { + required: "lang->line('giftcards_number_required'); ?>", + number: "lang->line('giftcards_number'); ?>" + }, + giftcard_amount: { required: "lang->line('giftcards_value_required'); ?>", diff --git a/application/views/home/form_change_password.php b/application/views/home/form_change_password.php index 44d51bc04..3602a1b74 100644 --- a/application/views/home/form_change_password.php +++ b/application/views/home/form_change_password.php @@ -81,17 +81,17 @@ $(document).ready(function() }, 'lang->line('employees_password_not_must_match'); ?>'); $('#employee_form').validate($.extend({ - submitHandler:function(form) - { + submitHandler: function(form) { $(form).ajaxSubmit({ - success:function(response) + success: function(response) { dialog_support.hide(); - $.notify(response.message, { type: response.success ? 'success' : 'danger'} ); + $.notify(response.message, {type: response.success ? 'success' : 'danger'}); }, - dataType:'json' + dataType: 'json' }); }, + rules: { current_password: @@ -110,6 +110,7 @@ $(document).ready(function() equalTo: "#password" } }, + messages: { password: diff --git a/application/views/item_kits/form.php b/application/views/item_kits/form.php index 9baebb5a4..bf7c80f3b 100644 --- a/application/views/item_kits/form.php +++ b/application/views/item_kits/form.php @@ -16,107 +16,130 @@
        -
        - lang->line('item_kits_find_kit_item'), 'item_name', array('class'=>'control-label col-xs-3')); ?> -
        -
        - 'item_name', - 'id'=>'item_name', - 'class'=>'form-control input-sm', - 'size'=>'50', - 'value'=>$selected_kit_item) - ); ?> - +
        + lang->line('item_kits_find_kit_item'), 'item_name', array('class'=>'control-label col-xs-3')); ?> +
        +
        + 'item_name', + 'id'=>'item_name', + 'class'=>'form-control input-sm', + 'size'=>'50', + 'value'=>$selected_kit_item) + ); ?> + -
        -
        -
        +
        +
        +
        -
        - lang->line('item_kits_discount_percent'), 'kit_discount_percent', array('class' => 'control-label col-xs-3')); ?> -
        -
        - 'kit_discount_percent', - 'size'=>'5', - 'maxlength'=>'5', - 'id'=>'kit_discount_percent', - 'class'=>'form-control input-sm', - 'value'=>$item_kit_info->kit_discount_percent) - );?> - % -
        -
        -
        +
        + lang->line('item_kits_discount_type'), 'kit_discount_type', array('class'=>'control-label col-xs-3')); ?> +
        + + +
        +
        -
        - lang->line('item_kits_price_option'), 'price_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> -
        - - - +
        + lang->line('item_kits_discount'), 'kit_discount', array('class' => 'control-label col-xs-3')); ?> +
        +
        + 'kit_discount', + 'size'=>'5', + 'maxlength'=>'5', + 'id'=>'kit_discount', + 'class'=>'form-control input-sm', + 'value'=>$item_kit_info->kit_discount) + );?> +
        +
        +
        -
        -
        +
        + lang->line('item_kits_price_option'), 'price_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> +
        + + + -
        - lang->line('item_kits_print_option'), 'print_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> -
        - - - +
        +
        -
        -
        +
        + lang->line('item_kits_print_option'), 'print_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> +
        + + + + +
        +
        @@ -146,7 +169,7 @@ lang->line('common_delete'); ?> - lang->line('item_kits_sequence'); ?> + lang->line('item_kits_sequence'); ?> lang->line('item_kits_item'); ?> lang->line('item_kits_quantity'); ?> @@ -158,9 +181,9 @@ ?> - ' name=item_kit_seq[] value=''/> + ' name=item_kit_seq[] value=""/> - ' name=item_kit_qty[] value=''/> + ' name=item_kit_qty[] value=""/> diff --git a/application/views/items/form.php b/application/views/items/form.php index 7ef0f1a2c..30cab1291 100644 --- a/application/views/items/form.php +++ b/application/views/items/form.php @@ -46,7 +46,12 @@
        - +
        + +
        +
        lang->line('items_stock_type'), 'stock_type', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?>
        @@ -80,6 +85,7 @@ 'type'=>'radio', 'id'=>'item_type', 'value'=>0, + 'disabled'=>$item_type_disabled, 'checked'=>$item_info->item_type == ITEM) ); ?> lang->line('items_standard'); ?> @@ -89,11 +95,13 @@ 'type'=>'radio', 'id'=>'item_type', 'value'=>1, + 'disabled'=>$item_type_disabled, 'checked'=>$item_info->item_type == ITEM_KIT) ); ?> lang->line('items_kit'); ?> config->item('derive_sale_quantity') == '1') { + if($this->config->item('derive_sale_quantity') == '1') + { ?>
        -
        lang->line('items_supplier'), 'supplier', array('class'=>'control-label col-xs-3')); ?> @@ -159,6 +180,7 @@
        +
        lang->line('items_tax_1'), 'tax_percent_1', array('class'=>'control-label col-xs-3')); ?>
        @@ -205,14 +227,42 @@
        - + + +
        lang->line('taxes_tax_category'), 'tax_category', array('class'=>'control-label col-xs-3')); ?>
        - 'form-control')); ?> +
        + 'tax_category', + 'id'=>'tax_category', + 'class'=>'form-control input-sm', + 'size'=>'50', + 'value'=>$tax_category) + ); ?> + +
        - + + + + +
        + lang->line('items_hsn_code'), 'category', array('class'=>'control-label col-xs-3')); ?> +
        +
        + 'hsn_code', + 'id'=>'hsn_code', + 'class'=>'form-control input-sm', + 'value'=>$hsn_code) + );?> +
        +
        +
        + $location_detail) @@ -315,6 +365,50 @@ + config->item('multi_pack_enabled') == '1') + { + ?> +
        + lang->line('items_qty_per_pack'), 'qty_per_pack', array('class'=>'control-label col-xs-3')); ?> +
        + 'qty_per_pack', + 'id'=>'qty_per_pack', + 'class'=>'form-control input-sm', + 'value'=>isset($item_info->item_id) ? to_quantity_decimals($item_info->qty_per_pack) : to_quantity_decimals(0)) + );?> +
        +
        +
        + lang->line('items_pack_name'), 'name', array('class'=>'control-label col-xs-3')); ?> +
        + 'pack_name', + 'id'=>'pack_name', + 'class'=>'form-control input-sm', + 'value'=>$item_info->pack_name) + );?> +
        +
        +
        + lang->line('items_low_sell_item'), 'low_sell_item_name', array('class'=>'control-label col-xs-3')); ?> +
        +
        + 'low_sell_item_name', + 'id'=>'low_sell_item_name', + 'class'=>'form-control input-sm', + 'value'=>$selected_low_sell_item) + ); ?> + +
        +
        +
        + +
        lang->line('items_is_deleted'), 'is_deleted', array('class'=>'control-label col-xs-3')); ?>
        @@ -327,30 +421,6 @@
        - - config->item('custom'.$i.'_name') != NULL) - { - $item_arr = (array)$item_info; - ?> -
        - config->item('custom'.$i.'_name'), 'custom'.$i, array('class'=>'control-label col-xs-3')); ?> -
        - 'custom'.$i, - 'id'=>'custom'.$i, - 'class'=>'form-control input-sm', - 'value'=>$item_arr['custom'.$i]) - );?> -
        -
        - @@ -358,65 +428,85 @@ //validation and submit handling $(document).ready(function() { - $("#new").click(function() { + $('#new').click(function() { stay_open = true; $("#item_form").submit(); }); - $("#submit").click(function() { + $('#submit').click(function() { stay_open = false; }); - var no_op = function(event, data, formatted){}; - $("#category").autocomplete({source: "",delay:10,appendTo: '.modal-content'}); + $("input[name='tax_category']").change(function() { + !$(this).val() && $(this).val(''); + }); - - $("#custom" + ).autocomplete({ - source:function (request, response) { - $.ajax({ - type: "POST", - url: "", - dataType: "json", - data: $.extend(request, $extend(csrf_form_base(), {field_no: })), - success: function(data) { - response($.map(data, function(item) { - return { - value: item.label - }; - })) - } - }); - }, - delay: 10, - appendTo: '.modal-content'}); - + var fill_value = function(event, ui) { + event.preventDefault(); + $("input[name='tax_category_id']").val(ui.item.value); + $("input[name='tax_category']").val(ui.item.label); + }; - $("a.fileinput-exists").click(function() { + $('#tax_category').autocomplete({ + source: "", + minChars: 0, + delay: 15, + cacheLength: 1, + appendTo: '.modal-content', + select: fill_value, + focus: fill_value + }); + + + + var fill_value = function(event, ui) { + event.preventDefault(); + $("input[name='low_sell_item_id']").val(ui.item.value); + $("input[name='low_sell_item_name']").val(ui.item.label); + }; + + $('#low_sell_item_name').autocomplete({ + source: "", + minChars: 0, + delay: 15, + cacheLength: 1, + appendTo: '.modal-content', + select: fill_value, + focus: fill_value + }); + + $("#category").autocomplete({ + source: "", + delay: 10, + appendTo: '.modal-content' + }); + + $('a.fileinput-exists').click(function() { $.ajax({ - type: "GET", - url: "item_id"); ?>", - dataType: "json" + type: 'GET', + url: "item_id'); ?>", + dataType: 'json' }) }); + $.validator.addMethod('valid_chars', function(value, element) { + return value.match(/(\||:)/g) == null; + }, "lang->line('attributes_attribute_value_invalid_chars'); ?>"); + $('#item_form').validate($.extend({ submitHandler: function(form, event) { $(form).ajaxSubmit({ success: function(response) { var stay_open = dialog_support.clicked_id() != 'submit'; - if (stay_open) + if(stay_open) { // set action of item_form to url without item id, so a new one can be created - $("#item_form").attr("action", ""); + $('#item_form').attr('action', ""); // use a whitelist of fields to minimize unintended side effects - $(':text, :password, :file, #description, #item_form').not('.quantity, #reorder_level, #tax_name_1,' + - '#tax_percent_name_1, #reference_number, #name, #cost_price, #unit_price, #taxed_cost_price, #taxed_unit_price').val(''); + $(':text, :password, :file, #description, #item_form').not('.quantity, #reorder_level, #tax_name_1, #receiving_quantity, ' + + '#tax_percent_name_1, #category, #reference_number, #name, #cost_price, #unit_price, #taxed_cost_price, #taxed_unit_price, #definition_name, [name^="attribute_links"]').val(''); // de-select any checkboxes, radios and drop-down menus - $(':input', '#item_form').not('#item_category_id').removeAttr('checked').removeAttr('selected'); + $(':input', '#item_form').removeAttr('checked').removeAttr('selected'); } else { @@ -428,25 +518,26 @@ $(document).ready(function() }); }, + errorLabelContainer: '#error_message_box', + rules: { - name: "required", - category: "required", + name: 'required', + category: 'required', item_number: { required: false, remote: { url: "", - type: "post", - data: $.extend(csrf_form_base(), - { - "item_id": "item_id; ?>", - "item_number": function() + type: 'POST', + data: { + 'item_id' : "item_id; ?>", + 'item_number' : function() { - return $("#item_number").val(); + return $('#item_number').val(); }, - }) + } } }, cost_price: @@ -534,3 +625,4 @@ $(document).ready(function() }, form_support.error)); }); + diff --git a/application/views/items/form_bulk.php b/application/views/items/form_bulk.php index 228eeeade..eceb13ca8 100644 --- a/application/views/items/form_bulk.php +++ b/application/views/items/form_bulk.php @@ -162,53 +162,60 @@ //validation and submit handling $(document).ready(function() { - $("#category").autocomplete({source: "", appendTo:'.modal-content', delay:10}); + $('#category').autocomplete({ + source: "", + appendTo: '.modal-content', + delay: 10 + }); var confirm_message = false; - $("#tax_percent_name_2, #tax_name_2").prop('disabled', true), - $("#tax_percent_name_1, #tax_name_1").blur(function() { - var disabled = !($("#tax_percent_name_1").val() + $("#tax_name_1").val()); - $("#tax_percent_name_2, #tax_name_2").prop('disabled', disabled); - confirm_message = disabled ? "" : "lang->line('items_confirm_bulk_edit_wipe_taxes') ?>"; + $('#tax_percent_name_2, #tax_name_2').prop('disabled', true), + $('#tax_percent_name_1, #tax_name_1').blur(function() { + var disabled = !($('#tax_percent_name_1').val() + $('#tax_name_1').val()); + $('#tax_percent_name_2, #tax_name_2').prop('disabled', disabled); + confirm_message = disabled ? '' : "lang->line('items_confirm_bulk_edit_wipe_taxes') ?>"; }); $('#item_form').validate($.extend({ - submitHandler:function(form) - { + submitHandler: function(form) { if(!confirm_message || confirm(confirm_message)) { $(form).ajaxSubmit({ beforeSubmit: function(arr, $form, options) { - arr.push({name: 'item_ids', value: table_support.selected_ids().join(": ")}); + arr.push({name: 'item_ids', value: table_support.selected_ids().join(":")}); }, - success:function(response) + success: function(response) { dialog_support.hide(); - table_support.handle_submit('', response); + table_support.handle_submit("", response); }, - dataType:'json' + dataType: 'json' }); } }, + + errorLabelContainer: '#error_message_box', + rules: { unit_price: { - number:true + number: true }, tax_percent: { - number:true + number: true }, quantity: { - number:true + number: true }, reorder_level: { - number:true + number: true } }, + messages: { unit_price: diff --git a/application/views/items/form_excel_import.php b/application/views/items/form_excel_import.php index 32e03fa34..229b414b9 100644 --- a/application/views/items/form_excel_import.php +++ b/application/views/items/form_excel_import.php @@ -25,7 +25,7 @@ $(document).ready(function() { $('#excel_form').validate($.extend({ - submitHandler:function(form) { + submitHandler: function(form) { $(form).ajaxSubmit({ success:function(response) { @@ -35,12 +35,14 @@ $(document).ready(function() dataType: 'json' }); }, - errorLabelContainer: "#error_message_box", - wrapper: "li", + + errorLabelContainer: '#error_message_box', + rules: { - file_path: "required" + file_path: 'required' }, + messages: { file_path: "lang->line('common_import_full_path'); ?>" diff --git a/application/views/items/form_inventory.php b/application/views/items/form_inventory.php index 61172bc16..417ae19fa 100644 --- a/application/views/items/form_inventory.php +++ b/application/views/items/form_inventory.php @@ -97,29 +97,29 @@ //validation and submit handling $(document).ready(function() { - $('#item_form').validate({ - submitHandler:function(form) - { + $('#item_form').validate($.extend({ + submitHandler: function(form) { $(form).ajaxSubmit({ - success:function(response) - { - dialog_support.hide(); - table_support.handle_submit('', response); - }, - dataType: 'json' - }); - + success: function(response) + { + dialog_support.hide(); + table_support.handle_submit("", response); + }, + dataType: 'json' + }); }, - errorLabelContainer: "#error_message_box", - wrapper: "li", + + errorLabelContainer: '#error_message_box', + rules: { newquantity: { - required:true, - number:true + required: true, + number: true } }, + messages: { newquantity: @@ -128,12 +128,12 @@ $(document).ready(function() number: "lang->line('items_quantity_number'); ?>" } } - }); + }, form_support.error)); }); function fill_quantity(val) { - var item_quantities = ; - document.getElementById("quantity").value = parseFloat(item_quantities[val]).toFixed(); + var item_quantities = ; + document.getElementById('quantity').value = parseFloat(item_quantities[val]).toFixed(); } diff --git a/application/views/login.php b/application/views/login.php index aae7977fa..d3c5a7228 100644 --- a/application/views/login.php +++ b/application/views/login.php @@ -19,6 +19,10 @@
        + migration->is_latest()): ?> +
        lang->line('common_migration_needed', $this->config->item('application_version')); ?>
        + +
        diff --git a/application/views/messages/form_sms.php b/application/views/messages/form_sms.php index 43615414d..653d0c400 100644 --- a/application/views/messages/form_sms.php +++ b/application/views/messages/form_sms.php @@ -35,45 +35,49 @@ \ No newline at end of file + diff --git a/application/views/partial/bootstrap_tables_locale.php b/application/views/partial/bootstrap_tables_locale.php index 612c2bd7e..3aef29dd1 100644 --- a/application/views/partial/bootstrap_tables_locale.php +++ b/application/views/partial/bootstrap_tables_locale.php @@ -33,12 +33,16 @@ formatAllRows: function () { return "lang->line('tables_all'); ?>"; }, - formatConfirmDelete : function() { - return "lang->line((isset($editable) ? $editable : $controller_name). "_confirm_delete")?>"; - }, - formatConfirmRestore : function() { - return "lang->line((isset($editable) ? $editable : $controller_name). "_confirm_restore")?>"; - } + formatConfirmAction: function(action) { + if (action == "delete") + { + return "lang->line((isset($editable) ? $editable : $controller_name). "_confirm_delete")?>"; + } + else + { + return "lang->line((isset($editable) ? $editable : $controller_name). "_confirm_restore")?>"; + } + } }; $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales[""]); diff --git a/application/views/partial/datepicker_locale.php b/application/views/partial/datepicker_locale.php index cb9544f6a..78b391aad 100644 --- a/application/views/partial/datepicker_locale.php +++ b/application/views/partial/datepicker_locale.php @@ -1,5 +1,34 @@ lang->load('calendar'); $this->lang->load('date'); ?> +var pickerconfig = function(start) { + return { + format: "config->item('dateformat')) . ' ' . dateformat_bootstrap($this->config->item('timeformat'));?>", + startDate: start || "", + config->item('timeformat'); + $m = $t[strlen($t)-1]; + if( strpos($this->config->item('timeformat'), 'a') !== false || strpos($this->config->item('timeformat'), 'A') !== false ) + { + ?> + showMeridian: true, + + showMeridian: false, + + minuteStep: 1, + autoclose: true, + todayBtn: true, + todayHighlight: true, + bootcssVer: 3, + language: "" + }; +}; + $.fn.datetimepicker.dates['config->item("language"); ?>'] = { days: [ "lang->line("cal_sunday"); ?>", @@ -79,4 +108,6 @@ $.fn.datetimepicker.dates['config->item("language"); ?>'] = { } ?> weekStart: lang->line("datepicker_weekstart"); ?> -}; \ No newline at end of file +}; + +$(".datetime").datetimepicker(pickerconfig()); \ No newline at end of file diff --git a/application/views/partial/footer.php b/application/views/partial/footer.php index 4f5ad5761..785f0b463 100644 --- a/application/views/partial/footer.php +++ b/application/views/partial/footer.php @@ -4,7 +4,7 @@