From 893aad350227d215c768088fb384f5512522d6e3 Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sat, 2 Sep 2017 13:31:33 -0400 Subject: [PATCH 01/12] Add Office Menu --- application/controllers/Config.php | 3 + application/controllers/Employees.php | 13 +++- application/controllers/Home.php | 5 ++ application/controllers/Office.php | 24 +++++++ application/controllers/Secure_Controller.php | 21 +++++- application/language/en-US/config_lang.php | 1 + application/language/en-US/module_lang.php | 4 ++ application/models/Employee.php | 41 ++++++++--- application/models/Module.php | 61 +++++++++++++++- application/views/configs/general_config.php | 32 +++++++-- application/views/employees/form.php | 56 ++++++++------- application/views/office.php | 23 +++++++ application/views/partial/header.php | 17 +++-- database/3.1.0_to_office-menu.sql | 20 ++++++ database/database.sql | 63 +++++++++-------- database/tables.sql | 65 ++++++++++-------- public/images/menubar/home.png | Bin 0 -> 1099 bytes public/images/menubar/office.png | Bin 0 -> 1099 bytes 18 files changed, 342 insertions(+), 107 deletions(-) create mode 100644 application/controllers/Office.php create mode 100644 application/views/office.php create mode 100644 database/3.1.0_to_office-menu.sql create mode 100644 public/images/menubar/home.png create mode 100644 public/images/menubar/office.png diff --git a/application/controllers/Config.php b/application/controllers/Config.php index 6684f52ed..fce888253 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -206,6 +206,7 @@ class Config extends Secure_Controller $data['register_mode_options'] = $this->sale_lib->get_register_mode_options(); $data['rounding_options'] = Rounding_mode::get_rounding_options(); $data['tax_codes'] = $this->get_tax_code_options(); + $data['show_office_group'] = $this->Module->get_show_office_group(); $data = $this->xss_clean($data); @@ -308,6 +309,8 @@ class Config extends Secure_Controller 'custom10_name' => $this->input->post('custom10_name') ); + $this->Module->set_show_office_group($this->input->post('show_office_group') != NULL); + $result = $this->Appconfig->batch_save($batch_save_data); $success = $result ? TRUE : FALSE; diff --git a/application/controllers/Employees.php b/application/controllers/Employees.php index 533f334b2..18960ad4a 100644 --- a/application/controllers/Employees.php +++ b/application/controllers/Employees.php @@ -61,6 +61,7 @@ class Employees extends Persons { $module->module_id = $this->xss_clean($module->module_id); $module->grant = $this->xss_clean($this->Employee->has_grant($module->module_id, $person_info->person_id)); + $module->menu_group = $this->xss_clean($this->Employee->get_menu_group($module->module_id, $person_info->person_id)); $modules[] = $module; } @@ -134,6 +135,16 @@ class Employees extends Persons 'comments' => $this->input->post('comments'), ); $grants_data = $this->input->post('grants') != NULL ? $this->input->post('grants') : array(); + $menu_groups = $this->input->post('menu_groups') != NULL ? $this->input->post('menu_groups') : array(); + + $grants_array = array(); + foreach ($grants_data as $key => $value) + { + $grants = array(); + $grants['permission_id'] = $value; + $grants['menu_group'] = $menu_groups[$key]; + $grants_array[] = $grants; + } //Password has been changed OR first time password set if($this->input->post('password') != '') @@ -149,7 +160,7 @@ class Employees extends Persons $employee_data = array('username' => $this->input->post('username')); } - if($this->Employee->save_employee($person_data, $employee_data, $grants_data, $employee_id)) + if($this->Employee->save_employee($person_data, $employee_data, $grants_array, $employee_id)) { // New employee if($employee_id == -1) diff --git a/application/controllers/Home.php b/application/controllers/Home.php index 87c1df243..c4c4a5820 100644 --- a/application/controllers/Home.php +++ b/application/controllers/Home.php @@ -4,6 +4,11 @@ require_once("Secure_Controller.php"); class Home extends Secure_Controller { + function __construct() + { + parent::__construct(NULL,NULL,'home'); + } + public function index() { $this->load->view('home'); diff --git a/application/controllers/Office.php b/application/controllers/Office.php new file mode 100644 index 000000000..d9339a4d0 --- /dev/null +++ b/application/controllers/Office.php @@ -0,0 +1,24 @@ +load->view('office'); + } + + public function logout() + { + $this->track_page('logout', 'logout'); + + $this->Employee->logout(); + } +} +?> diff --git a/application/controllers/Secure_Controller.php b/application/controllers/Secure_Controller.php index ad7f18e20..3125ae518 100644 --- a/application/controllers/Secure_Controller.php +++ b/application/controllers/Secure_Controller.php @@ -6,7 +6,7 @@ class Secure_Controller extends CI_Controller * Controllers that are considered secure extend Secure_Controller, optionally a $module_id can * be set to also check if a user can access a particular module in the system. */ - public function __construct($module_id = NULL, $submodule_id = NULL) + public function __construct($module_id = NULL, $submodule_id = NULL, $menu_group = NULL) { parent::__construct(); @@ -28,7 +28,24 @@ class Secure_Controller extends CI_Controller } // load up global data visible to all the loaded views - $data['allowed_modules'] = $this->Module->get_allowed_modules($logged_in_employee_info->person_id); + + $this->load->library('session'); + if($menu_group == NULL) + { + $menu_group = $this->session->userdata('menu_group'); + } + else + { + $this->session->set_userdata('menu_group', $menu_group); + } + if($menu_group == 'home') + { + $data['allowed_modules'] = $this->Module->get_allowed_home_modules($logged_in_employee_info->person_id); + } + else + { + $data['allowed_modules'] = $this->Module->get_allowed_office_modules($logged_in_employee_info->person_id); + } $data['user_info'] = $logged_in_employee_info; $data['controller_name'] = $module_id; diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index f106569f9..3b028986c 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -225,6 +225,7 @@ $lang["config_sales_invoice_format"] = "Sales Invoice Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration save successful."; $lang["config_saved_unsuccessfully"] = "Configuration save failed."; +$lang["config_show_office_group"] = "Show office icon"; $lang["config_statistics"] = "Send Statistics"; $lang["config_statistics_tooltip"] = "Send statistics for development and feature improvement purposes."; $lang["config_stock_location"] = "Stock location"; diff --git a/application/language/en-US/module_lang.php b/application/language/en-US/module_lang.php index e447a17a6..55bc997a4 100644 --- a/application/language/en-US/module_lang.php +++ b/application/language/en-US/module_lang.php @@ -1,5 +1,6 @@ db->insert('grants', array('permission_id' => $permission_id, 'person_id' => $employee_id)); + $success = $this->db->insert('grants', array('permission_id' => $grant['permission_id'], 'person_id' => $employee_id, 'menu_group' => $grant['menu_group'])); + $count = $count+ 1; } } } @@ -390,9 +392,9 @@ class Employee extends Person return ($this->db->get()->num_rows() == 0); } - /* - Determines whether the employee specified employee has access the specific module. - */ + /** + * Determines whether the employee specified employee has access the specific module. + */ public function has_grant($permission_id, $person_id) { //if no module_id is null, allow access @@ -406,9 +408,32 @@ class Employee extends Person return ($query->num_rows() == 1); } - /* - Gets employee permission grants - */ + /** + * Returns the menu group designation that this module is to appear in + */ + public function get_menu_group($permission_id, $person_id) + { + $this->db->select('menu_group'); + $this->db->from('grants'); + $this->db->where('permission_id', $permission_id); + $this->db->where('person_id', $person_id); + + $row = $this->db->get()->row(); + + // If no grants are assigned yet then set the default to 'home' + if ($row == null) + { + return "home"; + } + else + { + return $row->menu_group; + } + } + + /* + Gets employee permission grants + */ public function get_employee_grants($person_id) { $this->db->from('grants'); diff --git a/application/models/Module.php b/application/models/Module.php index 09edd4d6a..1b95375c7 100644 --- a/application/models/Module.php +++ b/application/models/Module.php @@ -6,6 +6,11 @@ class Module extends CI_Model { + function __construct() + { + parent::__construct(); + } + public function get_module_name($module_id) { $query = $this->db->get_where('modules', array('module_id' => $module_id), 1); @@ -55,19 +60,69 @@ class Module extends CI_Model { $this->db->from('modules'); $this->db->order_by('sort', 'asc'); - return $this->db->get(); } - public function get_allowed_modules($person_id) + public function get_allowed_home_modules($person_id) { + $menus = array('home', 'both'); $this->db->from('modules'); $this->db->join('permissions', 'permissions.permission_id = modules.module_id'); $this->db->join('grants', 'permissions.permission_id = grants.permission_id'); $this->db->where('person_id', $person_id); + $this->db->where_in('menu_group', $menus); + $this->db->where('sort !=', 0); $this->db->order_by('sort', 'asc'); - return $this->db->get(); } + + public function get_allowed_office_modules($person_id) + { + $menus = array('office', 'both'); + $this->db->from('modules'); + $this->db->join('permissions', 'permissions.permission_id = modules.module_id'); + $this->db->join('grants', 'permissions.permission_id = grants.permission_id'); + $this->db->where('person_id', $person_id); + $this->db->where_in('menu_group', $menus); + $this->db->where('sort !=', 0); + $this->db->order_by('sort', 'asc'); + return $this->db->get(); + } + + /** + * This method is used to set the show the office navigation icon on the home page + * which happens when the sort value is greater than zero + */ + public function set_show_office_group($show_office_group) + { + if($show_office_group) + { + $sort = 1; + } + else + { + $sort = 0; + } + + $modules_data = array( + 'sort' => $sort + ); + $this->db->where('module_id', 'office'); + $this->db->update('modules', $modules_data); + } + + /** + * This method is used to show the office navigation icon on the home page + * which happens when the sort value is greater than zero + */ + public function get_show_office_group() + { + $this->db->select('sort'); + $this->db->from('grants'); + $this->db->where('module_id', 'office'); + $this->db->from('modules'); + return $this->db->get()->row()->sort; + } + } ?> diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php index 1b179cf5c..86bc5a8c0 100644 --- a/application/views/configs/general_config.php +++ b/application/views/configs/general_config.php @@ -94,7 +94,7 @@
- lang->line('config_gcaptcha_site_key'), 'config_gcaptcha_site_key', array('class' => 'required control-label col-xs-2')); ?> + lang->line('config_gcaptcha_site_key'), 'config_gcaptcha_site_key', array('class' => 'required control-label col-xs-2','id' => 'config_gcaptcha_site_key')); ?>
'gcaptcha_site_key', @@ -105,7 +105,7 @@
- lang->line('config_gcaptcha_secret_key'), 'config_gcaptcha_secret_key', array('class' => 'required control-label col-xs-2')); ?> + lang->line('config_gcaptcha_secret_key'), 'config_gcaptcha_secret_key', array('class' => 'required control-label col-xs-2','id' => 'config_gcaptcha_secret_key')); ?>
'gcaptcha_secret_key', @@ -150,6 +150,17 @@
+
+ lang->line('config_show_office_group'), 'show_office_group', array('class' => 'control-label col-xs-2')); ?> +
+ 'show_office_group', + 'id' => 'show_office_group', + 'value' => 'show_office_group', + 'checked' => $show_office_group)); ?> +
+
+
lang->line('config_custom1'), 'config_custom1', array('class' => 'control-label col-xs-2')); ?>
@@ -284,7 +295,17 @@ $(document).ready(function() { var enable_disable_gcaptcha_enable = (function() { var gcaptcha_enable = $("#gcaptcha_enable").is(":checked"); - $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", !gcaptcha_enable); + if(gcaptcha_enable) + { + $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", !gcaptcha_enable).addClass("required"); + $("#config_gcaptcha_site_key, #config_gcaptcha_secret_key").addClass("required"); + } + else + { + $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", gcaptcha_enable).removeClass("required"); + $("#config_gcaptcha_site_key, #config_gcaptcha_secret_key").removeClass("required"); + } + return arguments.callee; })(); @@ -294,6 +315,7 @@ $(document).ready(function() window.location=''; }); + $('#general_config_form').validate($.extend(form_support.handler, { errorLabelContainer: "#general_error_message_box", @@ -312,11 +334,11 @@ $(document).ready(function() }, gcaptcha_site_key: { - required: true + required: "#gcaptcha_enable:checked" }, gcaptcha_secret_key: { - required: true + required: "#gcaptcha_enable:checked" } }, diff --git a/application/views/employees/form.php b/application/views/employees/form.php index 077a98639..cb97befc1 100644 --- a/application/views/employees/form.php +++ b/application/views/employees/form.php @@ -82,6 +82,11 @@ ?>
  • module_id, $module->grant, "class='module'"); ?> + $this->lang->line('module_home'), + 'office' => $this->lang->line('module_office'), + 'both' => $this->lang->line('module_both') + ), $module->menu_group, "class='module'"); ?> lang->line('module_'.$module->module_id);?>: lang->line('module_'.$module->module_id.'_desc');?>
  • permission_id, $permission->grant); ?> +
  • @@ -139,20 +145,20 @@ $(document).ready(function() $("ul#permission_list > li > input[name='grants[]']").each(function() { - var $this = $(this); - $("ul > li > input", $this.parent()).each(function() - { - var $that = $(this); - var updateCheckboxes = function (checked) - { + var $this = $(this); + $("ul > li > input", $this.parent()).each(function() + { + var $that = $(this); + var updateCheckboxes = function (checked) + { $that.prop("disabled", !checked); - !checked && $that.prop("checked", false); - } - $this.change(function() { - updateCheckboxes($this.is(":checked")); - }); + !checked && $that.prop("checked", false); + } + $this.change(function() { + updateCheckboxes($this.is(":checked")); + }); updateCheckboxes($this.is(":checked")); - }); + }); }); $('#employee_form').validate($.extend({ @@ -191,20 +197,20 @@ $(document).ready(function() }, repeat_password: { - equalTo: "#password" + equalTo: "#password" }, - email: "email" - }, + email: "email" + }, messages: { - first_name: "lang->line('common_first_name_required'); ?>", - last_name: "lang->line('common_last_name_required'); ?>", - username: - { - required: "lang->line('employees_username_required'); ?>", - minlength: "lang->line('employees_username_minlength'); ?>" - }, - + first_name: "lang->line('common_first_name_required'); ?>", + last_name: "lang->line('common_last_name_required'); ?>", + username: + { + required: "lang->line('employees_username_required'); ?>", + minlength: "lang->line('employees_username_minlength'); ?>" + }, + password: { lang->line('employees_password_must_match'); ?>" - }, - email: "lang->line('common_email_invalid_format'); ?>" + }, + email: "lang->line('common_email_invalid_format'); ?>" } }, form_support.error)); }); diff --git a/application/views/office.php b/application/views/office.php new file mode 100644 index 000000000..f55c47bb4 --- /dev/null +++ b/application/views/office.php @@ -0,0 +1,23 @@ +load->view("partial/header"); ?> + + + +

    lang->line('common_welcome_message'); ?>

    + + + +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/partial/header.php b/application/views/partial/header.php index 192acd02d..80420f109 100644 --- a/application/views/partial/header.php +++ b/application/views/partial/header.php @@ -124,13 +124,16 @@
    diff --git a/database/3.1.0_to_office-menu.sql b/database/3.1.0_to_office-menu.sql new file mode 100644 index 000000000..01045577d --- /dev/null +++ b/database/3.1.0_to_office-menu.sql @@ -0,0 +1,20 @@ +-- Add support for office menu group +ALTER TABLE `ospos_grants` + ADD COLUMN `menu_group` varchar(32) DEFAULT 'home'; + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES +('module_office', 'module_office_desc', 1, 'office'), +('module_home', 'module_home_desc', 1, 'home'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES +('office', 'office'), +('home', 'home'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES +('office', 1, 'home'), +('home', 1, 'office'); + +update `ospos_grants` +set menu_group = 'office' +where permission_id in ('config', 'home', 'employees', 'taxes', 'migrate') +and person_id = 1; \ No newline at end of file diff --git a/database/database.sql b/database/database.sql index ad706468b..02b0de8a3 100644 --- a/database/database.sql +++ b/database/database.sql @@ -354,10 +354,12 @@ INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_i ('module_customers', 'module_customers_desc', 10, 'customers'), ('module_employees', 'module_employees_desc', 80, 'employees'), ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), +('module_home', 'module_home_desc', 1, 'home'), ('module_items', 'module_items_desc', 20, 'items'), ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'), ('module_messages', 'module_messages_desc', 100, 'messages'), ('module_migrate', 'module_migrate_desc', 120, 'migrate'), +('module_office', 'module_office_desc', 1, 'office'), ('module_receivings', 'module_receivings_desc', 60, 'receivings'), ('module_reports', 'module_reports_desc', 50, 'reports'), ('module_sales', 'module_sales_desc', 70, 'sales'), @@ -428,10 +430,12 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('customers', 'customers'), ('employees', 'employees'), ('giftcards', 'giftcards'), +('home', 'home'), ('items', 'items'), ('item_kits', 'item_kits'), ('messages', 'messages'), ('migrate', 'migrate'), +('office', 'office'), ('receivings', 'receivings'), ('reports', 'reports'), ('sales', 'sales'), @@ -453,6 +457,7 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VA CREATE TABLE `ospos_grants` ( `permission_id` varchar(255) NOT NULL, `person_id` int(10) NOT NULL, + `menu_group` varchar(32) DEFAULT 'home', PRIMARY KEY (`permission_id`,`person_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -461,34 +466,36 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES -('reports_customers', 1), -('reports_receivings', 1), -('reports_items', 1), -('reports_inventory', 1), -('reports_employees', 1), -('reports_suppliers', 1), -('reports_sales', 1), -('reports_discounts', 1), -('reports_taxes', 1), -('reports_categories', 1), -('reports_payments', 1), -('customers', 1), -('employees', 1), -('giftcards', 1), -('items', 1), -('item_kits', 1), -('messages', 1), -('migrate', 1), -('receivings', 1), -('reports', 1), -('sales', 1), -('config', 1), -('items_stock', 1), -('sales_stock', 1), -('receivings_stock', 1), -('suppliers', 1), -('taxes', 1); +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +('reports_customers', 1, 'home'), +('reports_receivings', 1, 'home'), +('reports_items', 1, 'home'), +('reports_inventory', 1, 'home'), +('reports_employees', 1, 'home'), +('reports_suppliers', 1, 'home'), +('reports_sales', 1, 'home'), +('reports_discounts', 1, 'home'), +('reports_taxes', 1, 'home'), +('reports_categories', 1, 'home'), +('reports_payments', 1, 'home'), +('customers', 1, 'home'), +('employees', 1, 'office'), +('giftcards', 1, 'home'), +('items', 1, 'home'), +('item_kits', 1, 'home'), +('messages', 1, 'home'), +('migrate', 1, 'office'), +('receivings', 1, 'home'), +('reports', 1, 'home'), +('sales', 1, 'home'), +('config', 1, 'office'), +('items_stock', 1, 'home'), +('sales_stock', 1, 'home'), +('receivings_stock', 1, 'home'), +('suppliers', 1, 'home'), +('taxes', 1, 'office'), +('office', 1, 'home'), +('home', 1, 'office'); -- -- Table structure for table `ospos_receivings` diff --git a/database/tables.sql b/database/tables.sql index 1c47f83ec..37a23e993 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -354,10 +354,12 @@ INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_i ('module_customers', 'module_customers_desc', 10, 'customers'), ('module_employees', 'module_employees_desc', 80, 'employees'), ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), +('module_home', 'module_home_desc', 1, 'home'), ('module_items', 'module_items_desc', 20, 'items'), ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'), ('module_messages', 'module_messages_desc', 100, 'messages'), ('module_migrate', 'module_migrate_desc', 120, 'migrate'), +('module_office', 'module_office_desc', 1, 'office'), ('module_receivings', 'module_receivings_desc', 60, 'receivings'), ('module_reports', 'module_reports_desc', 50, 'reports'), ('module_sales', 'module_sales_desc', 70, 'sales'), @@ -428,10 +430,12 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('customers', 'customers'), ('employees', 'employees'), ('giftcards', 'giftcards'), +('home', 'home'), ('items', 'items'), ('item_kits', 'item_kits'), ('messages', 'messages'), ('migrate', 'migrate'), +('office', 'office'), ('receivings', 'receivings'), ('reports', 'reports'), ('sales', 'sales'), @@ -439,6 +443,8 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('suppliers', 'suppliers'), ('taxes', 'taxes'); + + INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VALUES ('items_stock', 'items', 1), ('sales_stock', 'sales', 1), @@ -453,6 +459,7 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VA CREATE TABLE `ospos_grants` ( `permission_id` varchar(255) NOT NULL, `person_id` int(10) NOT NULL, + `menu_group` varchar(32) DEFAULT 'home', PRIMARY KEY (`permission_id`,`person_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -461,34 +468,36 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES -('reports_customers', 1), -('reports_receivings', 1), -('reports_items', 1), -('reports_inventory', 1), -('reports_employees', 1), -('reports_suppliers', 1), -('reports_sales', 1), -('reports_discounts', 1), -('reports_taxes', 1), -('reports_categories', 1), -('reports_payments', 1), -('customers', 1), -('employees', 1), -('giftcards', 1), -('items', 1), -('item_kits', 1), -('messages', 1), -('migrate', 1), -('receivings', 1), -('reports', 1), -('sales', 1), -('config', 1), -('items_stock', 1), -('sales_stock', 1), -('receivings_stock', 1), -('suppliers', 1), -('taxes', 1); +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +('reports_customers', 1, 'home'), +('reports_receivings', 1, 'home'), +('reports_items', 1, 'home'), +('reports_inventory', 1, 'home'), +('reports_employees', 1, 'home'), +('reports_suppliers', 1, 'home'), +('reports_sales', 1, 'home'), +('reports_discounts', 1, 'home'), +('reports_taxes', 1, 'home'), +('reports_categories', 1, 'home'), +('reports_payments', 1, 'home'), +('customers', 1, 'home'), +('employees', 1, 'office'), +('giftcards', 1, 'home'), +('items', 1, 'home'), +('item_kits', 1, 'home'), +('messages', 1, 'home'), +('migrate', 1, 'office'), +('receivings', 1, 'home'), +('reports', 1, 'home'), +('sales', 1, 'home'), +('config', 1, 'office'), +('items_stock', 1, 'home'), +('sales_stock', 1, 'home'), +('receivings_stock', 1, 'home'), +('suppliers', 1, 'home'), +('taxes', 1, 'office'), +('office', 1, 'home'), +('home', 1, 'office'); -- -- Table structure for table `ospos_receivings` diff --git a/public/images/menubar/home.png b/public/images/menubar/home.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc8ddaf6be62a74a7ca479a8c054346b3c7b711 GIT binary patch literal 1099 zcmV-R1ho5!P)SP6G0Tm-|i+&8_`75UW$-dL98N)AmTwV|AECnKyvVI3f`OEJa~u~PlAaz zFOokY1wrV=1P?6;l28xY7;UPx#J0xw(s9|Yn`ARPQ#TpEFysfjv-|zLw==V|vs$Oq z0a;qO`yh%RX)G!BNxzc=c3Z(xW2Ibr{-_KRrHKZBrW5pmCF8=Z8?^`omJ-4!_!a;f zrwC`U+?E(Hf>FYfLl`w*0AR**SZ=}bswe^kHvpFEg@0h&u4OEF1hI8&0MLAvMLh!k zP@PT-AylLSV6A$|2T|{(MTC%-0szgYnE5#PTSbJB5ek5rFZ(Fv2dPTq4ma(BK8EIj zjX%ollH~_5qUMi4;09o6@J7+R2?2c+xY_{RvCP}rUx~Hh&fE^12^|P=@uh9R%l9YX zZ8IdicW?xN=BbZg;x&J7ep^a7pRS$q0^zFDI6?1m-7oPTg(5FY9_uc+Z3FVWN0-O}&q(M#5Wsp!A04YTP5~>48st!P9MSTxo=K4HD=i{Im zhK%YH0oeu`t7}7VM}~tZ!{%@L9=UK9w$|#xdjel(fYrS9KO+zi=xasXn{DbxJ=>N}W=O^H6edccnv5HNIjUH#Dge!6uydljCL z(hJn21K^nvx_E9HHa>2{&hAh6iU7#`Y;;n_>1`2!s^3O~x~@TdHsT0MuqxCD))XEI zb^(Rb1q z)#4+(Uf9)&@qx3#?Al4QK6I?iyUGAtCXC$+6Rw{NuuMqt_72CS#bL}3l>xSF7@L=- zxSkBLZpAOzK!dgvk9qD4uw_FURD5x=2MG0Eopk__02N=J?g7L1uh0J$U;qwpr*H0y Rxf=ig002ovPDHLkV1oVA^qK$w literal 0 HcmV?d00001 diff --git a/public/images/menubar/office.png b/public/images/menubar/office.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc8ddaf6be62a74a7ca479a8c054346b3c7b711 GIT binary patch literal 1099 zcmV-R1ho5!P)SP6G0Tm-|i+&8_`75UW$-dL98N)AmTwV|AECnKyvVI3f`OEJa~u~PlAaz zFOokY1wrV=1P?6;l28xY7;UPx#J0xw(s9|Yn`ARPQ#TpEFysfjv-|zLw==V|vs$Oq z0a;qO`yh%RX)G!BNxzc=c3Z(xW2Ibr{-_KRrHKZBrW5pmCF8=Z8?^`omJ-4!_!a;f zrwC`U+?E(Hf>FYfLl`w*0AR**SZ=}bswe^kHvpFEg@0h&u4OEF1hI8&0MLAvMLh!k zP@PT-AylLSV6A$|2T|{(MTC%-0szgYnE5#PTSbJB5ek5rFZ(Fv2dPTq4ma(BK8EIj zjX%ollH~_5qUMi4;09o6@J7+R2?2c+xY_{RvCP}rUx~Hh&fE^12^|P=@uh9R%l9YX zZ8IdicW?xN=BbZg;x&J7ep^a7pRS$q0^zFDI6?1m-7oPTg(5FY9_uc+Z3FVWN0-O}&q(M#5Wsp!A04YTP5~>48st!P9MSTxo=K4HD=i{Im zhK%YH0oeu`t7}7VM}~tZ!{%@L9=UK9w$|#xdjel(fYrS9KO+zi=xasXn{DbxJ=>N}W=O^H6edccnv5HNIjUH#Dge!6uydljCL z(hJn21K^nvx_E9HHa>2{&hAh6iU7#`Y;;n_>1`2!s^3O~x~@TdHsT0MuqxCD))XEI zb^(Rb1q z)#4+(Uf9)&@qx3#?Al4QK6I?iyUGAtCXC$+6Rw{NuuMqt_72CS#bL}3l>xSF7@L=- zxSkBLZpAOzK!dgvk9qD4uw_FURD5x=2MG0Eopk__02N=J?g7L1uh0J$U;qwpr*H0y Rxf=ig002ovPDHLkV1oVA^qK$w literal 0 HcmV?d00001 From d5c390706b75c97b0c696058130c7bf6bcfcf468 Mon Sep 17 00:00:00 2001 From: FrancescoUK Date: Sun, 3 Sep 2017 13:38:27 +0100 Subject: [PATCH 02/12] Bump version to 3.2.0 --- application/config/config.php | 2 +- bower.json | 2 +- deployment.json | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/config/config.php b/application/config/config.php index 32cfc75d9..94a0b5aa5 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -8,7 +8,7 @@ | | */ -$config['application_version'] = '3.1.1'; +$config['application_version'] = '3.2.0'; /* |-------------------------------------------------------------------------- diff --git a/bower.json b/bower.json index d96839b54..ee7a94a98 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "opensourcepos", "description": "Open Source Point of Sale is a web based POS system written in the PHP language. It uses MySQL as backend and has a simple user interface", - "version": "3.1.1", + "version": "3.2.0", "license": "MIT", "authors": [ "jekkos ", diff --git a/deployment.json b/deployment.json index 18cf5dad6..500ad016d 100644 --- a/deployment.json +++ b/deployment.json @@ -14,7 +14,7 @@ "public_stats": true }, "version": { - "name": "3.1.1" + "name": "3.2.0" }, "files": [ diff --git a/package.json b/package.json index 284ec41aa..14781246f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opensourcepos", - "version": "3.1.1", + "version": "3.2.0", "description": "Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.", "main": "index.php", "license": "MIT", From 23b4dacb9a2320fdd7234fcb59d89342ffb5b1dd Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sun, 3 Sep 2017 20:14:50 -0400 Subject: [PATCH 03/12] Fix database and table script. --- database/database.sql | 2 +- database/tables.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/database.sql b/database/database.sql index 02b0de8a3..a04f1e56f 100644 --- a/database/database.sql +++ b/database/database.sql @@ -466,7 +466,7 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES ('reports_customers', 1, 'home'), ('reports_receivings', 1, 'home'), ('reports_items', 1, 'home'), diff --git a/database/tables.sql b/database/tables.sql index 37a23e993..a7fffb2a4 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -468,7 +468,7 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES ('reports_customers', 1, 'home'), ('reports_receivings', 1, 'home'), ('reports_items', 1, 'home'), From 981aceda53f38513f707db8082f6c34e65036f11 Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sat, 2 Sep 2017 13:31:33 -0400 Subject: [PATCH 04/12] Add support for Work Orders --- application/controllers/Config.php | 5 +- application/controllers/Sales.php | 301 ++++++++++++------ application/language/en-US/config_lang.php | 3 + application/language/en-US/sales_lang.php | 13 +- application/libraries/Sale_lib.php | 80 ++++- application/libraries/tokens/Token.php | 4 +- .../tokens/Token_work_order_sequence.php | 19 ++ application/models/Appconfig.php | 7 + application/models/Sale.php | 158 +++++++-- application/views/configs/invoice_config.php | 124 +++++--- application/views/sales/quote.php | 2 +- application/views/sales/register.php | 28 +- application/views/sales/suspended.php | 6 +- application/views/sales/work_order.php | 213 +++++++++++++ application/views/sales/work_order_email.php | 128 ++++++++ database/3.1.0_work_orders.sql | 22 ++ database/database.sql | 9 +- database/tables.sql | 8 +- 18 files changed, 943 insertions(+), 187 deletions(-) create mode 100644 application/libraries/tokens/Token_work_order_sequence.php create mode 100644 application/views/sales/work_order.php create mode 100644 application/views/sales/work_order_email.php create mode 100644 database/3.1.0_work_orders.sql diff --git a/application/controllers/Config.php b/application/controllers/Config.php index fce888253..dc0bc8b17 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -844,7 +844,10 @@ class Config extends Secure_Controller '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_quote_number' =>$this->input->post('last_used_quote_number'), + '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') ); $result = $this->Appconfig->batch_save($batch_save_data); diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index 46cabc6d5..98f5ab48c 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -147,13 +147,36 @@ class Sales extends Secure_Controller public function change_mode() { + $mode = $this->input->post('mode'); + $this->sale_lib->set_mode($mode); + + if($mode == 'sale') + { + $this->sale_lib->set_sale_type(SALE_TYPE_POS); + } + else if($mode == 'sale_quote') + { + $this->sale_lib->set_sale_type(SALE_TYPE_QUOTE); + } + else if($mode == 'sale_work_order') + { + $this->sale_lib->set_sale_type(SALE_TYPE_WORK_ORDER); + } + else if($mode == 'sale_invoice') + { + $this->sale_lib->set_sale_type(SALE_TYPE_INVOICE); + } + else + { + $this->sale_lib->set_sale_type(SALE_SALE); + } + $stock_location = $this->input->post('stock_location'); if(!$stock_location || $stock_location == $this->sale_lib->get_sale_location()) { - $mode = $this->input->post('mode'); - $this->sale_lib->set_mode($mode); $dinner_table = $this->input->post('dinner_table'); $this->sale_lib->set_dinner_table($dinner_table); + } elseif($this->Stock_location->is_allowed_location($stock_location, 'sales')) { @@ -163,6 +186,30 @@ class Sales extends Secure_Controller $this->_reload(); } + public function change_register_mode($sale_type) + { + if($sale_type == SALE_TYPE_POS) + { + $this->sale_lib->set_mode('sale'); + } + elseif($sale_type == SALE_TYPE_QUOTE) + { + $this->sale_lib->set_mode('sale_quote'); + } + elseif($sale_type == SALE_TYPE_WORK_ORDER) + { + $this->sale_lib->set_mode('sale_work_order'); + } + elseif($sale_type == SALE_TYPE_INVOICE) + { + $this->sale_lib->set_mode('sale_invoice'); + } + else + { + $this->sale_lib->set_mode('sale'); + } + } + public function set_comment() { $this->sale_lib->set_comment($this->input->post('comment')); @@ -189,6 +236,11 @@ class Sales extends Secure_Controller $this->sale_lib->set_print_after_sale($this->input->post('sales_print_after_sale')); } + public function set_price_work_orders() + { + $this->sale_lib->set_price_work_orders($this->input->post('price_work_orders')); + } + public function set_email_receipt() { $this->sale_lib->set_email_receipt($this->input->post('email_receipt')); @@ -443,6 +495,8 @@ class Sales extends Secure_Controller public function complete() { + $sale_id = $this->sale_lib->get_sale_id(); + $sale_type = $this->sale_lib->get_sale_type(); $data = array(); $data['dinner_table'] = $this->sale_lib->get_dinner_table(); $data['cart'] = $this->sale_lib->get_cart(); @@ -463,10 +517,15 @@ class Sales extends Secure_Controller $data['cur_giftcard_value'] = $this->sale_lib->get_giftcard_remainder(); $data['cur_rewards_value'] = $this->sale_lib->get_rewards_remainder(); $data['print_after_sale'] = $this->sale_lib->is_print_after_sale(); + $data['price_work_orders'] = $this->sale_lib->is_price_work_orders(); $data['email_receipt'] = $this->sale_lib->get_email_receipt(); $customer_id = $this->sale_lib->get_customer(); - $data["invoice_number"] = $this->sale_lib->get_invoice_number(); - $data["quote_number"] = $this->sale_lib->get_quote_number(); + $invoice_number = $this->sale_lib->get_invoice_number(); + $data["invoice_number"] = $invoice_number; + $work_order_number = $this->sale_lib->get_work_order_number(); + $data["work_order_number"] = $work_order_number; + $quote_number = $this->sale_lib->get_quote_number(); + $data["quote_number"] = $quote_number; $customer_info = $this->_load_customer_data($customer_id, $data); if($customer_info != NULL) { @@ -501,13 +560,26 @@ class Sales extends Secure_Controller } $data['amount_change'] = $data['amount_due'] * -1; - if($this->sale_lib->is_invoice_mode() || $data['invoice_number_enabled'] == TRUE) + $data['print_price_info'] = TRUE; + + if($this->sale_lib->is_sale_by_receipt_mode() && $this->input->post('sales_invoice_enable') == '1' ) + { + $pos_invoice = TRUE; + } + else + { + $pos_invoice = FALSE; + } + + if($this->sale_lib->is_invoice_mode() || $pos_invoice) { // generate final invoice number (if using the invoice in sales by receipt mode then the invoice number can be manually entered or altered in some way - if($this->sale_lib->is_sale_by_receipt_mode()) + if($pos_invoice) { + // The user can retain the default encoded format or can manually override it. It still passes through the rendering step. $this->sale_lib->set_invoice_number($this->input->post('invoice_number'), $keep_custom = TRUE); $invoice_format = $this->sale_lib->get_invoice_number(); + // If the user blanks out the invoice number and doesn't put anything in there then revert back to the default format encoding if(empty($invoice_format)) { $invoice_format = $this->config->item('sales_invoice_format'); @@ -517,10 +589,11 @@ class Sales extends Secure_Controller { $invoice_format = $this->config->item('sales_invoice_format'); } - $invoice_number = $this->token_lib->render($invoice_format); - // TODO If duplicate invoice then determine the number of employees and repeat until until success or tried the number of employees (if QSEQ was used). - if($this->Sale->check_invoice_number_exists($invoice_number)) + $invoice_number = $this->token_lib->render($invoice_format); + $data['invoice_number'] = $invoice_number; + + if($sale_id == -1 && $this->Sale->check_invoice_number_exists($invoice_number)) { $data['error'] = $this->lang->line('sales_invoice_number_duplicate'); $this->_reload($data); @@ -529,9 +602,10 @@ class Sales extends Secure_Controller { $data['invoice_number'] = $invoice_number; $data['sale_status'] = COMPLETED; + $sale_type = SALE_TYPE_INVOICE; // Save the data to the sales table - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $data["quote_number"], $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'], $data['taxes']); $data['sale_id'] = 'POS ' . $data['sale_id_num']; // Resort and filter cart lines for printing @@ -551,10 +625,53 @@ class Sales extends Secure_Controller } } } + elseif($this->sale_lib->is_work_order_mode()) + { + + if(!($data['price_work_orders'] == 1)) + { + $data['print_price_info'] = FALSE; + } + + $data['sales_work_order'] = $this->lang->line('sales_work_order'); + $data['work_order_number_label'] = $this->lang->line('sales_work_order_number'); + + if($work_order_number == NULL) + { + // generate work order number + $work_order_format = $this->config->item('work_order_format'); + $work_order_number = $this->token_lib->render($work_order_format); + } + + if($sale_id == -1 && $this->Sale->check_work_order_number_exists($work_order_number)) + { + $data['error'] = $this->lang->line('sales_work_order_number_duplicate'); + $this->_reload($data); + } + else + { + $data['work_order_number'] = $work_order_number; + $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']); + $this->sale_lib->set_suspended_id($data['sale_id_num']); + + $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); + + $data = $this->xss_clean($data); + + $data['barcode'] = NULL; + + $this->load->view('sales/work_order', $data); + $this->sale_lib->clear_mode(); + $this->sale_lib->clear_all(); + } + } elseif($this->sale_lib->is_quote_mode()) { - $invoice_number = NULL; - $quote_number = $this->sale_lib->get_quote_number(); + $data['sales_quote'] = $this->lang->line('sales_quote'); + $data['quote_number_label'] = $this->lang->line('sales_quote_number'); if($quote_number == NULL) { @@ -563,19 +680,18 @@ class Sales extends Secure_Controller $quote_number = $this->token_lib->render($quote_format); } - // TODO If duplicate quote then determine the number of employees and repeat until until success or tried the number of employees (if QSEQ was used). - if($this->Sale->check_quote_number_exists($quote_number)) + if($sale_id == -1 && $this->Sale->check_quote_number_exists($quote_number)) { $data['error'] = $this->lang->line('sales_quote_number_duplicate'); $this->_reload($data); } else { - $data['invoice_number'] = $invoice_number; $data['quote_number'] = $quote_number; $data['sale_status'] = SUSPENDED; + $sale_type = SALE_TYPE_QUOTE; - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $quote_number, $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'], $data['taxes']); $this->sale_lib->set_suspended_id($data['sale_id_num']); $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); @@ -592,8 +708,10 @@ class Sales extends Secure_Controller else { // Save the data to the sales table - $data['sale_status'] = '0'; // Complete - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], NULL, NULL, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_status'] = COMPLETED; + $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'] = 'POS ' . $data['sale_id_num']; @@ -801,6 +919,8 @@ class Sales extends Secure_Controller )); $data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']); $data['print_after_sale'] = FALSE; + $data['price_work_orders'] = FALSE; + if($this->sale_lib->get_mode() == 'sale_invoice') { $data['mode_label'] = $this->lang->line('sales_invoice'); @@ -809,29 +929,26 @@ class Sales extends Secure_Controller { $data['mode_label'] = $this->lang->line('sales_quote'); } + elseif($this->sale_lib->get_mode() == 'sale_work_order') + { + $data['mode_label'] = $this->lang->line('sales_work_order'); + } return $this->xss_clean($data); } private function _reload($data = array()) { + $sale_id = $this->session->userdata('sale_id'); + if($sale_id == '') + { + $sale_id = -1; + $this->session->set_userdata('sale_id', -1); + } $data['cart'] = $this->sale_lib->get_cart(); $customer_info = $this->_load_customer_data($this->sale_lib->get_customer(), $data, TRUE); - if($this->config->item('invoice_enable') == '0') - { - $data['modes'] = array( - 'sale' => $this->lang->line('sales_sale'), - 'return' => $this->lang->line('sales_return')); - } - else - { - $data['modes'] = array( - 'sale' => $this->lang->line('sales_sale'), - 'sale_invoice' => $this->lang->line('sales_sale_by_invoice'), - 'sale_quote' => $this->lang->line('sales_quote'), - 'return' => $this->lang->line('sales_return')); - } + $data['modes'] = $this->sale_lib->get_register_mode_options(); $data['mode'] = $this->sale_lib->get_mode(); $data['empty_tables'] = $this->sale_lib->get_empty_tables(); $data['selected_table'] = $this->sale_lib->get_dinner_table(); @@ -841,6 +958,8 @@ class Sales extends Secure_Controller $data['taxes'] = $this->sale_lib->get_taxes(); $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(); @@ -878,11 +997,6 @@ class Sales extends Secure_Controller { $data['payment_options'] = $this->Sale->get_payment_options(); } - $quote_number = $this->sale_lib->get_quote_number(); - if($quote_number != NULL) - { - $data['quote_number'] = $quote_number; - } $data['items_module_allowed'] = $this->Employee->has_grant('items', $this->Employee->get_logged_in_employee_info()->person_id); @@ -894,8 +1008,13 @@ class Sales extends Secure_Controller $data['invoice_number_enabled'] = $this->sale_lib->is_invoice_mode(); $data['print_after_sale'] = $this->sale_lib->is_print_after_sale(); - $data['quote_or_invoice_mode'] = $data['mode'] == 'sale_invoice' || $data['mode'] == 'sale_quote'; - $data['sales_or_return_mode'] = $data['mode'] == 'sale' || $data['mode'] == 'return'; + $data['price_work_orders'] = $this->sale_lib->is_price_work_orders(); + + $data['pos_mode'] = $data['mode'] == 'sale' || $data['mode'] == 'return'; + + $data['quote_number'] = $this->sale_lib->get_quote_number(); + $data['work_order_number'] = $this->sale_lib->get_work_order_number(); + if($this->sale_lib->get_mode() == 'sale_invoice') { $data['mode_label'] = $this->lang->line('sales_invoice'); @@ -904,6 +1023,10 @@ class Sales extends Secure_Controller { $data['mode_label'] = $this->lang->line('sales_quote'); } + elseif($this->sale_lib->get_mode() == 'sale_work_order') + { + $data['mode_label'] = $this->lang->line('sales_work_order'); + } else { $data['mode_label'] = $this->lang->line('sales_receipt'); @@ -978,70 +1101,33 @@ class Sales extends Secure_Controller } } - public function save($sale_id = -1) + /** + * This is used to cancel a suspended pos sale, quote. + * Completed sales (POS Sales or Invoiced Sales) can not be removed from the system + * Work orders can be canceled but are not physically removed from the sales history + */ + public function cancel() { - $newdate = $this->input->post('date'); - $date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $newdate); - $sale_data = array( - 'sale_time' => $date_formatter->format('Y-m-d H:i:s'), - 'customer_id' => $this->input->post('customer_id') != '' ? $this->input->post('customer_id') : NULL, - 'employee_id' => $this->input->post('employee_id'), - 'comment' => $this->input->post('comment'), - 'invoice_number' => $this->input->post('invoice_number') != '' ? $this->input->post('invoice_number') : NULL - ); - - // go through all the payment type input from the form, make sure the form matches the name and iterator number - $payments = array(); - $number_of_payments = $this->input->post('number_of_payments'); - for($i = 0; $i < $number_of_payments; ++$i) + $sale_id = $this->sale_lib->get_sale_id(); + if($sale_id != -1 && $sale_id != '') { - $payment_amount = $this->input->post('payment_amount_' . $i); - $payment_type = $this->input->post('payment_type_' . $i); - // remove any 0 payment if by mistake any was introduced at sale time - if($payment_amount != 0) + $sale_type = $this->sale_lib->get_sale_type(); + if($sale_type == SALE_TYPE_WORK_ORDER) { - // search for any payment of the same type that was already added, if that's the case add up the new payment amount - $key = FALSE; - if(!empty($payments)) - { - // search in the multi array the key of the entry containing the current payment_type - // NOTE: in PHP5.5 the array_map could be replaced by an array_column - $key = array_search($payment_type, array_map(function ($v) - { - return $v['payment_type']; - }, $payments)); - } - - // if no previous payment is found add a new one - if($key === FALSE) - { - $payments[] = array('payment_type' => $payment_type, 'payment_amount' => $payment_amount); - } - else - { - // add up the new payment amount to an existing payment type - $payments[$key]['payment_amount'] += $payment_amount; - } + $this->Sale->update_sale_status($sale_id, CANCELED); + } + else + { + $this->Sale->delete($sale_id, FALSE); + $this->session->set_userdata('sale_id', -1); } } - if($this->Sale->update($sale_id, $sale_data, $payments)) - { - echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('sales_successfully_updated'), 'id' => $sale_id)); - } - else - { - echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('sales_unsuccessfully_updated'), 'id' => $sale_id)); - } - } - - public function cancel() - { $this->sale_lib->clear_all(); $this->_reload(); } - public function discard_quote() + public function discard_suspended_sale() { $suspended_id = $this->sale_lib->get_suspended_id(); $this->sale_lib->clear_all(); @@ -1049,8 +1135,15 @@ class Sales extends Secure_Controller $this->_reload(); } + /** + * Suspend the current sale. + * If the current sale is already suspended then update the existing suspended sale. + * Otherwise create it as a new suspended sale + */ public function suspend() { + $mode = $this->sale_lib->get_mode(); + $sale_id = $this->sale_lib->get_sale_id(); $dinner_table = $this->sale_lib->get_dinner_table(); $cart = $this->sale_lib->get_cart(); $payments = $this->sale_lib->get_payments(); @@ -1058,13 +1151,20 @@ class Sales extends Secure_Controller $customer_id = $this->sale_lib->get_customer(); $customer_info = $this->Customer->get_info($customer_id); $invoice_number = $this->sale_lib->get_invoice_number(); + $work_order_number = $this->sale_lib->get_work_order_number(); $quote_number = $this->sale_lib->get_quote_number(); + $sale_id = $this->sale_lib->get_sale_id(); + $sale_type = $this->sale_lib->get_sale_type(); + if($sale_type == '') + { + $sale_type = SALE_TYPE_POS; + } $comment = $this->sale_lib->get_comment(); - $sale_status = $this->sale_lib->is_quote_mode() ? QUOTE : SUSPENDED; + $sale_status = SUSPENDED; $data = array(); $sales_taxes = array(); - if($this->Sale->save($sale_status, $cart, $customer_id, $employee_id, $comment, $invoice_number, $quote_number, $payments, $dinner_table, $sales_taxes) == '-1') + 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'); } @@ -1077,6 +1177,9 @@ class Sales extends Secure_Controller $this->_reload($data); } + /** + * List suspended sales + */ public function suspended() { $customer_id = $this->sale_lib->get_customer(); @@ -1087,8 +1190,8 @@ class Sales extends Secure_Controller } /* - * We will eventually drop the current set of "suspended" tables since suspended sales - * are now stored in the sales tables with a sale_status value of suspended. + * Unsuspended sales are now left in the tables and are only removed + * when they are intentionally cancelled. */ public function unsuspend() { @@ -1098,9 +1201,11 @@ class Sales extends Secure_Controller if($sale_id > 0) { $this->sale_lib->copy_entire_sale($sale_id); - $this->Sale->delete_suspended_sale($sale_id); } + // Set current register mode to reflect that of unsuspended order type + $this->change_register_mode($this->sale_lib->get_sale_type()); + $this->_reload(); } diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index 3b028986c..7ad7bcbf8 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -142,6 +142,7 @@ $lang["config_jsprintsetup_required"] = "Warning: This functionality will only w $lang["config_language"] = "Language"; $lang["config_last_used_invoice_number"] = "Last used Invoice Number"; $lang["config_last_used_quote_number"] = "Last used Quote Number"; +$lang["config_last_used_work_order_number"] = "Last Used W/O Number"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; @@ -222,6 +223,7 @@ $lang["config_reward"] = "Reward"; $lang["config_reward_configuration"] = "Reward Configuration"; $lang["config_right"] = "Right"; $lang["config_sales_invoice_format"] = "Sales Invoice Format"; +$lang["config_work_order_format"] = "Work Order Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration save successful."; $lang["config_saved_unsuccessfully"] = "Configuration save failed."; @@ -246,3 +248,4 @@ $lang["config_thousands_separator"] = "Thousands Separator"; $lang["config_timezone"] = "Timezone"; $lang["config_top"] = "Top"; $lang["config_website"] = "Website"; +$lang["config_work_order_enable"] = "Work Order Support"; diff --git a/application/language/en-US/sales_lang.php b/application/language/en-US/sales_lang.php index dbb022d4e..2efbe6066 100644 --- a/application/language/en-US/sales_lang.php +++ b/application/language/en-US/sales_lang.php @@ -8,6 +8,7 @@ $lang["sales_amount_due"] = "Amount Due"; $lang["sales_amount_tendered"] = "Amount Tendered"; $lang["sales_cancel_sale"] = "Cancel"; $lang["sales_cash"] = "Cash"; +$lang["sales_cash_deposit"] = "Cash Deposit"; $lang["sales_cash_filter"] = "Cash"; $lang["sales_change_due"] = "Change Due"; $lang["sales_check"] = "Check"; @@ -19,6 +20,7 @@ $lang["sales_complete_sale"] = "Complete"; $lang["sales_confirm_cancel_sale"] = "Are you sure you want to clear this sale? All items will cleared."; $lang["sales_confirm_delete"] = "Are you sure you want to delete the selected Sale(s)?"; $lang["sales_credit"] = "Credit Card"; +$lang["sales_credit_deposit"] = "Credit Deposit"; $lang["sales_customer"] = "Name"; $lang["sales_customer_address"] = "Address"; $lang["sales_customer_discount"] = "Discount"; @@ -36,7 +38,7 @@ $lang["sales_delete_entire_sale"] = "Delete Entire Sale"; $lang["sales_delete_successful"] = "Sale delete successful."; $lang["sales_delete_unsuccessful"] = "Sale delete failed."; $lang["sales_description_abbrv"] = "Desc."; -$lang["sales_discard_quote"] = "Discard"; +$lang["sales_discard"] = "Discard"; $lang["sales_discount"] = "Disc %"; $lang["sales_discount_included"] = "% Discount"; $lang["sales_discount_short"] = "%"; @@ -57,6 +59,7 @@ $lang["sales_giftcard_number"] = "Gift Card Number"; $lang["sales_group_by_category"] = "Group by Category"; $lang["sales_group_by_type"] = "Group by Type"; $lang["sales_id"] = "Sale ID"; +$lang["sales_include_prices"] = "Include Prices?"; $lang["sales_invoice"] = "Invoice"; $lang["sales_invoice_confirm"] = "This invoice will be sent to"; $lang["sales_invoice_enable"] = "Create Invoice"; @@ -94,6 +97,7 @@ $lang["sales_quantity_less_than_reorder_level"] = "Warning: Desired Quantity is $lang["sales_quantity_less_than_zero"] = "Warning: Desired Quantity is insufficient. You can still process the sale, but audit your inventory."; $lang["sales_quote"] = "Quote"; $lang["sales_quote_number"] = "Quote Number"; +$lang["sales_quote_number_duplicate"] = "Quote Number must be unique."; $lang["sales_quote_sent"] = "Quote sent to"; $lang["sales_quote_unsent"] = "Quote failed to be sent to"; $lang["sales_receipt"] = "Sales Receipt"; @@ -114,6 +118,7 @@ $lang["sales_select_customer"] = "Select Customer (Optional)"; $lang["sales_send_invoice"] = "Send Invoice"; $lang["sales_send_quote"] = "Send Quote"; $lang["sales_send_receipt"] = "Send Receipt"; +$lang["sales_send_work_order"] = "Send Work Order"; $lang["sales_serial"] = "Serial"; $lang["sales_show_invoice"] = "Show Invoice"; $lang["sales_show_receipt"] = "Show Receipt"; @@ -125,6 +130,7 @@ $lang["sales_successfully_deleted"] = "You have successfully deleted"; $lang["sales_successfully_suspended_sale"] = "Sale suspend successful."; $lang["sales_successfully_updated"] = "Sale update successful."; $lang["sales_suspend_sale"] = "Suspend"; +$lang["sales_suspended_doc_id"] = "Document"; $lang["sales_suspended_sale_id"] = "ID"; $lang["sales_suspended_sales"] = "Suspended"; $lang["sales_table"] = "Table"; @@ -141,3 +147,8 @@ $lang["sales_unsuccessfully_updated"] = "Sale update failed."; $lang["sales_unsuspend"] = "Unsuspend"; $lang["sales_unsuspend_and_delete"] = "Action"; $lang["sales_update"] = "Update"; +$lang["sales_work_order"] = "Work Order"; +$lang["sales_work_order_number"] = "Work Order Number"; +$lang["sales_work_order_number_duplicate"] = "The Work Order Number is a duplicate"; +$lang["sales_work_order_sent"] = "Work Order sent to"; +$lang["sales_work_order_unsent"] = "Work Order failed to be sent to"; diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php index 4166f9057..bd58aae77 100644 --- a/application/libraries/Sale_lib.php +++ b/application/libraries/Sale_lib.php @@ -28,11 +28,23 @@ class Sale_lib public function get_register_mode_options() { - return array( - 'sale' => $this->CI->lang->line('sales_receipt'), - 'sale_invoice' => $this->CI->lang->line('sales_invoice'), - 'sale_quote' => $this->CI->lang->line('sales_quote') - ); + $register_modes = array(); + if($this->CI->config->item('invoice_enable') == '0') + { + $register_modes['sale'] = $this->CI->lang->line('sales_sale'); + } + else + { + $register_modes['sale'] = $this->CI->lang->line('sales_receipt'); + $register_modes['sale_quote'] = $this->CI->lang->line('sales_quote'); + if($this->CI->config->item('work_order_enable') == '1') + { + $register_modes['sale_work_order'] = $this->CI->lang->line('sales_work_order'); + } + $register_modes['sale_invoice'] = $this->CI->lang->line('sales_invoice'); + } + $register_modes['return'] = $this->CI->lang->line('sales_return'); + return $register_modes; } public function get_cart() @@ -148,6 +160,16 @@ class Sale_lib return $this->CI->session->userdata('sales_quote_number'); } + public function get_work_order_number() + { + return $this->CI->session->userdata('sales_work_order_number'); + } + + public function get_sale_type() + { + return $this->CI->session->userdata('sale_type'); + } + public function set_invoice_number($invoice_number, $keep_custom = FALSE) { $current_invoice_number = $this->CI->session->userdata('sales_invoice_number'); @@ -166,6 +188,24 @@ class Sale_lib } } + public function set_work_order_number($work_order_number, $keep_custom = FALSE) + { + $current_work_order_number = $this->CI->session->userdata('sales_work_order_number'); + if(!$keep_custom || empty($current_work_order_number)) + { + $this->CI->session->set_userdata('sales_work_order_number', $work_order_number); + } + } + + public function set_sale_type($sale_type, $keep_custom = FALSE) + { + $current_sale_type = $this->CI->session->userdata('sale_type'); + if(!$keep_custom || empty($current_sale_type)) + { + $this->CI->session->set_userdata('sale_type', $sale_type); + } + } + public function clear_invoice_number() { $this->CI->session->unset_userdata('sales_invoice_number'); @@ -176,6 +216,11 @@ class Sale_lib $this->CI->session->unset_userdata('sales_quote_number'); } + public function clear_sale_type() + { + $this->CI->session->unset_userdata('sale_type'); + } + public function set_suspended_id($suspended_id) { $this->CI->session->set_userdata('suspended_id', $suspended_id); @@ -204,6 +249,11 @@ class Sale_lib return ($this->CI->session->userdata('sales_mode') == 'sale_quote'); } + public function is_work_order_mode() + { + return ($this->CI->session->userdata('sales_mode') == 'sale_work_order'); + } + public function set_invoice_number_enabled($invoice_number_enabled) { return $this->CI->session->set_userdata('sales_invoice_number_enabled', $invoice_number_enabled); @@ -215,11 +265,22 @@ class Sale_lib $this->CI->session->userdata('sales_print_after_sale') == '1'); } + public function is_price_work_orders() + { + return ($this->CI->session->userdata('sales_price_work_orders') == 'true' || + $this->CI->session->userdata('sales_price_work_orders') == '1'); + } + public function set_print_after_sale($print_after_sale) { return $this->CI->session->set_userdata('sales_print_after_sale', $print_after_sale); } + public function set_price_work_orders($price_work_orders) + { + return $this->CI->session->set_userdata('sales_price_work_orders', $price_work_orders); + } + public function get_email_receipt() { return $this->CI->session->userdata('sales_email_receipt'); @@ -380,7 +441,6 @@ class Sale_lib { $cash_total = $total; $totals['cash_total'] = $cash_total; - } $payment_total = $this->get_payments_total(); @@ -862,8 +922,14 @@ class Sale_lib $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); $this->set_employee($this->CI->Sale->get_employee($sale_id)->person_id); $this->set_quote_number($this->CI->Sale->get_quote_number($sale_id)); + $this->set_sale_type($this->CI->Sale->get_sale_type($sale_id)); $this->set_comment($this->CI->Sale->get_comment($sale_id)); $this->set_dinner_table($this->CI->Sale->get_dinner_table($sale_id)); + $this->CI->session->set_userdata('sale_id', $sale_id); + } + + public function get_sale_id() { + return $this->CI->session->userdata('sale_id'); } public function get_cart_reordered($sale_id) @@ -880,6 +946,7 @@ class Sale_lib public function clear_all() { + $this->CI->session->set_userdata('sale_id', -1); $this->set_invoice_number_enabled(FALSE); $this->clear_table(); $this->empty_cart(); @@ -887,6 +954,7 @@ class Sale_lib $this->clear_email_receipt(); $this->clear_invoice_number(); $this->clear_quote_number(); + $this->clear_sale_type(); $this->clear_giftcard_remainder(); $this->empty_payments(); $this->remove_customer(); diff --git a/application/libraries/tokens/Token.php b/application/libraries/tokens/Token.php index 06697e712..2d4874409 100644 --- a/application/libraries/tokens/Token.php +++ b/application/libraries/tokens/Token.php @@ -5,6 +5,7 @@ require_once(APPPATH . 'libraries/tokens/Token_customer.php'); require_once(APPPATH . 'libraries/tokens/Token_invoice_count.php'); require_once(APPPATH . 'libraries/tokens/Token_invoice_sequence.php'); require_once(APPPATH . 'libraries/tokens/Token_quote_sequence.php'); +require_once(APPPATH . 'libraries/tokens/Token_work_order_sequence.php'); require_once(APPPATH . 'libraries/tokens/Token_suspended_invoice_count.php'); require_once(APPPATH . 'libraries/tokens/Token_year_invoice_count.php'); @@ -27,7 +28,8 @@ abstract class Token static function get_tokens() { return array(new Token_customer(), new Token_invoice_count(), new Token_invoice_sequence(), - new Token_quote_sequence(), new Token_suspended_invoice_count(), new Token_quote_sequence(), new Token_year_invoice_count()); + new Token_quote_sequence(), new Token_suspended_invoice_count(), new Token_quote_sequence(), + new Token_work_order_sequence(), new Token_year_invoice_count()); } abstract public function token_id(); diff --git a/application/libraries/tokens/Token_work_order_sequence.php b/application/libraries/tokens/Token_work_order_sequence.php new file mode 100644 index 000000000..9405902bf --- /dev/null +++ b/application/libraries/tokens/Token_work_order_sequence.php @@ -0,0 +1,19 @@ +CI->Appconfig->acquire_save_next_work_order_sequence(); + } +} +?> diff --git a/application/models/Appconfig.php b/application/models/Appconfig.php index 58d01604d..09cfef6ef 100644 --- a/application/models/Appconfig.php +++ b/application/models/Appconfig.php @@ -93,5 +93,12 @@ class Appconfig extends CI_Model $this->save('last_used_quote_number', $last_used); return $last_used; } + + public function acquire_save_next_work_order_sequence() + { + $last_used = $this->get('last_used_work_order_number') + 1; + $this->save('last_used_work_order_number', $last_used); + return $last_used; + } } ?> diff --git a/application/models/Sale.php b/application/models/Sale.php index 52378f889..39d3ee513 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -2,7 +2,13 @@ define('COMPLETED', 0); define('SUSPENDED', 1); -define('QUOTE', 2); +define('CANCELED', 2); + +define('SALE_TYPE_POS', 0); +define('SALE_TYPE_INVOICE', 1); +define('SALE_TYPE_WORK_ORDER', 2); +define('SALE_TYPE_QUOTE', 3); +define('SALE_TYPE_RETURN', 4); /** * Sale class @@ -537,8 +543,15 @@ 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_status, &$items, $customer_id, $employee_id, $comment, $invoice_number, $quote_number, $payments, $dinner_table, &$sales_taxes, $sale_id = FALSE) + 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) { + + error_log('>>>save sale_id-' . $sale_id . ', sale_type-' . $sale_type); + if($sale_id != -1) + { + $this->clear_suspended_sale_detail($sale_id); + } + $tax_decimals = tax_decimals(); if(count($items) == 0) @@ -549,22 +562,34 @@ class Sale extends CI_Model $table_status = $this->determine_sale_status($sale_status, $dinner_table); $sales_data = array( - 'sale_time' => date('Y-m-d H:i:s'), - 'customer_id' => $this->Customer->exists($customer_id) ? $customer_id : null, - 'employee_id' => $employee_id, - 'comment' => $comment, - 'sale_status' => $sale_status, - 'invoice_number' => $invoice_number, - 'quote_number' => $quote_number, - 'dinner_table_id'=> $dinner_table, - 'sale_status' => $sale_status + 'sale_time' => date('Y-m-d H:i:s'), + 'customer_id' => $this->Customer->exists($customer_id) ? $customer_id : null, + 'employee_id' => $employee_id, + 'comment' => $comment, + 'sale_status' => $sale_status, + 'invoice_number' => $invoice_number, + 'quote_number' => $quote_number, + 'work_order_number' => $work_order_number, + 'dinner_table_id' => $dinner_table, + 'sale_status' => $sale_status, + 'sale_type' => $sale_type ); // Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - $this->db->insert('sales', $sales_data); - $sale_id = $this->db->insert_id(); + error_log('>>> sales_data-' . print_r($sales_data, true)); + error_log('>>> sales_id-' . $sale_id); + if($sale_id == -1) + { + $this->db->insert('sales', $sales_data); + $sale_id = $this->db->insert_id(); + } + else + { + $this->db->where('sale_id', $sale_id); + $this->db->update('sales', $sales_data); + } $total_amount = 0; $total_amount_used = 0; foreach($payments as $payment_id=>$payment) @@ -800,19 +825,16 @@ class Sale extends CI_Model } /** - * Delete sale + * Delete sale. Hard deletes are not supported for sales transactions. + * When a sale is "deleted" it is simply changed to a status of canceled. + * However, if applicable the inventory still needs to be updated */ public function delete($sale_id, $employee_id, $update_inventory = TRUE) { // start a transaction to assure data integrity $this->db->trans_start(); - // first delete all payments - $this->db->delete('sales_payments', array('sale_id' => $sale_id)); - // then delete all taxes on items - $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); - - if($update_inventory) + if($update_inventory && $sale_status = $this->get_sale_status($sale_id) == COMPLETED) { // defect, not all item deletions will be undone?? // get array with all the items involved in the sale to update the inventory tracking @@ -840,10 +862,8 @@ class Sale extends CI_Model } } - // delete all items - $this->db->delete('sales_items', array('sale_id' => $sale_id)); - // delete sale itself - $this->db->delete('sales', array('sale_id' => $sale_id)); + // Set the status of the sale to canceled + $this->update_sale_status($sale_id, CANCELED); // execute transaction $this->db->trans_complete(); @@ -965,6 +985,12 @@ class Sale extends CI_Model $payments[$this->lang->line('sales_rewards')] = $this->lang->line('sales_rewards'); } + if($this->sale_lib->get_mode() == 'sale_work_order') + { + $payments[$this->lang->line('sales_cash_deposit')] = $this->lang->line('sales_cash_deposit'); + $payments[$this->lang->line('sales_credit_deposit')] = $this->lang->line('sales_credit_deposit'); + } + return $payments; } @@ -1021,6 +1047,21 @@ class Sale extends CI_Model return ($this->db->get()->num_rows() == 1); } + /** + * Checks if work order number exists + */ + public function check_work_order_number_exists($work_order_number, $sale_id = '') + { + $this->db->from('sales'); + $this->db->where('invoice_number', $work_order_number); + if(!empty($sale_id)) + { + $this->db->where('sale_id !=', $sale_id); + } + + return ($this->db->get()->num_rows() == 1); + } + /** * Gets Giftcard value */ @@ -1184,12 +1225,12 @@ class Sale extends CI_Model { if($customer_id == -1) { - $query = $this->db->query('select sale_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from ' + $query = $this->db->query("select sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' then quote_number when sale_type = '".SALE_TYPE_WORK_ORDER."' then work_order_number else sale_id end as doc_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from " . $this->db->dbprefix('sales') . ' where sale_status = ' . SUSPENDED); } else { - $query = $this->db->query('select sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from ' + $query = $this->db->query("select sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' then quote_number when sale_type = '".SALE_TYPE_WORK_ORDER."' then work_order_number else sale_id end as doc_id, sale_status, sale_time, dinner_table_id, customer_id, comment from " . $this->db->dbprefix('sales') . ' where sale_status = '. SUSPENDED .' AND customer_id = ' . $customer_id); } @@ -1202,12 +1243,46 @@ class Sale extends CI_Model */ public function get_dinner_table($sale_id) { + if($sale_id == -1) + { + return NULL; + } + error_log('>>>get_dinner_table sale_id-'.$sale_id); $this->db->from('sales'); $this->db->where('sale_id', $sale_id); return $this->db->get()->row()->dinner_table_id; } + /** + * Gets the sale type for the selected sale + */ + public function get_sale_type($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id', $sale_id); + + return $this->db->get()->row()->sale_type; + } + + /** + * Gets the sale status for the selected sale + */ + public function get_sale_status($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id', $sale_id); + + return $this->db->get()->row()->sale_status; + } + + public function update_sale_status($sale_id, $sale_status) + { + $this->db->where('sale_id', $sale_id); + $this->db->update('sales', array('sale_status'=>$sale_status)); + } + + /** * Gets the quote_number for the selected sale */ @@ -1277,17 +1352,38 @@ class Sale extends CI_Model $this->db->where('dinner_table_id',$dinner_table); $this->db->update('dinner_tables', $dinner_table_data); - $this->db->delete('sales_payments', array('sale_id' => $sale_id)); - $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); - $this->db->delete('sales_items', array('sale_id' => $sale_id)); - $this->db->delete('sales_taxes', array('sale_id' => $sale_id)); - $this->db->delete('sales', array('sale_id' => $sale_id, 'sale_status' => SUSPENDED)); + $this->update_sale_status($sale_id, CANCELED); $this->db->trans_complete(); return $this->db->trans_status(); } + /** + * This clears the sales detail for a given sale_id before the detail is resaved. + * This allows us to reuse the same sale_id + */ + public function clear_suspended_sale_detail($sale_id) + { + $this->db->trans_start(); + + $dinner_table = $this->get_dinner_table($sale_id); + $dinner_table_data = array( + 'status' => 0 + ); + + $this->db->where('dinner_table_id',$dinner_table); + $this->db->update('dinner_tables', $dinner_table_data); + + $this->db->delete('sales_payments', array('sale_id' => $sale_id)); + $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); + $this->db->delete('sales_items', array('sale_id' => $sale_id)); + $this->db->delete('sales_taxes', array('sale_id' => $sale_id)); + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } /** * Gets suspended sale info */ diff --git a/application/views/configs/invoice_config.php b/application/views/configs/invoice_config.php index 0a8d71a97..fc7cc20c1 100644 --- a/application/views/configs/invoice_config.php +++ b/application/views/configs/invoice_config.php @@ -15,36 +15,14 @@
    -
    +
    lang->line('config_register_mode_default'), 'default_register_mode', array('class' => 'control-label col-xs-2')); ?> -
    - config->item('default_register_mode'), array('class' => 'form-control input-sm')); ?> -
    -
    - -
    - lang->line('config_sales_invoice_format'), 'sales_invoice_format', array('class' => 'control-label col-xs-2')); ?>
    - 'sales_invoice_format', - 'id' => 'sales_invoice_format', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('sales_invoice_format'))); ?> + config->item('default_register_mode'), array('class' => 'form-control input-sm')); ?>
    -
    - lang->line('config_sales_quote_format'), 'sales_quote_format', array('class' => 'control-label col-xs-2')); ?> -
    - 'sales_quote_format', - 'id' => 'sales_quote_format', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('sales_quote_format'))); ?> -
    -
    - -
    +
    lang->line('config_recv_invoice_format'), 'recv_invoice_format', array('class' => 'control-label col-xs-2')); ?>
    -
    +
    + lang->line('config_sales_invoice_format'), 'sales_invoice_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'sales_invoice_format', + 'id' => 'sales_invoice_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('sales_invoice_format'))); ?> +
    +
    + +
    lang->line('config_last_used_invoice_number'), 'last_used_invoice_number', array('class' => 'control-label col-xs-2')); ?> -
    +
    'number', 'name' => 'last_used_invoice_number', 'id' => 'last_used_invoice_number', 'class' => 'form-control input-sm required', 'value'=>$this->config->item('last_used_invoice_number'))); ?> -
    -
    +
    +
    -
    +
    + lang->line('config_sales_quote_format'), 'sales_quote_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'sales_quote_format', + 'id' => 'sales_quote_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('sales_quote_format'))); ?> +
    +
    + +
    lang->line('config_last_used_quote_number'), 'last_used_quote_number', array('class' => 'control-label col-xs-2')); ?> -
    +
    'number', 'name' => 'last_used_quote_number', 'id' => 'last_used_quote_number', 'class' => 'form-control input-sm required', 'value'=>$this->config->item('last_used_quote_number'))); ?> -
    -
    +
    +
    + +
    + lang->line('config_work_order_enable'), 'work_order_enable', array('class' => 'control-label col-xs-2')); ?> +
    + 'work_order_enable', + 'value' => 'work_order_enable', + 'id' => 'work_order_enable', + 'checked' => $this->config->item('work_order_enable')));?> +
    +
    + +
    + lang->line('config_work_order_format'), 'work_order_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'work_order_format', + 'id' => 'work_order_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('work_order_format'))); ?> +
    +
    + +
    + lang->line('config_last_used_work_order_number'), 'last_used_work_order_number', array('class' => 'control-label col-xs-2')); ?> +
    + 'number', + 'name' => 'last_used_work_order_number', + 'id' => 'last_used_work_order_number', + 'class' => 'form-control input-sm required', + 'value'=>$this->config->item('last_used_work_order_number'))); ?> +
    +
    'submit_form', @@ -122,13 +156,30 @@ $(document).ready(function() { var enable_disable_invoice_enable = (function() { - var invoice_enable = $("#invoice_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").prop("disabled", !invoice_enable); + 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, #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 { + $("#work_order_enable").attr('checked', false); + } + return arguments.callee; + })(); + + var enable_disable_work_order_enable = (function() { + var work_order_enabled = $("#work_order_enable").is(":checked"); + var invoice_enabled = $("#invoice_enable").is(":checked"); + if(invoice_enabled) { + $("#work_order_format, #last_used_work_order_number").prop("disabled", !work_order_enabled); + } return arguments.callee; })(); $("#invoice_enable").change(enable_disable_invoice_enable); + $("#work_order_enable").change(enable_disable_work_order_enable); + $("#invoice_config_form").validate($.extend(form_support.handler, { errorLabelContainer: "#invoice_error_message_box", @@ -136,13 +187,14 @@ $(document).ready(function() submitHandler: function(form) { $(form).ajaxSubmit({ beforeSerialize: function(arr, $form, options) { - $("#sales_invoice_format, #sales_quote_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, #last_used_invoice_number, #last_used_quote_number").prop("disabled", false); + $("#sales_invoice_format, #sales_quote_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, #last_used_invoice_number, #last_used_quote_number, #work_order_enable, #work_order_format, #last_used_work_order_number").prop("disabled", false); return true; }, success: function(response) { $.notify(response.message, { type: response.success ? 'success' : 'danger'} ); // set back disabled state enable_disable_invoice_enable(); + enable_disable_work_order_enable(); }, dataType:'json' }); diff --git a/application/views/sales/quote.php b/application/views/sales/quote.php index d89552725..427ec4b95 100644 --- a/application/views/sales/quote.php +++ b/application/views/sales/quote.php @@ -40,7 +40,7 @@ if (isset($error_message))
     ' . $this->lang->line('sales_send_quote'); ?>
     ' . $this->lang->line('sales_register'), array('class'=>'btn btn-info btn-sm', 'id'=>'show_sales_button')); ?> -  ' . $this->lang->line('sales_discard_quote'), array('class'=>'btn btn-danger btn-sm', 'id'=>'discard_quote_button')); ?> +  ' . $this->lang->line('sales_discard'), array('class'=>'btn btn-danger btn-sm', 'id'=>'discard_quote_button')); ?>
    diff --git a/application/views/sales/register.php b/application/views/sales/register.php index c0614da4d..dc272dc7b 100644 --- a/application/views/sales/register.php +++ b/application/views/sales/register.php @@ -411,7 +411,7 @@ if(isset($success))
     lang->line('sales_complete_sale'); ?>
    @@ -485,7 +485,7 @@ if(isset($success))
     lang->line('sales_suspend_sale'); ?>
     
    @@ -500,7 +500,7 @@ if(isset($success))
    @@ -535,7 +535,20 @@ if(isset($success)) -
    + +
    + +
    + +
    config->item('invoice_enable') == TRUE) @@ -678,7 +691,12 @@ $(document).ready(function() { $.post('', {sales_print_after_sale: $(this).is(":checked")}); }); - + + $("#price_work_orders").change(function() + { + $.post('', {price_work_orders: $(this).is(":checked")}); + }); + $('#email_receipt').change(function() { $.post('', {email_receipt: $('#email_receipt').is(':checked') ? '1' : '0'}); diff --git a/application/views/sales/suspended.php b/application/views/sales/suspended.php index 86200bbfe..5d0f0bf51 100644 --- a/application/views/sales/suspended.php +++ b/application/views/sales/suspended.php @@ -1,7 +1,7 @@ - + config->item('dinner_table_enable') == TRUE) @@ -22,7 +22,7 @@ { ?> - + config->item('dinner_table_enable') == TRUE) @@ -50,7 +50,7 @@
    lang->line('sales_suspended_sale_id'); ?>lang->line('sales_suspended_doc_id'); ?> lang->line('sales_date'); ?>
    config->item('dateformat'), strtotime($suspended_sale['sale_time']));?> diff --git a/application/views/sales/work_order.php b/application/views/sales/work_order.php new file mode 100644 index 000000000..6dc578a5c --- /dev/null +++ b/application/views/sales/work_order.php @@ -0,0 +1,213 @@ +load->view("partial/header"); ?> + +".$error_message.""; + exit; +} +?> + + + + + +load->view('partial/print_receipt', array('print_after_sale'=>$print_after_sale, 'selected_printer'=>'invoice_printer')); ?> + + + +
    + +
    +
    + + + +
    + + +
    + +
    + + + + + + + + + + + + + + + + +
    lang->line('common_date'); ?>
    lang->line('sales_amount_due'); ?>
    +
    + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + $sales_tax) + { + ?> + + + + + + + + + + + + + $payment) + { + $only_sale_check |= $payment['payment_type'] == $this->lang->line('sales_check'); + $splitpayment = explode(':', $payment['payment_type']); + $show_giftcard_remainder |= $splitpayment[0] == $this->lang->line('sales_giftcard'); + ?> + + + + + + +
    lang->line('sales_item_number'); ?>lang->line('sales_item_name'); ?>lang->line('sales_quantity'); ?>lang->line('sales_price'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
    +
    + + + +load->view("partial/footer"); ?> diff --git a/application/views/sales/work_order_email.php b/application/views/sales/work_order_email.php new file mode 100644 index 000000000..39c920609 --- /dev/null +++ b/application/views/sales/work_order_email.php @@ -0,0 +1,128 @@ + + + + + + + + +".$error_message.""; + exit; +} +?> + +
    + + + + + + + + + + +
    +
    +
    +
    config->item('company'); ?>
    +
    +
    + + + + + + + + + + 0) + { + ?> + + + + + +
    lang->line('sales_work_order_number');?>
    lang->line('common_date'); ?>
    lang->line('sales_amount_due'); ?>
    +
    + + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + $value) { ?> + + + + + + + + + + + +
    lang->line('sales_item_number'); ?>lang->line('sales_item_name'); ?>lang->line('sales_quantity'); ?>lang->line('sales_price'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
    lang->line('sales_sub_total'); ?>
    lang->line('sales_total'); ?>
    + +
    +
    +
    +
    config->item('payment_message')); ?>
    +
    lang->line('sales_comments'). ': ' . (empty($comments) ? $this->config->item('invoice_default_comments') : $comments); ?>
    +
    + config->item('return_policy')); ?> +
    +
    +
    + +
    +
    +
    + + + diff --git a/database/3.1.0_work_orders.sql b/database/3.1.0_work_orders.sql new file mode 100644 index 000000000..a9aa675f1 --- /dev/null +++ b/database/3.1.0_work_orders.sql @@ -0,0 +1,22 @@ +-- Add support for Work Orders + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); + +ALTER TABLE `ospos_sales` + ADD COLUMN `work_order_number` varchar(32) DEFAULT NULL, + ADD COLUMN `sale_type` tinyint(2) NOT NULL DEFAULT 0; + +-- sale_type (0=pos, 1=invoice, 2=work order, 3=quote) + +update `ospos_sales` + set `sale_type` = '3' where quote_number IS NOT NULL; + +update `ospos_sales` + set `sale_type` = '2', `work_order_number` = `quote_number` + where quote_number IS NOT NULL; + +update `ospos_sales` + set `sale_type` = '1' where invoice_number IS NOT NULL; diff --git a/database/database.sql b/database/database.sql index a04f1e56f..92268bbd6 100644 --- a/database/database.sql +++ b/database/database.sql @@ -111,9 +111,10 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('gcaptcha_enable', '0'), ('gcaptcha_secret_key', ''), ('gcaptcha_site_key', ''), -('receiving_calculate_average_price', '0'); - - +('receiving_calculate_average_price', '0'), +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); -- -------------------------------------------------------- -- @@ -563,6 +564,8 @@ CREATE TABLE `ospos_sales` ( `sale_id` int(10) NOT NULL AUTO_INCREMENT, `sale_status` tinyint(2) NOT NULL DEFAULT 0, `dinner_table_id` int(11) NULL, + `work_order_number` varchar(32) DEFAULT NULL, + `sale_type` tinyint(2) NOT NULL DEFAULT 0, PRIMARY KEY (`sale_id`), KEY `customer_id` (`customer_id`), KEY `employee_id` (`employee_id`), diff --git a/database/tables.sql b/database/tables.sql index a7fffb2a4..bbf4c6e37 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -111,7 +111,11 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('gcaptcha_enable', '0'), ('gcaptcha_secret_key', ''), ('gcaptcha_site_key', ''), -('receiving_calculate_average_price', '0'); +('receiving_calculate_average_price', '0'), +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); + -- -------------------------------------------------------- @@ -565,6 +569,8 @@ CREATE TABLE `ospos_sales` ( `sale_id` int(10) NOT NULL AUTO_INCREMENT, `sale_status` tinyint(2) NOT NULL DEFAULT 0, `dinner_table_id` int(11) NULL, + `work_order_number` varchar(32) DEFAULT NULL, + `sale_type` tinyint(2) NOT NULL DEFAULT 0, PRIMARY KEY (`sale_id`), KEY `customer_id` (`customer_id`), KEY `employee_id` (`employee_id`), From cfa051cee8b2d41614f03386c1912ff1433ddb3b Mon Sep 17 00:00:00 2001 From: FrancescoUK Date: Mon, 4 Sep 2017 22:55:45 +0100 Subject: [PATCH 05/12] Add en_GB translations to backoffice feature (#1543 #1539) --- application/language/en-GB/config_lang.php | 4 ++ application/language/en-GB/module_lang.php | 4 ++ application/language/en-GB/sales_lang.php | 13 +++- database/database.sql | 5 ++ database/migrate_phppos_dist.sql | 73 +++++++++++++--------- 5 files changed, 69 insertions(+), 30 deletions(-) diff --git a/application/language/en-GB/config_lang.php b/application/language/en-GB/config_lang.php index e500d2423..e1902e15e 100644 --- a/application/language/en-GB/config_lang.php +++ b/application/language/en-GB/config_lang.php @@ -142,6 +142,7 @@ $lang["config_jsprintsetup_required"] = "Warning! This disabled functionality wi $lang["config_language"] = "Language"; $lang["config_last_used_invoice_number"] = "Last Used Invoice Number"; $lang["config_last_used_quote_number"] = "Last Used Quote Number"; +$lang["config_last_used_work_order_number"] = "Last Used W/O Number"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; @@ -225,6 +226,7 @@ $lang["config_sales_invoice_format"] = "Sales Invoice Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration saved successfully"; $lang["config_saved_unsuccessfully"] = "Configuration saved unsuccessfully"; +$lang["config_show_office_group"] = "Show office icon"; $lang["config_statistics"] = "Send Statistics"; $lang["config_statistics_tooltip"] = "Send statistics for development and feature improvement purposes"; $lang["config_stock_location"] = "Stock location"; @@ -245,3 +247,5 @@ $lang["config_thousands_separator"] = "Thousands Separator"; $lang["config_timezone"] = "Timezone"; $lang["config_top"] = "Top"; $lang["config_website"] = "Website"; +$lang["config_work_order_enable"] = "Work Order Support"; +$lang["config_work_order_format"] = "Work Order Format"; diff --git a/application/language/en-GB/module_lang.php b/application/language/en-GB/module_lang.php index fc6b555f7..8ef821048 100644 --- a/application/language/en-GB/module_lang.php +++ b/application/language/en-GB/module_lang.php @@ -1,5 +1,6 @@ Date: Sat, 2 Sep 2017 13:31:33 -0400 Subject: [PATCH 06/12] Enance reporting to accomodate work orders and canceled transactions. --- application/controllers/Reports.php | 29 ++++++- application/controllers/Sales.php | 13 +++- application/language/en-US/config_lang.php | 2 +- application/language/en-US/reports_lang.php | 8 ++ application/language/en-US/sales_lang.php | 2 +- application/libraries/Sale_lib.php | 5 ++ application/models/Sale.php | 6 +- application/models/reports/Detailed_sales.php | 75 +++++++++++++++---- .../models/reports/Specific_customer.php | 73 +++++++++++++++--- .../models/reports/Specific_discount.php | 73 +++++++++++++++--- .../models/reports/Specific_employee.php | 73 +++++++++++++++--- application/models/reports/Summary_report.php | 32 ++++++-- application/views/reports/date_input.php | 5 +- application/views/reports/specific_input.php | 5 +- database/3.1.0_work_orders.sql | 27 +++++-- 15 files changed, 348 insertions(+), 80 deletions(-) diff --git a/application/controllers/Reports.php b/application/controllers/Reports.php index 426d510f2..1ffcc3ddd 100644 --- a/application/controllers/Reports.php +++ b/application/controllers/Reports.php @@ -358,6 +358,7 @@ class Reports extends Secure_Controller $stock_locations['all'] = $this->lang->line('reports_all'); $data['stock_locations'] = array_reverse($stock_locations, TRUE); $data['mode'] = 'sale'; + $data['sale_type_options'] = $this->get_sale_type_options(); $this->load->view('reports/date_input', $data); } @@ -370,6 +371,7 @@ class Reports extends Secure_Controller $stock_locations['all'] = $this->lang->line('reports_all'); $data['stock_locations'] = array_reverse($stock_locations, TRUE); $data['mode'] = 'sale'; + $data['sale_type_options'] = $this->get_sale_type_options(); $this->load->view('reports/date_input', $data); } @@ -711,6 +713,7 @@ class Reports extends Secure_Controller $customers[$customer->person_id] = $this->xss_clean($customer->first_name . ' ' . $customer->last_name); } $data['specific_input_data'] = $customers; + $data['sale_type_options'] = $this->get_sale_type_options(); $this->load->view('reports/specific_input', $data); } @@ -735,6 +738,7 @@ class Reports extends Secure_Controller { $summary_data[] = $this->xss_clean(array( 'id' => anchor('sales/receipt/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target'=>'_blank')), + 'type_code' => $row['type_code'], 'sale_date' => $row['sale_date'], 'quantity' => to_quantity_decimals($row['items_purchased']), 'employee_name' => $row['employee_name'], @@ -796,6 +800,7 @@ class Reports extends Secure_Controller $employees[$employee->person_id] = $this->xss_clean($employee->first_name . ' ' . $employee->last_name); } $data['specific_input_data'] = $employees; + $data['sale_type_options'] = $this->get_sale_type_options(); $this->load->view('reports/specific_input', $data); } @@ -820,6 +825,7 @@ class Reports extends Secure_Controller { $summary_data[] = $this->xss_clean(array( 'id' => anchor('sales/receipt/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target'=>'_blank')), + 'type_code' => $row['type_code'], 'sale_date' => $row['sale_date'], 'quantity' => to_quantity_decimals($row['items_purchased']), 'customer_name' => $row['customer_name'], @@ -881,7 +887,8 @@ class Reports extends Secure_Controller $discounts[$i] = $i . '%'; } $data['specific_input_data'] = $discounts; - + $data['sale_type_options'] = $this->get_sale_type_options(); + $data = $this->xss_clean($data); $this->load->view('reports/specific_input', $data); @@ -907,6 +914,7 @@ class Reports extends Secure_Controller { $summary_data[] = $this->xss_clean(array( 'id' => anchor('sales/receipt/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target'=>'_blank')), + 'type_code' => $row['type_code'], 'sale_date' => $row['sale_date'], 'quantity' => to_quantity_decimals($row['items_purchased']), 'customer_name' => $row['customer_name'], @@ -987,6 +995,24 @@ class Reports extends Secure_Controller echo json_encode(array($sale_id => $summary_data)); } + public function get_sale_type_options() + { + $sale_type_options = array(); + $sale_type_options['complete'] = $this->lang->line('reports_complete'); + $sale_type_options['sales'] = $this->lang->line('reports_completed_sales'); + if($this->config->item('invoice_enable') == '1') + { + $sale_type_options['quotes'] = $this->lang->line('reports_quotes'); + if($this->config->item('work_order_enable') == '1') + { + $sale_type_options['work_orders'] = $this->lang->line('reports_work_orders'); + $sale_type_options['canceled'] = $this->lang->line('reports_canceled'); + } + } + $sale_type_options['returns'] = $this->lang->line('reports_returns'); + return $sale_type_options; + } + 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); @@ -1010,6 +1036,7 @@ class Reports extends Secure_Controller { $summary_data[] = $this->xss_clean(array( 'id' => $row['sale_id'], + 'type_code' => $row['type_code'], 'sale_date' => $row['sale_date'], 'quantity' => to_quantity_decimals($row['items_purchased']), 'employee_name' => $row['employee_name'], diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index 98f5ab48c..c10c9c061 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -204,6 +204,10 @@ class Sales extends Secure_Controller { $this->sale_lib->set_mode('sale_invoice'); } + elseif($sale_type == SALE_TYPE_RETURN) + { + $this->sale_lib->set_mode('return'); + } else { $this->sale_lib->set_mode('sale'); @@ -709,7 +713,14 @@ class Sales extends Secure_Controller { // Save the data to the sales table $data['sale_status'] = COMPLETED; - $sale_type = SALE_TYPE_POS; + if($this->sale_lib->is_return_mode()) + { + $sale_type = SALE_TYPE_RETURN; + } + else + { + $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']); diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index 7ad7bcbf8..15d996f81 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -142,7 +142,7 @@ $lang["config_jsprintsetup_required"] = "Warning: This functionality will only w $lang["config_language"] = "Language"; $lang["config_last_used_invoice_number"] = "Last used Invoice Number"; $lang["config_last_used_quote_number"] = "Last used Quote Number"; -$lang["config_last_used_work_order_number"] = "Last Used W/O Number"; +$lang["config_last_used_work_order_number"] = "Last used W/O Number"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; diff --git a/application/language/en-US/reports_lang.php b/application/language/en-US/reports_lang.php index 127e4c03e..81dcf34d0 100644 --- a/application/language/en-US/reports_lang.php +++ b/application/language/en-US/reports_lang.php @@ -1,9 +1,16 @@ CI->session->userdata('sales_mode') == 'sale_quote'); } + public function is_return_mode() + { + return ($this->CI->session->userdata('sales_mode') == 'return'); + } + public function is_work_order_mode() { return ($this->CI->session->userdata('sales_mode') == 'sale_work_order'); diff --git a/application/models/Sale.php b/application/models/Sale.php index 39d3ee513..3cab08104 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -545,8 +545,6 @@ class Sale extends CI_Model */ 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) { - - error_log('>>>save sale_id-' . $sale_id . ', sale_type-' . $sale_type); if($sale_id != -1) { $this->clear_suspended_sale_detail($sale_id); @@ -578,8 +576,6 @@ class Sale extends CI_Model // Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - error_log('>>> sales_data-' . print_r($sales_data, true)); - error_log('>>> sales_id-' . $sale_id); if($sale_id == -1) { $this->db->insert('sales', $sales_data); @@ -1158,6 +1154,7 @@ class Sale extends CI_Model MAX(sales.sale_time) AS sale_time, sales.sale_id AS sale_id, MAX(sales.sale_status) AS sale_status, + MAX(sales.sale_type) AS sale_type, MAX(sales.comment) AS comment, MAX(sales.invoice_number) AS invoice_number, MAX(sales.quote_number) AS quote_number, @@ -1247,7 +1244,6 @@ class Sale extends CI_Model { return NULL; } - error_log('>>>get_dinner_table sale_id-'.$sale_id); $this->db->from('sales'); $this->db->where('sale_id', $sale_id); diff --git a/application/models/reports/Detailed_sales.php b/application/models/reports/Detailed_sales.php index d295ef10d..e247ae9c1 100644 --- a/application/models/reports/Detailed_sales.php +++ b/application/models/reports/Detailed_sales.php @@ -15,6 +15,7 @@ class Detailed_sales extends Report return array( 'summary' => array( array('id' => $this->lang->line('reports_sale_id')), + array('type_code' => $this->lang->line('reports_code_type')), array('sale_date' => $this->lang->line('reports_date')), array('quantity' => $this->lang->line('reports_quantity')), array('employee_name' => $this->lang->line('reports_sold_by')), @@ -66,7 +67,15 @@ class Detailed_sales extends Report public function getData(array $inputs) { - $this->db->select('sale_id, + $this->db->select('sale_id, + MAX(CASE + WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_invoice') . '\' + WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_work_order') . '\' + WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_quote') . '\' + WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_return') . '\' + WHEN sale_status = ' . CANCELED . ' THEN \'' . $this->lang->line('reports_code_canceled') . '\' + ELSE \'\' + END) AS type_code, MAX(sale_status) as sale_status, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, @@ -86,21 +95,41 @@ class Detailed_sales extends Report $this->db->where('item_location', $inputs['location_id']); } - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = '. COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } $this->db->group_by('sale_id'); @@ -136,21 +165,41 @@ class Detailed_sales extends Report $this->db->where('item_location', $inputs['location_id']); } - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } return $this->db->get()->row_array(); diff --git a/application/models/reports/Specific_customer.php b/application/models/reports/Specific_customer.php index 2ce8e31e9..ba33c3933 100644 --- a/application/models/reports/Specific_customer.php +++ b/application/models/reports/Specific_customer.php @@ -15,6 +15,7 @@ class Specific_customer extends Report return array( 'summary' => array( array('id' => $this->lang->line('reports_sale_id')), + array('type_code' => $this->lang->line('reports_code_type')), array('sale_date' => $this->lang->line('reports_date')), array('quantity' => $this->lang->line('reports_quantity')), array('employee_name' => $this->lang->line('reports_sold_by')), @@ -46,6 +47,14 @@ class Specific_customer extends Report public function getData(array $inputs) { $this->db->select('sale_id, + MAX(CASE + WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_invoice') . '\' + WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_work_order') . '\' + WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_quote') . '\' + WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_return') . '\' + WHEN sale_status = ' . CANCELED . ' THEN \'' . $this->lang->line('reports_code_canceled') . '\' + ELSE \'\' + END) AS type_code, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, MAX(employee_name) AS employee_name, @@ -59,21 +68,41 @@ class Specific_customer extends Report $this->db->from('sales_items_temp'); $this->db->where('customer_id', $inputs['customer_id']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } $this->db->group_by('sale_id'); @@ -105,21 +134,41 @@ class Specific_customer extends Report $this->db->from('sales_items_temp'); $this->db->where('customer_id', $inputs['customer_id']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } return $this->db->get()->row_array(); diff --git a/application/models/reports/Specific_discount.php b/application/models/reports/Specific_discount.php index d42ba8055..c2291ebb5 100755 --- a/application/models/reports/Specific_discount.php +++ b/application/models/reports/Specific_discount.php @@ -15,6 +15,7 @@ class Specific_discount extends Report return array( 'summary' => array( array('id' => $this->lang->line('reports_sale_id')), + array('type_code' => $this->lang->line('reports_code_type')), array('sale_date' => $this->lang->line('reports_date')), array('quantity' => $this->lang->line('reports_quantity')), array('customer_name' => $this->lang->line('reports_sold_to')), @@ -44,6 +45,14 @@ class Specific_discount extends Report public function getData(array $inputs) { $this->db->select('sale_id, + MAX(CASE + WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_invoice') . '\' + WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_work_order') . '\' + WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_quote') . '\' + WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_return') . '\' + WHEN sale_status = ' . CANCELED . ' THEN \'' . $this->lang->line('reports_code_canceled') . '\' + ELSE \'\' + END) AS type_code, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, MAX(customer_name) AS customer_name, @@ -57,21 +66,41 @@ class Specific_discount extends Report $this->db->from('sales_items_temp'); $this->db->where('discount_percent >=', $inputs['discount']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } $this->db->group_by('sale_id'); @@ -103,21 +132,41 @@ class Specific_discount extends Report $this->db->from('sales_items_temp'); $this->db->where('discount_percent >=', $inputs['discount']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } return $this->db->get()->row_array(); diff --git a/application/models/reports/Specific_employee.php b/application/models/reports/Specific_employee.php index 5eace2d21..f0e83f80f 100644 --- a/application/models/reports/Specific_employee.php +++ b/application/models/reports/Specific_employee.php @@ -15,6 +15,7 @@ class Specific_employee extends Report return array( 'summary' => array( array('id' => $this->lang->line('reports_sale_id')), + array('type_code' => $this->lang->line('reports_code_type')), array('sale_date' => $this->lang->line('reports_date')), array('quantity' => $this->lang->line('reports_quantity')), array('customer_name' => $this->lang->line('reports_sold_to')), @@ -46,6 +47,14 @@ class Specific_employee extends Report public function getData(array $inputs) { $this->db->select('sale_id, + MAX(CASE + WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_invoice') . '\' + WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_work_order') . '\' + WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . $this->lang->line('reports_code_quote') . '\' + WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . $this->lang->line('reports_code_return') . '\' + WHEN sale_status = ' . CANCELED . ' THEN \'' . $this->lang->line('reports_code_canceled') . '\' + ELSE \'\' + END) AS type_code, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, MAX(customer_name) AS customer_name, @@ -59,21 +68,41 @@ class Specific_employee extends Report $this->db->from('sales_items_temp'); $this->db->where('employee_id', $inputs['employee_id']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } $this->db->group_by('sale_id'); @@ -105,21 +134,41 @@ class Specific_employee extends Report $this->db->from('sales_items_temp'); $this->db->where('employee_id', $inputs['employee_id']); - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } return $this->db->get()->row_array(); diff --git a/application/models/reports/Summary_report.php b/application/models/reports/Summary_report.php index 1dd464edd..92392a15c 100644 --- a/application/models/reports/Summary_report.php +++ b/application/models/reports/Summary_report.php @@ -90,21 +90,41 @@ abstract class Summary_report extends Report $this->db->where('sales_items.item_location', $inputs['location_id']); } - if($inputs['sale_type'] == 'sales') + if($inputs['sale_type'] == 'complete') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased > 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->or_where('sale_type', SALE_TYPE_RETURN); + $this->db->group_end(); } - elseif($inputs['sale_type'] == 'all') + elseif($inputs['sale_type'] == 'sales') { - $this->db->where('sale_status = ' . COMPLETED); + $this->db->where('sale_status', COMPLETED); + $this->db->group_start(); + $this->db->where('sale_type', SALE_TYPE_POS); + $this->db->or_where('sale_type', SALE_TYPE_INVOICE); + $this->db->group_end(); } elseif($inputs['sale_type'] == 'quotes') { - $this->db->where('sale_status = ' . SUSPENDED . ' and quote_number IS NOT NULL'); + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_QUOTE); + } + elseif($inputs['sale_type'] == 'work_orders') + { + $this->db->where('sale_status', SUSPENDED); + $this->db->where('sale_type', SALE_TYPE_WORK_ORDER); + } + elseif($inputs['sale_type'] == 'canceled') + { + $this->db->where('sale_status', CANCELED); } elseif($inputs['sale_type'] == 'returns') { - $this->db->where('sale_status = ' . COMPLETED . ' and quantity_purchased < 0'); + $this->db->where('sale_status', COMPLETED); + $this->db->where('sale_type', SALE_TYPE_RETURN); } diff --git a/application/views/reports/date_input.php b/application/views/reports/date_input.php index 42db42037..4874314d7 100644 --- a/application/views/reports/date_input.php +++ b/application/views/reports/date_input.php @@ -29,10 +29,7 @@ if(isset($error)) ?> lang->line('reports_sale_type'), 'reports_sale_type_label', array('class'=>'required control-label col-xs-2')); ?>
    - $this->lang->line('reports_all'), - 'sales' => $this->lang->line('reports_sales'), - 'quotes' => $this->lang->line('reports_quotes'), - 'returns' => $this->lang->line('reports_returns')), 'all', array('id'=>'input_type', 'class'=>'form-control')); ?> + 'input_type', 'class'=>'form-control')); ?>
    lang->line('reports_sale_type'), 'reports_sale_type_label', array('class'=>'required control-label col-xs-2')); ?>
    - $this->lang->line('reports_all'), - 'sales' => $this->lang->line('reports_sales'), - 'quotes' => $this->lang->line('reports_quotes'), - 'returns' => $this->lang->line('reports_returns')), 'all', 'id="input_type" class="form-control"'); ?> +
    diff --git a/database/3.1.0_work_orders.sql b/database/3.1.0_work_orders.sql index a9aa675f1..9b69edafe 100644 --- a/database/3.1.0_work_orders.sql +++ b/database/3.1.0_work_orders.sql @@ -9,14 +9,25 @@ ALTER TABLE `ospos_sales` ADD COLUMN `work_order_number` varchar(32) DEFAULT NULL, ADD COLUMN `sale_type` tinyint(2) NOT NULL DEFAULT 0; --- sale_type (0=pos, 1=invoice, 2=work order, 3=quote) +-- sale_type (0=pos, 1=invoice, 2=work order, 3=quote, 4=return) -update `ospos_sales` - set `sale_type` = '3' where quote_number IS NOT NULL; +UPDATE `ospos_sales` + SET `sale_type` = 0; -update `ospos_sales` - set `sale_type` = '2', `work_order_number` = `quote_number` - where quote_number IS NOT NULL; +UPDATE ospos_sales t1 + SET sale_type = 4 +WHERE EXISTS (SELECT t2.sale_id FROM ospos_sales_items t2 WHERE t1.sale_id = t2.sale_id AND t2.quantity_purchased < 0); -update `ospos_sales` - set `sale_type` = '1' where invoice_number IS NOT NULL; +UPDATE `ospos_sales` + SET `sale_type` = 3 +WHERE `quote_number` IS NOT NULL; + +-- The following is needed only if quotes were being treated as work orders. +-- UPDATE `ospos_sales` +-- SET `sale_type` = 2, `work_order_number` = `quote_number` +-- WHERE quote_number IS NOT NULL; + +-- Identify invoices +UPDATE `ospos_sales` + SET `sale_type` = 1 +WHERE `invoice_number` IS NOT NULL; From de91510beb5a51582daa7a74bdfdeefdda398a94 Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sat, 2 Sep 2017 13:31:33 -0400 Subject: [PATCH 07/12] Add Office Menu --- application/controllers/Config.php | 3 + application/controllers/Employees.php | 13 +++- application/controllers/Home.php | 5 ++ application/controllers/Office.php | 24 +++++++ application/controllers/Secure_Controller.php | 21 +++++- application/language/en-US/config_lang.php | 1 + application/language/en-US/module_lang.php | 4 ++ application/models/Employee.php | 41 ++++++++--- application/models/Module.php | 61 +++++++++++++++- application/views/configs/general_config.php | 32 +++++++-- application/views/employees/form.php | 56 ++++++++------- application/views/office.php | 23 +++++++ application/views/partial/header.php | 17 +++-- database/3.1.0_to_office-menu.sql | 20 ++++++ database/database.sql | 63 +++++++++-------- database/tables.sql | 65 ++++++++++-------- public/images/menubar/home.png | Bin 0 -> 1099 bytes public/images/menubar/office.png | Bin 0 -> 1099 bytes 18 files changed, 342 insertions(+), 107 deletions(-) create mode 100644 application/controllers/Office.php create mode 100644 application/views/office.php create mode 100644 database/3.1.0_to_office-menu.sql create mode 100644 public/images/menubar/home.png create mode 100644 public/images/menubar/office.png diff --git a/application/controllers/Config.php b/application/controllers/Config.php index 6684f52ed..fce888253 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -206,6 +206,7 @@ class Config extends Secure_Controller $data['register_mode_options'] = $this->sale_lib->get_register_mode_options(); $data['rounding_options'] = Rounding_mode::get_rounding_options(); $data['tax_codes'] = $this->get_tax_code_options(); + $data['show_office_group'] = $this->Module->get_show_office_group(); $data = $this->xss_clean($data); @@ -308,6 +309,8 @@ class Config extends Secure_Controller 'custom10_name' => $this->input->post('custom10_name') ); + $this->Module->set_show_office_group($this->input->post('show_office_group') != NULL); + $result = $this->Appconfig->batch_save($batch_save_data); $success = $result ? TRUE : FALSE; diff --git a/application/controllers/Employees.php b/application/controllers/Employees.php index 533f334b2..18960ad4a 100644 --- a/application/controllers/Employees.php +++ b/application/controllers/Employees.php @@ -61,6 +61,7 @@ class Employees extends Persons { $module->module_id = $this->xss_clean($module->module_id); $module->grant = $this->xss_clean($this->Employee->has_grant($module->module_id, $person_info->person_id)); + $module->menu_group = $this->xss_clean($this->Employee->get_menu_group($module->module_id, $person_info->person_id)); $modules[] = $module; } @@ -134,6 +135,16 @@ class Employees extends Persons 'comments' => $this->input->post('comments'), ); $grants_data = $this->input->post('grants') != NULL ? $this->input->post('grants') : array(); + $menu_groups = $this->input->post('menu_groups') != NULL ? $this->input->post('menu_groups') : array(); + + $grants_array = array(); + foreach ($grants_data as $key => $value) + { + $grants = array(); + $grants['permission_id'] = $value; + $grants['menu_group'] = $menu_groups[$key]; + $grants_array[] = $grants; + } //Password has been changed OR first time password set if($this->input->post('password') != '') @@ -149,7 +160,7 @@ class Employees extends Persons $employee_data = array('username' => $this->input->post('username')); } - if($this->Employee->save_employee($person_data, $employee_data, $grants_data, $employee_id)) + if($this->Employee->save_employee($person_data, $employee_data, $grants_array, $employee_id)) { // New employee if($employee_id == -1) diff --git a/application/controllers/Home.php b/application/controllers/Home.php index 87c1df243..c4c4a5820 100644 --- a/application/controllers/Home.php +++ b/application/controllers/Home.php @@ -4,6 +4,11 @@ require_once("Secure_Controller.php"); class Home extends Secure_Controller { + function __construct() + { + parent::__construct(NULL,NULL,'home'); + } + public function index() { $this->load->view('home'); diff --git a/application/controllers/Office.php b/application/controllers/Office.php new file mode 100644 index 000000000..d9339a4d0 --- /dev/null +++ b/application/controllers/Office.php @@ -0,0 +1,24 @@ +load->view('office'); + } + + public function logout() + { + $this->track_page('logout', 'logout'); + + $this->Employee->logout(); + } +} +?> diff --git a/application/controllers/Secure_Controller.php b/application/controllers/Secure_Controller.php index ad7f18e20..3125ae518 100644 --- a/application/controllers/Secure_Controller.php +++ b/application/controllers/Secure_Controller.php @@ -6,7 +6,7 @@ class Secure_Controller extends CI_Controller * Controllers that are considered secure extend Secure_Controller, optionally a $module_id can * be set to also check if a user can access a particular module in the system. */ - public function __construct($module_id = NULL, $submodule_id = NULL) + public function __construct($module_id = NULL, $submodule_id = NULL, $menu_group = NULL) { parent::__construct(); @@ -28,7 +28,24 @@ class Secure_Controller extends CI_Controller } // load up global data visible to all the loaded views - $data['allowed_modules'] = $this->Module->get_allowed_modules($logged_in_employee_info->person_id); + + $this->load->library('session'); + if($menu_group == NULL) + { + $menu_group = $this->session->userdata('menu_group'); + } + else + { + $this->session->set_userdata('menu_group', $menu_group); + } + if($menu_group == 'home') + { + $data['allowed_modules'] = $this->Module->get_allowed_home_modules($logged_in_employee_info->person_id); + } + else + { + $data['allowed_modules'] = $this->Module->get_allowed_office_modules($logged_in_employee_info->person_id); + } $data['user_info'] = $logged_in_employee_info; $data['controller_name'] = $module_id; diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index f106569f9..3b028986c 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -225,6 +225,7 @@ $lang["config_sales_invoice_format"] = "Sales Invoice Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration save successful."; $lang["config_saved_unsuccessfully"] = "Configuration save failed."; +$lang["config_show_office_group"] = "Show office icon"; $lang["config_statistics"] = "Send Statistics"; $lang["config_statistics_tooltip"] = "Send statistics for development and feature improvement purposes."; $lang["config_stock_location"] = "Stock location"; diff --git a/application/language/en-US/module_lang.php b/application/language/en-US/module_lang.php index e447a17a6..55bc997a4 100644 --- a/application/language/en-US/module_lang.php +++ b/application/language/en-US/module_lang.php @@ -1,5 +1,6 @@ db->insert('grants', array('permission_id' => $permission_id, 'person_id' => $employee_id)); + $success = $this->db->insert('grants', array('permission_id' => $grant['permission_id'], 'person_id' => $employee_id, 'menu_group' => $grant['menu_group'])); + $count = $count+ 1; } } } @@ -390,9 +392,9 @@ class Employee extends Person return ($this->db->get()->num_rows() == 0); } - /* - Determines whether the employee specified employee has access the specific module. - */ + /** + * Determines whether the employee specified employee has access the specific module. + */ public function has_grant($permission_id, $person_id) { //if no module_id is null, allow access @@ -406,9 +408,32 @@ class Employee extends Person return ($query->num_rows() == 1); } - /* - Gets employee permission grants - */ + /** + * Returns the menu group designation that this module is to appear in + */ + public function get_menu_group($permission_id, $person_id) + { + $this->db->select('menu_group'); + $this->db->from('grants'); + $this->db->where('permission_id', $permission_id); + $this->db->where('person_id', $person_id); + + $row = $this->db->get()->row(); + + // If no grants are assigned yet then set the default to 'home' + if ($row == null) + { + return "home"; + } + else + { + return $row->menu_group; + } + } + + /* + Gets employee permission grants + */ public function get_employee_grants($person_id) { $this->db->from('grants'); diff --git a/application/models/Module.php b/application/models/Module.php index 09edd4d6a..1b95375c7 100644 --- a/application/models/Module.php +++ b/application/models/Module.php @@ -6,6 +6,11 @@ class Module extends CI_Model { + function __construct() + { + parent::__construct(); + } + public function get_module_name($module_id) { $query = $this->db->get_where('modules', array('module_id' => $module_id), 1); @@ -55,19 +60,69 @@ class Module extends CI_Model { $this->db->from('modules'); $this->db->order_by('sort', 'asc'); - return $this->db->get(); } - public function get_allowed_modules($person_id) + public function get_allowed_home_modules($person_id) { + $menus = array('home', 'both'); $this->db->from('modules'); $this->db->join('permissions', 'permissions.permission_id = modules.module_id'); $this->db->join('grants', 'permissions.permission_id = grants.permission_id'); $this->db->where('person_id', $person_id); + $this->db->where_in('menu_group', $menus); + $this->db->where('sort !=', 0); $this->db->order_by('sort', 'asc'); - return $this->db->get(); } + + public function get_allowed_office_modules($person_id) + { + $menus = array('office', 'both'); + $this->db->from('modules'); + $this->db->join('permissions', 'permissions.permission_id = modules.module_id'); + $this->db->join('grants', 'permissions.permission_id = grants.permission_id'); + $this->db->where('person_id', $person_id); + $this->db->where_in('menu_group', $menus); + $this->db->where('sort !=', 0); + $this->db->order_by('sort', 'asc'); + return $this->db->get(); + } + + /** + * This method is used to set the show the office navigation icon on the home page + * which happens when the sort value is greater than zero + */ + public function set_show_office_group($show_office_group) + { + if($show_office_group) + { + $sort = 1; + } + else + { + $sort = 0; + } + + $modules_data = array( + 'sort' => $sort + ); + $this->db->where('module_id', 'office'); + $this->db->update('modules', $modules_data); + } + + /** + * This method is used to show the office navigation icon on the home page + * which happens when the sort value is greater than zero + */ + public function get_show_office_group() + { + $this->db->select('sort'); + $this->db->from('grants'); + $this->db->where('module_id', 'office'); + $this->db->from('modules'); + return $this->db->get()->row()->sort; + } + } ?> diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php index 1b179cf5c..86bc5a8c0 100644 --- a/application/views/configs/general_config.php +++ b/application/views/configs/general_config.php @@ -94,7 +94,7 @@
    - lang->line('config_gcaptcha_site_key'), 'config_gcaptcha_site_key', array('class' => 'required control-label col-xs-2')); ?> + lang->line('config_gcaptcha_site_key'), 'config_gcaptcha_site_key', array('class' => 'required control-label col-xs-2','id' => 'config_gcaptcha_site_key')); ?>
    'gcaptcha_site_key', @@ -105,7 +105,7 @@
    - lang->line('config_gcaptcha_secret_key'), 'config_gcaptcha_secret_key', array('class' => 'required control-label col-xs-2')); ?> + lang->line('config_gcaptcha_secret_key'), 'config_gcaptcha_secret_key', array('class' => 'required control-label col-xs-2','id' => 'config_gcaptcha_secret_key')); ?>
    'gcaptcha_secret_key', @@ -150,6 +150,17 @@
    +
    + lang->line('config_show_office_group'), 'show_office_group', array('class' => 'control-label col-xs-2')); ?> +
    + 'show_office_group', + 'id' => 'show_office_group', + 'value' => 'show_office_group', + 'checked' => $show_office_group)); ?> +
    +
    +
    lang->line('config_custom1'), 'config_custom1', array('class' => 'control-label col-xs-2')); ?>
    @@ -284,7 +295,17 @@ $(document).ready(function() { var enable_disable_gcaptcha_enable = (function() { var gcaptcha_enable = $("#gcaptcha_enable").is(":checked"); - $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", !gcaptcha_enable); + if(gcaptcha_enable) + { + $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", !gcaptcha_enable).addClass("required"); + $("#config_gcaptcha_site_key, #config_gcaptcha_secret_key").addClass("required"); + } + else + { + $("#gcaptcha_site_key, #gcaptcha_secret_key").prop("disabled", gcaptcha_enable).removeClass("required"); + $("#config_gcaptcha_site_key, #config_gcaptcha_secret_key").removeClass("required"); + } + return arguments.callee; })(); @@ -294,6 +315,7 @@ $(document).ready(function() window.location=''; }); + $('#general_config_form').validate($.extend(form_support.handler, { errorLabelContainer: "#general_error_message_box", @@ -312,11 +334,11 @@ $(document).ready(function() }, gcaptcha_site_key: { - required: true + required: "#gcaptcha_enable:checked" }, gcaptcha_secret_key: { - required: true + required: "#gcaptcha_enable:checked" } }, diff --git a/application/views/employees/form.php b/application/views/employees/form.php index 077a98639..cb97befc1 100644 --- a/application/views/employees/form.php +++ b/application/views/employees/form.php @@ -82,6 +82,11 @@ ?>
  • module_id, $module->grant, "class='module'"); ?> + $this->lang->line('module_home'), + 'office' => $this->lang->line('module_office'), + 'both' => $this->lang->line('module_both') + ), $module->menu_group, "class='module'"); ?> lang->line('module_'.$module->module_id);?>: lang->line('module_'.$module->module_id.'_desc');?>
  • permission_id, $permission->grant); ?> +
  • @@ -139,20 +145,20 @@ $(document).ready(function() $("ul#permission_list > li > input[name='grants[]']").each(function() { - var $this = $(this); - $("ul > li > input", $this.parent()).each(function() - { - var $that = $(this); - var updateCheckboxes = function (checked) - { + var $this = $(this); + $("ul > li > input", $this.parent()).each(function() + { + var $that = $(this); + var updateCheckboxes = function (checked) + { $that.prop("disabled", !checked); - !checked && $that.prop("checked", false); - } - $this.change(function() { - updateCheckboxes($this.is(":checked")); - }); + !checked && $that.prop("checked", false); + } + $this.change(function() { + updateCheckboxes($this.is(":checked")); + }); updateCheckboxes($this.is(":checked")); - }); + }); }); $('#employee_form').validate($.extend({ @@ -191,20 +197,20 @@ $(document).ready(function() }, repeat_password: { - equalTo: "#password" + equalTo: "#password" }, - email: "email" - }, + email: "email" + }, messages: { - first_name: "lang->line('common_first_name_required'); ?>", - last_name: "lang->line('common_last_name_required'); ?>", - username: - { - required: "lang->line('employees_username_required'); ?>", - minlength: "lang->line('employees_username_minlength'); ?>" - }, - + first_name: "lang->line('common_first_name_required'); ?>", + last_name: "lang->line('common_last_name_required'); ?>", + username: + { + required: "lang->line('employees_username_required'); ?>", + minlength: "lang->line('employees_username_minlength'); ?>" + }, + password: { lang->line('employees_password_must_match'); ?>" - }, - email: "lang->line('common_email_invalid_format'); ?>" + }, + email: "lang->line('common_email_invalid_format'); ?>" } }, form_support.error)); }); diff --git a/application/views/office.php b/application/views/office.php new file mode 100644 index 000000000..f55c47bb4 --- /dev/null +++ b/application/views/office.php @@ -0,0 +1,23 @@ +load->view("partial/header"); ?> + + + +

    lang->line('common_welcome_message'); ?>

    + + + +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/partial/header.php b/application/views/partial/header.php index 192acd02d..80420f109 100644 --- a/application/views/partial/header.php +++ b/application/views/partial/header.php @@ -124,13 +124,16 @@
    diff --git a/database/3.1.0_to_office-menu.sql b/database/3.1.0_to_office-menu.sql new file mode 100644 index 000000000..01045577d --- /dev/null +++ b/database/3.1.0_to_office-menu.sql @@ -0,0 +1,20 @@ +-- Add support for office menu group +ALTER TABLE `ospos_grants` + ADD COLUMN `menu_group` varchar(32) DEFAULT 'home'; + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES +('module_office', 'module_office_desc', 1, 'office'), +('module_home', 'module_home_desc', 1, 'home'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES +('office', 'office'), +('home', 'home'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES +('office', 1, 'home'), +('home', 1, 'office'); + +update `ospos_grants` +set menu_group = 'office' +where permission_id in ('config', 'home', 'employees', 'taxes', 'migrate') +and person_id = 1; \ No newline at end of file diff --git a/database/database.sql b/database/database.sql index ad706468b..02b0de8a3 100644 --- a/database/database.sql +++ b/database/database.sql @@ -354,10 +354,12 @@ INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_i ('module_customers', 'module_customers_desc', 10, 'customers'), ('module_employees', 'module_employees_desc', 80, 'employees'), ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), +('module_home', 'module_home_desc', 1, 'home'), ('module_items', 'module_items_desc', 20, 'items'), ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'), ('module_messages', 'module_messages_desc', 100, 'messages'), ('module_migrate', 'module_migrate_desc', 120, 'migrate'), +('module_office', 'module_office_desc', 1, 'office'), ('module_receivings', 'module_receivings_desc', 60, 'receivings'), ('module_reports', 'module_reports_desc', 50, 'reports'), ('module_sales', 'module_sales_desc', 70, 'sales'), @@ -428,10 +430,12 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('customers', 'customers'), ('employees', 'employees'), ('giftcards', 'giftcards'), +('home', 'home'), ('items', 'items'), ('item_kits', 'item_kits'), ('messages', 'messages'), ('migrate', 'migrate'), +('office', 'office'), ('receivings', 'receivings'), ('reports', 'reports'), ('sales', 'sales'), @@ -453,6 +457,7 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VA CREATE TABLE `ospos_grants` ( `permission_id` varchar(255) NOT NULL, `person_id` int(10) NOT NULL, + `menu_group` varchar(32) DEFAULT 'home', PRIMARY KEY (`permission_id`,`person_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -461,34 +466,36 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES -('reports_customers', 1), -('reports_receivings', 1), -('reports_items', 1), -('reports_inventory', 1), -('reports_employees', 1), -('reports_suppliers', 1), -('reports_sales', 1), -('reports_discounts', 1), -('reports_taxes', 1), -('reports_categories', 1), -('reports_payments', 1), -('customers', 1), -('employees', 1), -('giftcards', 1), -('items', 1), -('item_kits', 1), -('messages', 1), -('migrate', 1), -('receivings', 1), -('reports', 1), -('sales', 1), -('config', 1), -('items_stock', 1), -('sales_stock', 1), -('receivings_stock', 1), -('suppliers', 1), -('taxes', 1); +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +('reports_customers', 1, 'home'), +('reports_receivings', 1, 'home'), +('reports_items', 1, 'home'), +('reports_inventory', 1, 'home'), +('reports_employees', 1, 'home'), +('reports_suppliers', 1, 'home'), +('reports_sales', 1, 'home'), +('reports_discounts', 1, 'home'), +('reports_taxes', 1, 'home'), +('reports_categories', 1, 'home'), +('reports_payments', 1, 'home'), +('customers', 1, 'home'), +('employees', 1, 'office'), +('giftcards', 1, 'home'), +('items', 1, 'home'), +('item_kits', 1, 'home'), +('messages', 1, 'home'), +('migrate', 1, 'office'), +('receivings', 1, 'home'), +('reports', 1, 'home'), +('sales', 1, 'home'), +('config', 1, 'office'), +('items_stock', 1, 'home'), +('sales_stock', 1, 'home'), +('receivings_stock', 1, 'home'), +('suppliers', 1, 'home'), +('taxes', 1, 'office'), +('office', 1, 'home'), +('home', 1, 'office'); -- -- Table structure for table `ospos_receivings` diff --git a/database/tables.sql b/database/tables.sql index 1c47f83ec..37a23e993 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -354,10 +354,12 @@ INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_i ('module_customers', 'module_customers_desc', 10, 'customers'), ('module_employees', 'module_employees_desc', 80, 'employees'), ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), +('module_home', 'module_home_desc', 1, 'home'), ('module_items', 'module_items_desc', 20, 'items'), ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'), ('module_messages', 'module_messages_desc', 100, 'messages'), ('module_migrate', 'module_migrate_desc', 120, 'migrate'), +('module_office', 'module_office_desc', 1, 'office'), ('module_receivings', 'module_receivings_desc', 60, 'receivings'), ('module_reports', 'module_reports_desc', 50, 'reports'), ('module_sales', 'module_sales_desc', 70, 'sales'), @@ -428,10 +430,12 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('customers', 'customers'), ('employees', 'employees'), ('giftcards', 'giftcards'), +('home', 'home'), ('items', 'items'), ('item_kits', 'item_kits'), ('messages', 'messages'), ('migrate', 'migrate'), +('office', 'office'), ('receivings', 'receivings'), ('reports', 'reports'), ('sales', 'sales'), @@ -439,6 +443,8 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('suppliers', 'suppliers'), ('taxes', 'taxes'); + + INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VALUES ('items_stock', 'items', 1), ('sales_stock', 'sales', 1), @@ -453,6 +459,7 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VA CREATE TABLE `ospos_grants` ( `permission_id` varchar(255) NOT NULL, `person_id` int(10) NOT NULL, + `menu_group` varchar(32) DEFAULT 'home', PRIMARY KEY (`permission_id`,`person_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -461,34 +468,36 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES -('reports_customers', 1), -('reports_receivings', 1), -('reports_items', 1), -('reports_inventory', 1), -('reports_employees', 1), -('reports_suppliers', 1), -('reports_sales', 1), -('reports_discounts', 1), -('reports_taxes', 1), -('reports_categories', 1), -('reports_payments', 1), -('customers', 1), -('employees', 1), -('giftcards', 1), -('items', 1), -('item_kits', 1), -('messages', 1), -('migrate', 1), -('receivings', 1), -('reports', 1), -('sales', 1), -('config', 1), -('items_stock', 1), -('sales_stock', 1), -('receivings_stock', 1), -('suppliers', 1), -('taxes', 1); +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +('reports_customers', 1, 'home'), +('reports_receivings', 1, 'home'), +('reports_items', 1, 'home'), +('reports_inventory', 1, 'home'), +('reports_employees', 1, 'home'), +('reports_suppliers', 1, 'home'), +('reports_sales', 1, 'home'), +('reports_discounts', 1, 'home'), +('reports_taxes', 1, 'home'), +('reports_categories', 1, 'home'), +('reports_payments', 1, 'home'), +('customers', 1, 'home'), +('employees', 1, 'office'), +('giftcards', 1, 'home'), +('items', 1, 'home'), +('item_kits', 1, 'home'), +('messages', 1, 'home'), +('migrate', 1, 'office'), +('receivings', 1, 'home'), +('reports', 1, 'home'), +('sales', 1, 'home'), +('config', 1, 'office'), +('items_stock', 1, 'home'), +('sales_stock', 1, 'home'), +('receivings_stock', 1, 'home'), +('suppliers', 1, 'home'), +('taxes', 1, 'office'), +('office', 1, 'home'), +('home', 1, 'office'); -- -- Table structure for table `ospos_receivings` diff --git a/public/images/menubar/home.png b/public/images/menubar/home.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc8ddaf6be62a74a7ca479a8c054346b3c7b711 GIT binary patch literal 1099 zcmV-R1ho5!P)SP6G0Tm-|i+&8_`75UW$-dL98N)AmTwV|AECnKyvVI3f`OEJa~u~PlAaz zFOokY1wrV=1P?6;l28xY7;UPx#J0xw(s9|Yn`ARPQ#TpEFysfjv-|zLw==V|vs$Oq z0a;qO`yh%RX)G!BNxzc=c3Z(xW2Ibr{-_KRrHKZBrW5pmCF8=Z8?^`omJ-4!_!a;f zrwC`U+?E(Hf>FYfLl`w*0AR**SZ=}bswe^kHvpFEg@0h&u4OEF1hI8&0MLAvMLh!k zP@PT-AylLSV6A$|2T|{(MTC%-0szgYnE5#PTSbJB5ek5rFZ(Fv2dPTq4ma(BK8EIj zjX%ollH~_5qUMi4;09o6@J7+R2?2c+xY_{RvCP}rUx~Hh&fE^12^|P=@uh9R%l9YX zZ8IdicW?xN=BbZg;x&J7ep^a7pRS$q0^zFDI6?1m-7oPTg(5FY9_uc+Z3FVWN0-O}&q(M#5Wsp!A04YTP5~>48st!P9MSTxo=K4HD=i{Im zhK%YH0oeu`t7}7VM}~tZ!{%@L9=UK9w$|#xdjel(fYrS9KO+zi=xasXn{DbxJ=>N}W=O^H6edccnv5HNIjUH#Dge!6uydljCL z(hJn21K^nvx_E9HHa>2{&hAh6iU7#`Y;;n_>1`2!s^3O~x~@TdHsT0MuqxCD))XEI zb^(Rb1q z)#4+(Uf9)&@qx3#?Al4QK6I?iyUGAtCXC$+6Rw{NuuMqt_72CS#bL}3l>xSF7@L=- zxSkBLZpAOzK!dgvk9qD4uw_FURD5x=2MG0Eopk__02N=J?g7L1uh0J$U;qwpr*H0y Rxf=ig002ovPDHLkV1oVA^qK$w literal 0 HcmV?d00001 diff --git a/public/images/menubar/office.png b/public/images/menubar/office.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc8ddaf6be62a74a7ca479a8c054346b3c7b711 GIT binary patch literal 1099 zcmV-R1ho5!P)SP6G0Tm-|i+&8_`75UW$-dL98N)AmTwV|AECnKyvVI3f`OEJa~u~PlAaz zFOokY1wrV=1P?6;l28xY7;UPx#J0xw(s9|Yn`ARPQ#TpEFysfjv-|zLw==V|vs$Oq z0a;qO`yh%RX)G!BNxzc=c3Z(xW2Ibr{-_KRrHKZBrW5pmCF8=Z8?^`omJ-4!_!a;f zrwC`U+?E(Hf>FYfLl`w*0AR**SZ=}bswe^kHvpFEg@0h&u4OEF1hI8&0MLAvMLh!k zP@PT-AylLSV6A$|2T|{(MTC%-0szgYnE5#PTSbJB5ek5rFZ(Fv2dPTq4ma(BK8EIj zjX%ollH~_5qUMi4;09o6@J7+R2?2c+xY_{RvCP}rUx~Hh&fE^12^|P=@uh9R%l9YX zZ8IdicW?xN=BbZg;x&J7ep^a7pRS$q0^zFDI6?1m-7oPTg(5FY9_uc+Z3FVWN0-O}&q(M#5Wsp!A04YTP5~>48st!P9MSTxo=K4HD=i{Im zhK%YH0oeu`t7}7VM}~tZ!{%@L9=UK9w$|#xdjel(fYrS9KO+zi=xasXn{DbxJ=>N}W=O^H6edccnv5HNIjUH#Dge!6uydljCL z(hJn21K^nvx_E9HHa>2{&hAh6iU7#`Y;;n_>1`2!s^3O~x~@TdHsT0MuqxCD))XEI zb^(Rb1q z)#4+(Uf9)&@qx3#?Al4QK6I?iyUGAtCXC$+6Rw{NuuMqt_72CS#bL}3l>xSF7@L=- zxSkBLZpAOzK!dgvk9qD4uw_FURD5x=2MG0Eopk__02N=J?g7L1uh0J$U;qwpr*H0y Rxf=ig002ovPDHLkV1oVA^qK$w literal 0 HcmV?d00001 From e42e01a07f09c8630ce7ae9ab34befaf7edea59c Mon Sep 17 00:00:00 2001 From: FrancescoUK Date: Sun, 3 Sep 2017 13:38:27 +0100 Subject: [PATCH 08/12] Bump version to 3.2.0 --- application/config/config.php | 2 +- bower.json | 2 +- deployment.json | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/config/config.php b/application/config/config.php index 32cfc75d9..94a0b5aa5 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -8,7 +8,7 @@ | | */ -$config['application_version'] = '3.1.1'; +$config['application_version'] = '3.2.0'; /* |-------------------------------------------------------------------------- diff --git a/bower.json b/bower.json index d96839b54..ee7a94a98 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "opensourcepos", "description": "Open Source Point of Sale is a web based POS system written in the PHP language. It uses MySQL as backend and has a simple user interface", - "version": "3.1.1", + "version": "3.2.0", "license": "MIT", "authors": [ "jekkos ", diff --git a/deployment.json b/deployment.json index 18cf5dad6..500ad016d 100644 --- a/deployment.json +++ b/deployment.json @@ -14,7 +14,7 @@ "public_stats": true }, "version": { - "name": "3.1.1" + "name": "3.2.0" }, "files": [ diff --git a/package.json b/package.json index 284ec41aa..14781246f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opensourcepos", - "version": "3.1.1", + "version": "3.2.0", "description": "Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.", "main": "index.php", "license": "MIT", From af84a617de312530f82753a193a4bcff5abb0e68 Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sun, 3 Sep 2017 20:14:50 -0400 Subject: [PATCH 09/12] Fix database and table script. --- database/database.sql | 2 +- database/tables.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/database.sql b/database/database.sql index 02b0de8a3..a04f1e56f 100644 --- a/database/database.sql +++ b/database/database.sql @@ -466,7 +466,7 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES ('reports_customers', 1, 'home'), ('reports_receivings', 1, 'home'), ('reports_items', 1, 'home'), diff --git a/database/tables.sql b/database/tables.sql index 37a23e993..a7fffb2a4 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -468,7 +468,7 @@ CREATE TABLE `ospos_grants` ( -- -- -------------------------------------------------------- -INSERT INTO `ospos_grants` (`permission_id`, `person_id`, 'menu_group') VALUES +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES ('reports_customers', 1, 'home'), ('reports_receivings', 1, 'home'), ('reports_items', 1, 'home'), From 36d549cb9ba43a46e45a8081bbb7f7b99c2e80dd Mon Sep 17 00:00:00 2001 From: Steve Ireland Date: Sat, 2 Sep 2017 13:31:33 -0400 Subject: [PATCH 10/12] Add support for Work Orders --- application/controllers/Config.php | 5 +- application/controllers/Sales.php | 301 ++++++++++++------ application/language/en-US/config_lang.php | 3 + application/language/en-US/sales_lang.php | 13 +- application/libraries/Sale_lib.php | 80 ++++- application/libraries/tokens/Token.php | 4 +- .../tokens/Token_work_order_sequence.php | 19 ++ application/models/Appconfig.php | 7 + application/models/Sale.php | 158 +++++++-- application/views/configs/invoice_config.php | 124 +++++--- application/views/sales/quote.php | 2 +- application/views/sales/register.php | 28 +- application/views/sales/suspended.php | 6 +- application/views/sales/work_order.php | 213 +++++++++++++ application/views/sales/work_order_email.php | 128 ++++++++ database/3.1.0_work_orders.sql | 22 ++ database/database.sql | 9 +- database/tables.sql | 8 +- 18 files changed, 943 insertions(+), 187 deletions(-) create mode 100644 application/libraries/tokens/Token_work_order_sequence.php create mode 100644 application/views/sales/work_order.php create mode 100644 application/views/sales/work_order_email.php create mode 100644 database/3.1.0_work_orders.sql diff --git a/application/controllers/Config.php b/application/controllers/Config.php index fce888253..dc0bc8b17 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -844,7 +844,10 @@ class Config extends Secure_Controller '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_quote_number' =>$this->input->post('last_used_quote_number'), + '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') ); $result = $this->Appconfig->batch_save($batch_save_data); diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index 46cabc6d5..98f5ab48c 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -147,13 +147,36 @@ class Sales extends Secure_Controller public function change_mode() { + $mode = $this->input->post('mode'); + $this->sale_lib->set_mode($mode); + + if($mode == 'sale') + { + $this->sale_lib->set_sale_type(SALE_TYPE_POS); + } + else if($mode == 'sale_quote') + { + $this->sale_lib->set_sale_type(SALE_TYPE_QUOTE); + } + else if($mode == 'sale_work_order') + { + $this->sale_lib->set_sale_type(SALE_TYPE_WORK_ORDER); + } + else if($mode == 'sale_invoice') + { + $this->sale_lib->set_sale_type(SALE_TYPE_INVOICE); + } + else + { + $this->sale_lib->set_sale_type(SALE_SALE); + } + $stock_location = $this->input->post('stock_location'); if(!$stock_location || $stock_location == $this->sale_lib->get_sale_location()) { - $mode = $this->input->post('mode'); - $this->sale_lib->set_mode($mode); $dinner_table = $this->input->post('dinner_table'); $this->sale_lib->set_dinner_table($dinner_table); + } elseif($this->Stock_location->is_allowed_location($stock_location, 'sales')) { @@ -163,6 +186,30 @@ class Sales extends Secure_Controller $this->_reload(); } + public function change_register_mode($sale_type) + { + if($sale_type == SALE_TYPE_POS) + { + $this->sale_lib->set_mode('sale'); + } + elseif($sale_type == SALE_TYPE_QUOTE) + { + $this->sale_lib->set_mode('sale_quote'); + } + elseif($sale_type == SALE_TYPE_WORK_ORDER) + { + $this->sale_lib->set_mode('sale_work_order'); + } + elseif($sale_type == SALE_TYPE_INVOICE) + { + $this->sale_lib->set_mode('sale_invoice'); + } + else + { + $this->sale_lib->set_mode('sale'); + } + } + public function set_comment() { $this->sale_lib->set_comment($this->input->post('comment')); @@ -189,6 +236,11 @@ class Sales extends Secure_Controller $this->sale_lib->set_print_after_sale($this->input->post('sales_print_after_sale')); } + public function set_price_work_orders() + { + $this->sale_lib->set_price_work_orders($this->input->post('price_work_orders')); + } + public function set_email_receipt() { $this->sale_lib->set_email_receipt($this->input->post('email_receipt')); @@ -443,6 +495,8 @@ class Sales extends Secure_Controller public function complete() { + $sale_id = $this->sale_lib->get_sale_id(); + $sale_type = $this->sale_lib->get_sale_type(); $data = array(); $data['dinner_table'] = $this->sale_lib->get_dinner_table(); $data['cart'] = $this->sale_lib->get_cart(); @@ -463,10 +517,15 @@ class Sales extends Secure_Controller $data['cur_giftcard_value'] = $this->sale_lib->get_giftcard_remainder(); $data['cur_rewards_value'] = $this->sale_lib->get_rewards_remainder(); $data['print_after_sale'] = $this->sale_lib->is_print_after_sale(); + $data['price_work_orders'] = $this->sale_lib->is_price_work_orders(); $data['email_receipt'] = $this->sale_lib->get_email_receipt(); $customer_id = $this->sale_lib->get_customer(); - $data["invoice_number"] = $this->sale_lib->get_invoice_number(); - $data["quote_number"] = $this->sale_lib->get_quote_number(); + $invoice_number = $this->sale_lib->get_invoice_number(); + $data["invoice_number"] = $invoice_number; + $work_order_number = $this->sale_lib->get_work_order_number(); + $data["work_order_number"] = $work_order_number; + $quote_number = $this->sale_lib->get_quote_number(); + $data["quote_number"] = $quote_number; $customer_info = $this->_load_customer_data($customer_id, $data); if($customer_info != NULL) { @@ -501,13 +560,26 @@ class Sales extends Secure_Controller } $data['amount_change'] = $data['amount_due'] * -1; - if($this->sale_lib->is_invoice_mode() || $data['invoice_number_enabled'] == TRUE) + $data['print_price_info'] = TRUE; + + if($this->sale_lib->is_sale_by_receipt_mode() && $this->input->post('sales_invoice_enable') == '1' ) + { + $pos_invoice = TRUE; + } + else + { + $pos_invoice = FALSE; + } + + if($this->sale_lib->is_invoice_mode() || $pos_invoice) { // generate final invoice number (if using the invoice in sales by receipt mode then the invoice number can be manually entered or altered in some way - if($this->sale_lib->is_sale_by_receipt_mode()) + if($pos_invoice) { + // The user can retain the default encoded format or can manually override it. It still passes through the rendering step. $this->sale_lib->set_invoice_number($this->input->post('invoice_number'), $keep_custom = TRUE); $invoice_format = $this->sale_lib->get_invoice_number(); + // If the user blanks out the invoice number and doesn't put anything in there then revert back to the default format encoding if(empty($invoice_format)) { $invoice_format = $this->config->item('sales_invoice_format'); @@ -517,10 +589,11 @@ class Sales extends Secure_Controller { $invoice_format = $this->config->item('sales_invoice_format'); } - $invoice_number = $this->token_lib->render($invoice_format); - // TODO If duplicate invoice then determine the number of employees and repeat until until success or tried the number of employees (if QSEQ was used). - if($this->Sale->check_invoice_number_exists($invoice_number)) + $invoice_number = $this->token_lib->render($invoice_format); + $data['invoice_number'] = $invoice_number; + + if($sale_id == -1 && $this->Sale->check_invoice_number_exists($invoice_number)) { $data['error'] = $this->lang->line('sales_invoice_number_duplicate'); $this->_reload($data); @@ -529,9 +602,10 @@ class Sales extends Secure_Controller { $data['invoice_number'] = $invoice_number; $data['sale_status'] = COMPLETED; + $sale_type = SALE_TYPE_INVOICE; // Save the data to the sales table - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $data["quote_number"], $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'], $data['taxes']); $data['sale_id'] = 'POS ' . $data['sale_id_num']; // Resort and filter cart lines for printing @@ -551,10 +625,53 @@ class Sales extends Secure_Controller } } } + elseif($this->sale_lib->is_work_order_mode()) + { + + if(!($data['price_work_orders'] == 1)) + { + $data['print_price_info'] = FALSE; + } + + $data['sales_work_order'] = $this->lang->line('sales_work_order'); + $data['work_order_number_label'] = $this->lang->line('sales_work_order_number'); + + if($work_order_number == NULL) + { + // generate work order number + $work_order_format = $this->config->item('work_order_format'); + $work_order_number = $this->token_lib->render($work_order_format); + } + + if($sale_id == -1 && $this->Sale->check_work_order_number_exists($work_order_number)) + { + $data['error'] = $this->lang->line('sales_work_order_number_duplicate'); + $this->_reload($data); + } + else + { + $data['work_order_number'] = $work_order_number; + $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']); + $this->sale_lib->set_suspended_id($data['sale_id_num']); + + $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); + + $data = $this->xss_clean($data); + + $data['barcode'] = NULL; + + $this->load->view('sales/work_order', $data); + $this->sale_lib->clear_mode(); + $this->sale_lib->clear_all(); + } + } elseif($this->sale_lib->is_quote_mode()) { - $invoice_number = NULL; - $quote_number = $this->sale_lib->get_quote_number(); + $data['sales_quote'] = $this->lang->line('sales_quote'); + $data['quote_number_label'] = $this->lang->line('sales_quote_number'); if($quote_number == NULL) { @@ -563,19 +680,18 @@ class Sales extends Secure_Controller $quote_number = $this->token_lib->render($quote_format); } - // TODO If duplicate quote then determine the number of employees and repeat until until success or tried the number of employees (if QSEQ was used). - if($this->Sale->check_quote_number_exists($quote_number)) + if($sale_id == -1 && $this->Sale->check_quote_number_exists($quote_number)) { $data['error'] = $this->lang->line('sales_quote_number_duplicate'); $this->_reload($data); } else { - $data['invoice_number'] = $invoice_number; $data['quote_number'] = $quote_number; $data['sale_status'] = SUSPENDED; + $sale_type = SALE_TYPE_QUOTE; - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $quote_number, $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'], $data['taxes']); $this->sale_lib->set_suspended_id($data['sale_id_num']); $data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']); @@ -592,8 +708,10 @@ class Sales extends Secure_Controller else { // Save the data to the sales table - $data['sale_status'] = '0'; // Complete - $data['sale_id_num'] = $this->Sale->save($data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], NULL, NULL, $data['payments'], $data['dinner_table'], $data['taxes']); + $data['sale_status'] = COMPLETED; + $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'] = 'POS ' . $data['sale_id_num']; @@ -801,6 +919,8 @@ class Sales extends Secure_Controller )); $data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']); $data['print_after_sale'] = FALSE; + $data['price_work_orders'] = FALSE; + if($this->sale_lib->get_mode() == 'sale_invoice') { $data['mode_label'] = $this->lang->line('sales_invoice'); @@ -809,29 +929,26 @@ class Sales extends Secure_Controller { $data['mode_label'] = $this->lang->line('sales_quote'); } + elseif($this->sale_lib->get_mode() == 'sale_work_order') + { + $data['mode_label'] = $this->lang->line('sales_work_order'); + } return $this->xss_clean($data); } private function _reload($data = array()) { + $sale_id = $this->session->userdata('sale_id'); + if($sale_id == '') + { + $sale_id = -1; + $this->session->set_userdata('sale_id', -1); + } $data['cart'] = $this->sale_lib->get_cart(); $customer_info = $this->_load_customer_data($this->sale_lib->get_customer(), $data, TRUE); - if($this->config->item('invoice_enable') == '0') - { - $data['modes'] = array( - 'sale' => $this->lang->line('sales_sale'), - 'return' => $this->lang->line('sales_return')); - } - else - { - $data['modes'] = array( - 'sale' => $this->lang->line('sales_sale'), - 'sale_invoice' => $this->lang->line('sales_sale_by_invoice'), - 'sale_quote' => $this->lang->line('sales_quote'), - 'return' => $this->lang->line('sales_return')); - } + $data['modes'] = $this->sale_lib->get_register_mode_options(); $data['mode'] = $this->sale_lib->get_mode(); $data['empty_tables'] = $this->sale_lib->get_empty_tables(); $data['selected_table'] = $this->sale_lib->get_dinner_table(); @@ -841,6 +958,8 @@ class Sales extends Secure_Controller $data['taxes'] = $this->sale_lib->get_taxes(); $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(); @@ -878,11 +997,6 @@ class Sales extends Secure_Controller { $data['payment_options'] = $this->Sale->get_payment_options(); } - $quote_number = $this->sale_lib->get_quote_number(); - if($quote_number != NULL) - { - $data['quote_number'] = $quote_number; - } $data['items_module_allowed'] = $this->Employee->has_grant('items', $this->Employee->get_logged_in_employee_info()->person_id); @@ -894,8 +1008,13 @@ class Sales extends Secure_Controller $data['invoice_number_enabled'] = $this->sale_lib->is_invoice_mode(); $data['print_after_sale'] = $this->sale_lib->is_print_after_sale(); - $data['quote_or_invoice_mode'] = $data['mode'] == 'sale_invoice' || $data['mode'] == 'sale_quote'; - $data['sales_or_return_mode'] = $data['mode'] == 'sale' || $data['mode'] == 'return'; + $data['price_work_orders'] = $this->sale_lib->is_price_work_orders(); + + $data['pos_mode'] = $data['mode'] == 'sale' || $data['mode'] == 'return'; + + $data['quote_number'] = $this->sale_lib->get_quote_number(); + $data['work_order_number'] = $this->sale_lib->get_work_order_number(); + if($this->sale_lib->get_mode() == 'sale_invoice') { $data['mode_label'] = $this->lang->line('sales_invoice'); @@ -904,6 +1023,10 @@ class Sales extends Secure_Controller { $data['mode_label'] = $this->lang->line('sales_quote'); } + elseif($this->sale_lib->get_mode() == 'sale_work_order') + { + $data['mode_label'] = $this->lang->line('sales_work_order'); + } else { $data['mode_label'] = $this->lang->line('sales_receipt'); @@ -978,70 +1101,33 @@ class Sales extends Secure_Controller } } - public function save($sale_id = -1) + /** + * This is used to cancel a suspended pos sale, quote. + * Completed sales (POS Sales or Invoiced Sales) can not be removed from the system + * Work orders can be canceled but are not physically removed from the sales history + */ + public function cancel() { - $newdate = $this->input->post('date'); - $date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $newdate); - $sale_data = array( - 'sale_time' => $date_formatter->format('Y-m-d H:i:s'), - 'customer_id' => $this->input->post('customer_id') != '' ? $this->input->post('customer_id') : NULL, - 'employee_id' => $this->input->post('employee_id'), - 'comment' => $this->input->post('comment'), - 'invoice_number' => $this->input->post('invoice_number') != '' ? $this->input->post('invoice_number') : NULL - ); - - // go through all the payment type input from the form, make sure the form matches the name and iterator number - $payments = array(); - $number_of_payments = $this->input->post('number_of_payments'); - for($i = 0; $i < $number_of_payments; ++$i) + $sale_id = $this->sale_lib->get_sale_id(); + if($sale_id != -1 && $sale_id != '') { - $payment_amount = $this->input->post('payment_amount_' . $i); - $payment_type = $this->input->post('payment_type_' . $i); - // remove any 0 payment if by mistake any was introduced at sale time - if($payment_amount != 0) + $sale_type = $this->sale_lib->get_sale_type(); + if($sale_type == SALE_TYPE_WORK_ORDER) { - // search for any payment of the same type that was already added, if that's the case add up the new payment amount - $key = FALSE; - if(!empty($payments)) - { - // search in the multi array the key of the entry containing the current payment_type - // NOTE: in PHP5.5 the array_map could be replaced by an array_column - $key = array_search($payment_type, array_map(function ($v) - { - return $v['payment_type']; - }, $payments)); - } - - // if no previous payment is found add a new one - if($key === FALSE) - { - $payments[] = array('payment_type' => $payment_type, 'payment_amount' => $payment_amount); - } - else - { - // add up the new payment amount to an existing payment type - $payments[$key]['payment_amount'] += $payment_amount; - } + $this->Sale->update_sale_status($sale_id, CANCELED); + } + else + { + $this->Sale->delete($sale_id, FALSE); + $this->session->set_userdata('sale_id', -1); } } - if($this->Sale->update($sale_id, $sale_data, $payments)) - { - echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('sales_successfully_updated'), 'id' => $sale_id)); - } - else - { - echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('sales_unsuccessfully_updated'), 'id' => $sale_id)); - } - } - - public function cancel() - { $this->sale_lib->clear_all(); $this->_reload(); } - public function discard_quote() + public function discard_suspended_sale() { $suspended_id = $this->sale_lib->get_suspended_id(); $this->sale_lib->clear_all(); @@ -1049,8 +1135,15 @@ class Sales extends Secure_Controller $this->_reload(); } + /** + * Suspend the current sale. + * If the current sale is already suspended then update the existing suspended sale. + * Otherwise create it as a new suspended sale + */ public function suspend() { + $mode = $this->sale_lib->get_mode(); + $sale_id = $this->sale_lib->get_sale_id(); $dinner_table = $this->sale_lib->get_dinner_table(); $cart = $this->sale_lib->get_cart(); $payments = $this->sale_lib->get_payments(); @@ -1058,13 +1151,20 @@ class Sales extends Secure_Controller $customer_id = $this->sale_lib->get_customer(); $customer_info = $this->Customer->get_info($customer_id); $invoice_number = $this->sale_lib->get_invoice_number(); + $work_order_number = $this->sale_lib->get_work_order_number(); $quote_number = $this->sale_lib->get_quote_number(); + $sale_id = $this->sale_lib->get_sale_id(); + $sale_type = $this->sale_lib->get_sale_type(); + if($sale_type == '') + { + $sale_type = SALE_TYPE_POS; + } $comment = $this->sale_lib->get_comment(); - $sale_status = $this->sale_lib->is_quote_mode() ? QUOTE : SUSPENDED; + $sale_status = SUSPENDED; $data = array(); $sales_taxes = array(); - if($this->Sale->save($sale_status, $cart, $customer_id, $employee_id, $comment, $invoice_number, $quote_number, $payments, $dinner_table, $sales_taxes) == '-1') + 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'); } @@ -1077,6 +1177,9 @@ class Sales extends Secure_Controller $this->_reload($data); } + /** + * List suspended sales + */ public function suspended() { $customer_id = $this->sale_lib->get_customer(); @@ -1087,8 +1190,8 @@ class Sales extends Secure_Controller } /* - * We will eventually drop the current set of "suspended" tables since suspended sales - * are now stored in the sales tables with a sale_status value of suspended. + * Unsuspended sales are now left in the tables and are only removed + * when they are intentionally cancelled. */ public function unsuspend() { @@ -1098,9 +1201,11 @@ class Sales extends Secure_Controller if($sale_id > 0) { $this->sale_lib->copy_entire_sale($sale_id); - $this->Sale->delete_suspended_sale($sale_id); } + // Set current register mode to reflect that of unsuspended order type + $this->change_register_mode($this->sale_lib->get_sale_type()); + $this->_reload(); } diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index 3b028986c..7ad7bcbf8 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -142,6 +142,7 @@ $lang["config_jsprintsetup_required"] = "Warning: This functionality will only w $lang["config_language"] = "Language"; $lang["config_last_used_invoice_number"] = "Last used Invoice Number"; $lang["config_last_used_quote_number"] = "Last used Quote Number"; +$lang["config_last_used_work_order_number"] = "Last Used W/O Number"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; @@ -222,6 +223,7 @@ $lang["config_reward"] = "Reward"; $lang["config_reward_configuration"] = "Reward Configuration"; $lang["config_right"] = "Right"; $lang["config_sales_invoice_format"] = "Sales Invoice Format"; +$lang["config_work_order_format"] = "Work Order Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration save successful."; $lang["config_saved_unsuccessfully"] = "Configuration save failed."; @@ -246,3 +248,4 @@ $lang["config_thousands_separator"] = "Thousands Separator"; $lang["config_timezone"] = "Timezone"; $lang["config_top"] = "Top"; $lang["config_website"] = "Website"; +$lang["config_work_order_enable"] = "Work Order Support"; diff --git a/application/language/en-US/sales_lang.php b/application/language/en-US/sales_lang.php index dbb022d4e..2efbe6066 100644 --- a/application/language/en-US/sales_lang.php +++ b/application/language/en-US/sales_lang.php @@ -8,6 +8,7 @@ $lang["sales_amount_due"] = "Amount Due"; $lang["sales_amount_tendered"] = "Amount Tendered"; $lang["sales_cancel_sale"] = "Cancel"; $lang["sales_cash"] = "Cash"; +$lang["sales_cash_deposit"] = "Cash Deposit"; $lang["sales_cash_filter"] = "Cash"; $lang["sales_change_due"] = "Change Due"; $lang["sales_check"] = "Check"; @@ -19,6 +20,7 @@ $lang["sales_complete_sale"] = "Complete"; $lang["sales_confirm_cancel_sale"] = "Are you sure you want to clear this sale? All items will cleared."; $lang["sales_confirm_delete"] = "Are you sure you want to delete the selected Sale(s)?"; $lang["sales_credit"] = "Credit Card"; +$lang["sales_credit_deposit"] = "Credit Deposit"; $lang["sales_customer"] = "Name"; $lang["sales_customer_address"] = "Address"; $lang["sales_customer_discount"] = "Discount"; @@ -36,7 +38,7 @@ $lang["sales_delete_entire_sale"] = "Delete Entire Sale"; $lang["sales_delete_successful"] = "Sale delete successful."; $lang["sales_delete_unsuccessful"] = "Sale delete failed."; $lang["sales_description_abbrv"] = "Desc."; -$lang["sales_discard_quote"] = "Discard"; +$lang["sales_discard"] = "Discard"; $lang["sales_discount"] = "Disc %"; $lang["sales_discount_included"] = "% Discount"; $lang["sales_discount_short"] = "%"; @@ -57,6 +59,7 @@ $lang["sales_giftcard_number"] = "Gift Card Number"; $lang["sales_group_by_category"] = "Group by Category"; $lang["sales_group_by_type"] = "Group by Type"; $lang["sales_id"] = "Sale ID"; +$lang["sales_include_prices"] = "Include Prices?"; $lang["sales_invoice"] = "Invoice"; $lang["sales_invoice_confirm"] = "This invoice will be sent to"; $lang["sales_invoice_enable"] = "Create Invoice"; @@ -94,6 +97,7 @@ $lang["sales_quantity_less_than_reorder_level"] = "Warning: Desired Quantity is $lang["sales_quantity_less_than_zero"] = "Warning: Desired Quantity is insufficient. You can still process the sale, but audit your inventory."; $lang["sales_quote"] = "Quote"; $lang["sales_quote_number"] = "Quote Number"; +$lang["sales_quote_number_duplicate"] = "Quote Number must be unique."; $lang["sales_quote_sent"] = "Quote sent to"; $lang["sales_quote_unsent"] = "Quote failed to be sent to"; $lang["sales_receipt"] = "Sales Receipt"; @@ -114,6 +118,7 @@ $lang["sales_select_customer"] = "Select Customer (Optional)"; $lang["sales_send_invoice"] = "Send Invoice"; $lang["sales_send_quote"] = "Send Quote"; $lang["sales_send_receipt"] = "Send Receipt"; +$lang["sales_send_work_order"] = "Send Work Order"; $lang["sales_serial"] = "Serial"; $lang["sales_show_invoice"] = "Show Invoice"; $lang["sales_show_receipt"] = "Show Receipt"; @@ -125,6 +130,7 @@ $lang["sales_successfully_deleted"] = "You have successfully deleted"; $lang["sales_successfully_suspended_sale"] = "Sale suspend successful."; $lang["sales_successfully_updated"] = "Sale update successful."; $lang["sales_suspend_sale"] = "Suspend"; +$lang["sales_suspended_doc_id"] = "Document"; $lang["sales_suspended_sale_id"] = "ID"; $lang["sales_suspended_sales"] = "Suspended"; $lang["sales_table"] = "Table"; @@ -141,3 +147,8 @@ $lang["sales_unsuccessfully_updated"] = "Sale update failed."; $lang["sales_unsuspend"] = "Unsuspend"; $lang["sales_unsuspend_and_delete"] = "Action"; $lang["sales_update"] = "Update"; +$lang["sales_work_order"] = "Work Order"; +$lang["sales_work_order_number"] = "Work Order Number"; +$lang["sales_work_order_number_duplicate"] = "The Work Order Number is a duplicate"; +$lang["sales_work_order_sent"] = "Work Order sent to"; +$lang["sales_work_order_unsent"] = "Work Order failed to be sent to"; diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php index 4166f9057..bd58aae77 100644 --- a/application/libraries/Sale_lib.php +++ b/application/libraries/Sale_lib.php @@ -28,11 +28,23 @@ class Sale_lib public function get_register_mode_options() { - return array( - 'sale' => $this->CI->lang->line('sales_receipt'), - 'sale_invoice' => $this->CI->lang->line('sales_invoice'), - 'sale_quote' => $this->CI->lang->line('sales_quote') - ); + $register_modes = array(); + if($this->CI->config->item('invoice_enable') == '0') + { + $register_modes['sale'] = $this->CI->lang->line('sales_sale'); + } + else + { + $register_modes['sale'] = $this->CI->lang->line('sales_receipt'); + $register_modes['sale_quote'] = $this->CI->lang->line('sales_quote'); + if($this->CI->config->item('work_order_enable') == '1') + { + $register_modes['sale_work_order'] = $this->CI->lang->line('sales_work_order'); + } + $register_modes['sale_invoice'] = $this->CI->lang->line('sales_invoice'); + } + $register_modes['return'] = $this->CI->lang->line('sales_return'); + return $register_modes; } public function get_cart() @@ -148,6 +160,16 @@ class Sale_lib return $this->CI->session->userdata('sales_quote_number'); } + public function get_work_order_number() + { + return $this->CI->session->userdata('sales_work_order_number'); + } + + public function get_sale_type() + { + return $this->CI->session->userdata('sale_type'); + } + public function set_invoice_number($invoice_number, $keep_custom = FALSE) { $current_invoice_number = $this->CI->session->userdata('sales_invoice_number'); @@ -166,6 +188,24 @@ class Sale_lib } } + public function set_work_order_number($work_order_number, $keep_custom = FALSE) + { + $current_work_order_number = $this->CI->session->userdata('sales_work_order_number'); + if(!$keep_custom || empty($current_work_order_number)) + { + $this->CI->session->set_userdata('sales_work_order_number', $work_order_number); + } + } + + public function set_sale_type($sale_type, $keep_custom = FALSE) + { + $current_sale_type = $this->CI->session->userdata('sale_type'); + if(!$keep_custom || empty($current_sale_type)) + { + $this->CI->session->set_userdata('sale_type', $sale_type); + } + } + public function clear_invoice_number() { $this->CI->session->unset_userdata('sales_invoice_number'); @@ -176,6 +216,11 @@ class Sale_lib $this->CI->session->unset_userdata('sales_quote_number'); } + public function clear_sale_type() + { + $this->CI->session->unset_userdata('sale_type'); + } + public function set_suspended_id($suspended_id) { $this->CI->session->set_userdata('suspended_id', $suspended_id); @@ -204,6 +249,11 @@ class Sale_lib return ($this->CI->session->userdata('sales_mode') == 'sale_quote'); } + public function is_work_order_mode() + { + return ($this->CI->session->userdata('sales_mode') == 'sale_work_order'); + } + public function set_invoice_number_enabled($invoice_number_enabled) { return $this->CI->session->set_userdata('sales_invoice_number_enabled', $invoice_number_enabled); @@ -215,11 +265,22 @@ class Sale_lib $this->CI->session->userdata('sales_print_after_sale') == '1'); } + public function is_price_work_orders() + { + return ($this->CI->session->userdata('sales_price_work_orders') == 'true' || + $this->CI->session->userdata('sales_price_work_orders') == '1'); + } + public function set_print_after_sale($print_after_sale) { return $this->CI->session->set_userdata('sales_print_after_sale', $print_after_sale); } + public function set_price_work_orders($price_work_orders) + { + return $this->CI->session->set_userdata('sales_price_work_orders', $price_work_orders); + } + public function get_email_receipt() { return $this->CI->session->userdata('sales_email_receipt'); @@ -380,7 +441,6 @@ class Sale_lib { $cash_total = $total; $totals['cash_total'] = $cash_total; - } $payment_total = $this->get_payments_total(); @@ -862,8 +922,14 @@ class Sale_lib $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); $this->set_employee($this->CI->Sale->get_employee($sale_id)->person_id); $this->set_quote_number($this->CI->Sale->get_quote_number($sale_id)); + $this->set_sale_type($this->CI->Sale->get_sale_type($sale_id)); $this->set_comment($this->CI->Sale->get_comment($sale_id)); $this->set_dinner_table($this->CI->Sale->get_dinner_table($sale_id)); + $this->CI->session->set_userdata('sale_id', $sale_id); + } + + public function get_sale_id() { + return $this->CI->session->userdata('sale_id'); } public function get_cart_reordered($sale_id) @@ -880,6 +946,7 @@ class Sale_lib public function clear_all() { + $this->CI->session->set_userdata('sale_id', -1); $this->set_invoice_number_enabled(FALSE); $this->clear_table(); $this->empty_cart(); @@ -887,6 +954,7 @@ class Sale_lib $this->clear_email_receipt(); $this->clear_invoice_number(); $this->clear_quote_number(); + $this->clear_sale_type(); $this->clear_giftcard_remainder(); $this->empty_payments(); $this->remove_customer(); diff --git a/application/libraries/tokens/Token.php b/application/libraries/tokens/Token.php index 06697e712..2d4874409 100644 --- a/application/libraries/tokens/Token.php +++ b/application/libraries/tokens/Token.php @@ -5,6 +5,7 @@ require_once(APPPATH . 'libraries/tokens/Token_customer.php'); require_once(APPPATH . 'libraries/tokens/Token_invoice_count.php'); require_once(APPPATH . 'libraries/tokens/Token_invoice_sequence.php'); require_once(APPPATH . 'libraries/tokens/Token_quote_sequence.php'); +require_once(APPPATH . 'libraries/tokens/Token_work_order_sequence.php'); require_once(APPPATH . 'libraries/tokens/Token_suspended_invoice_count.php'); require_once(APPPATH . 'libraries/tokens/Token_year_invoice_count.php'); @@ -27,7 +28,8 @@ abstract class Token static function get_tokens() { return array(new Token_customer(), new Token_invoice_count(), new Token_invoice_sequence(), - new Token_quote_sequence(), new Token_suspended_invoice_count(), new Token_quote_sequence(), new Token_year_invoice_count()); + new Token_quote_sequence(), new Token_suspended_invoice_count(), new Token_quote_sequence(), + new Token_work_order_sequence(), new Token_year_invoice_count()); } abstract public function token_id(); diff --git a/application/libraries/tokens/Token_work_order_sequence.php b/application/libraries/tokens/Token_work_order_sequence.php new file mode 100644 index 000000000..9405902bf --- /dev/null +++ b/application/libraries/tokens/Token_work_order_sequence.php @@ -0,0 +1,19 @@ +CI->Appconfig->acquire_save_next_work_order_sequence(); + } +} +?> diff --git a/application/models/Appconfig.php b/application/models/Appconfig.php index 58d01604d..09cfef6ef 100644 --- a/application/models/Appconfig.php +++ b/application/models/Appconfig.php @@ -93,5 +93,12 @@ class Appconfig extends CI_Model $this->save('last_used_quote_number', $last_used); return $last_used; } + + public function acquire_save_next_work_order_sequence() + { + $last_used = $this->get('last_used_work_order_number') + 1; + $this->save('last_used_work_order_number', $last_used); + return $last_used; + } } ?> diff --git a/application/models/Sale.php b/application/models/Sale.php index 52378f889..39d3ee513 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -2,7 +2,13 @@ define('COMPLETED', 0); define('SUSPENDED', 1); -define('QUOTE', 2); +define('CANCELED', 2); + +define('SALE_TYPE_POS', 0); +define('SALE_TYPE_INVOICE', 1); +define('SALE_TYPE_WORK_ORDER', 2); +define('SALE_TYPE_QUOTE', 3); +define('SALE_TYPE_RETURN', 4); /** * Sale class @@ -537,8 +543,15 @@ 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_status, &$items, $customer_id, $employee_id, $comment, $invoice_number, $quote_number, $payments, $dinner_table, &$sales_taxes, $sale_id = FALSE) + 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) { + + error_log('>>>save sale_id-' . $sale_id . ', sale_type-' . $sale_type); + if($sale_id != -1) + { + $this->clear_suspended_sale_detail($sale_id); + } + $tax_decimals = tax_decimals(); if(count($items) == 0) @@ -549,22 +562,34 @@ class Sale extends CI_Model $table_status = $this->determine_sale_status($sale_status, $dinner_table); $sales_data = array( - 'sale_time' => date('Y-m-d H:i:s'), - 'customer_id' => $this->Customer->exists($customer_id) ? $customer_id : null, - 'employee_id' => $employee_id, - 'comment' => $comment, - 'sale_status' => $sale_status, - 'invoice_number' => $invoice_number, - 'quote_number' => $quote_number, - 'dinner_table_id'=> $dinner_table, - 'sale_status' => $sale_status + 'sale_time' => date('Y-m-d H:i:s'), + 'customer_id' => $this->Customer->exists($customer_id) ? $customer_id : null, + 'employee_id' => $employee_id, + 'comment' => $comment, + 'sale_status' => $sale_status, + 'invoice_number' => $invoice_number, + 'quote_number' => $quote_number, + 'work_order_number' => $work_order_number, + 'dinner_table_id' => $dinner_table, + 'sale_status' => $sale_status, + 'sale_type' => $sale_type ); // Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - $this->db->insert('sales', $sales_data); - $sale_id = $this->db->insert_id(); + error_log('>>> sales_data-' . print_r($sales_data, true)); + error_log('>>> sales_id-' . $sale_id); + if($sale_id == -1) + { + $this->db->insert('sales', $sales_data); + $sale_id = $this->db->insert_id(); + } + else + { + $this->db->where('sale_id', $sale_id); + $this->db->update('sales', $sales_data); + } $total_amount = 0; $total_amount_used = 0; foreach($payments as $payment_id=>$payment) @@ -800,19 +825,16 @@ class Sale extends CI_Model } /** - * Delete sale + * Delete sale. Hard deletes are not supported for sales transactions. + * When a sale is "deleted" it is simply changed to a status of canceled. + * However, if applicable the inventory still needs to be updated */ public function delete($sale_id, $employee_id, $update_inventory = TRUE) { // start a transaction to assure data integrity $this->db->trans_start(); - // first delete all payments - $this->db->delete('sales_payments', array('sale_id' => $sale_id)); - // then delete all taxes on items - $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); - - if($update_inventory) + if($update_inventory && $sale_status = $this->get_sale_status($sale_id) == COMPLETED) { // defect, not all item deletions will be undone?? // get array with all the items involved in the sale to update the inventory tracking @@ -840,10 +862,8 @@ class Sale extends CI_Model } } - // delete all items - $this->db->delete('sales_items', array('sale_id' => $sale_id)); - // delete sale itself - $this->db->delete('sales', array('sale_id' => $sale_id)); + // Set the status of the sale to canceled + $this->update_sale_status($sale_id, CANCELED); // execute transaction $this->db->trans_complete(); @@ -965,6 +985,12 @@ class Sale extends CI_Model $payments[$this->lang->line('sales_rewards')] = $this->lang->line('sales_rewards'); } + if($this->sale_lib->get_mode() == 'sale_work_order') + { + $payments[$this->lang->line('sales_cash_deposit')] = $this->lang->line('sales_cash_deposit'); + $payments[$this->lang->line('sales_credit_deposit')] = $this->lang->line('sales_credit_deposit'); + } + return $payments; } @@ -1021,6 +1047,21 @@ class Sale extends CI_Model return ($this->db->get()->num_rows() == 1); } + /** + * Checks if work order number exists + */ + public function check_work_order_number_exists($work_order_number, $sale_id = '') + { + $this->db->from('sales'); + $this->db->where('invoice_number', $work_order_number); + if(!empty($sale_id)) + { + $this->db->where('sale_id !=', $sale_id); + } + + return ($this->db->get()->num_rows() == 1); + } + /** * Gets Giftcard value */ @@ -1184,12 +1225,12 @@ class Sale extends CI_Model { if($customer_id == -1) { - $query = $this->db->query('select sale_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from ' + $query = $this->db->query("select sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' then quote_number when sale_type = '".SALE_TYPE_WORK_ORDER."' then work_order_number else sale_id end as doc_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from " . $this->db->dbprefix('sales') . ' where sale_status = ' . SUSPENDED); } else { - $query = $this->db->query('select sale_id, sale_status, sale_time, dinner_table_id, customer_id, comment from ' + $query = $this->db->query("select sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' then quote_number when sale_type = '".SALE_TYPE_WORK_ORDER."' then work_order_number else sale_id end as doc_id, sale_status, sale_time, dinner_table_id, customer_id, comment from " . $this->db->dbprefix('sales') . ' where sale_status = '. SUSPENDED .' AND customer_id = ' . $customer_id); } @@ -1202,12 +1243,46 @@ class Sale extends CI_Model */ public function get_dinner_table($sale_id) { + if($sale_id == -1) + { + return NULL; + } + error_log('>>>get_dinner_table sale_id-'.$sale_id); $this->db->from('sales'); $this->db->where('sale_id', $sale_id); return $this->db->get()->row()->dinner_table_id; } + /** + * Gets the sale type for the selected sale + */ + public function get_sale_type($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id', $sale_id); + + return $this->db->get()->row()->sale_type; + } + + /** + * Gets the sale status for the selected sale + */ + public function get_sale_status($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id', $sale_id); + + return $this->db->get()->row()->sale_status; + } + + public function update_sale_status($sale_id, $sale_status) + { + $this->db->where('sale_id', $sale_id); + $this->db->update('sales', array('sale_status'=>$sale_status)); + } + + /** * Gets the quote_number for the selected sale */ @@ -1277,17 +1352,38 @@ class Sale extends CI_Model $this->db->where('dinner_table_id',$dinner_table); $this->db->update('dinner_tables', $dinner_table_data); - $this->db->delete('sales_payments', array('sale_id' => $sale_id)); - $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); - $this->db->delete('sales_items', array('sale_id' => $sale_id)); - $this->db->delete('sales_taxes', array('sale_id' => $sale_id)); - $this->db->delete('sales', array('sale_id' => $sale_id, 'sale_status' => SUSPENDED)); + $this->update_sale_status($sale_id, CANCELED); $this->db->trans_complete(); return $this->db->trans_status(); } + /** + * This clears the sales detail for a given sale_id before the detail is resaved. + * This allows us to reuse the same sale_id + */ + public function clear_suspended_sale_detail($sale_id) + { + $this->db->trans_start(); + + $dinner_table = $this->get_dinner_table($sale_id); + $dinner_table_data = array( + 'status' => 0 + ); + + $this->db->where('dinner_table_id',$dinner_table); + $this->db->update('dinner_tables', $dinner_table_data); + + $this->db->delete('sales_payments', array('sale_id' => $sale_id)); + $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); + $this->db->delete('sales_items', array('sale_id' => $sale_id)); + $this->db->delete('sales_taxes', array('sale_id' => $sale_id)); + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } /** * Gets suspended sale info */ diff --git a/application/views/configs/invoice_config.php b/application/views/configs/invoice_config.php index 0a8d71a97..fc7cc20c1 100644 --- a/application/views/configs/invoice_config.php +++ b/application/views/configs/invoice_config.php @@ -15,36 +15,14 @@
    -
    +
    lang->line('config_register_mode_default'), 'default_register_mode', array('class' => 'control-label col-xs-2')); ?> -
    - config->item('default_register_mode'), array('class' => 'form-control input-sm')); ?> -
    -
    - -
    - lang->line('config_sales_invoice_format'), 'sales_invoice_format', array('class' => 'control-label col-xs-2')); ?>
    - 'sales_invoice_format', - 'id' => 'sales_invoice_format', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('sales_invoice_format'))); ?> + config->item('default_register_mode'), array('class' => 'form-control input-sm')); ?>
    -
    - lang->line('config_sales_quote_format'), 'sales_quote_format', array('class' => 'control-label col-xs-2')); ?> -
    - 'sales_quote_format', - 'id' => 'sales_quote_format', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('sales_quote_format'))); ?> -
    -
    - -
    +
    lang->line('config_recv_invoice_format'), 'recv_invoice_format', array('class' => 'control-label col-xs-2')); ?>
    -
    +
    + lang->line('config_sales_invoice_format'), 'sales_invoice_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'sales_invoice_format', + 'id' => 'sales_invoice_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('sales_invoice_format'))); ?> +
    +
    + +
    lang->line('config_last_used_invoice_number'), 'last_used_invoice_number', array('class' => 'control-label col-xs-2')); ?> -
    +
    'number', 'name' => 'last_used_invoice_number', 'id' => 'last_used_invoice_number', 'class' => 'form-control input-sm required', 'value'=>$this->config->item('last_used_invoice_number'))); ?> -
    -
    +
    +
    -
    +
    + lang->line('config_sales_quote_format'), 'sales_quote_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'sales_quote_format', + 'id' => 'sales_quote_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('sales_quote_format'))); ?> +
    +
    + +
    lang->line('config_last_used_quote_number'), 'last_used_quote_number', array('class' => 'control-label col-xs-2')); ?> -
    +
    'number', 'name' => 'last_used_quote_number', 'id' => 'last_used_quote_number', 'class' => 'form-control input-sm required', 'value'=>$this->config->item('last_used_quote_number'))); ?> -
    -
    +
    +
    + +
    + lang->line('config_work_order_enable'), 'work_order_enable', array('class' => 'control-label col-xs-2')); ?> +
    + 'work_order_enable', + 'value' => 'work_order_enable', + 'id' => 'work_order_enable', + 'checked' => $this->config->item('work_order_enable')));?> +
    +
    + +
    + lang->line('config_work_order_format'), 'work_order_format', array('class' => 'control-label col-xs-2')); ?> +
    + 'work_order_format', + 'id' => 'work_order_format', + 'class' => 'form-control input-sm', + 'value' => $this->config->item('work_order_format'))); ?> +
    +
    + +
    + lang->line('config_last_used_work_order_number'), 'last_used_work_order_number', array('class' => 'control-label col-xs-2')); ?> +
    + 'number', + 'name' => 'last_used_work_order_number', + 'id' => 'last_used_work_order_number', + 'class' => 'form-control input-sm required', + 'value'=>$this->config->item('last_used_work_order_number'))); ?> +
    +
    'submit_form', @@ -122,13 +156,30 @@ $(document).ready(function() { var enable_disable_invoice_enable = (function() { - var invoice_enable = $("#invoice_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").prop("disabled", !invoice_enable); + 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, #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 { + $("#work_order_enable").attr('checked', false); + } + return arguments.callee; + })(); + + var enable_disable_work_order_enable = (function() { + var work_order_enabled = $("#work_order_enable").is(":checked"); + var invoice_enabled = $("#invoice_enable").is(":checked"); + if(invoice_enabled) { + $("#work_order_format, #last_used_work_order_number").prop("disabled", !work_order_enabled); + } return arguments.callee; })(); $("#invoice_enable").change(enable_disable_invoice_enable); + $("#work_order_enable").change(enable_disable_work_order_enable); + $("#invoice_config_form").validate($.extend(form_support.handler, { errorLabelContainer: "#invoice_error_message_box", @@ -136,13 +187,14 @@ $(document).ready(function() submitHandler: function(form) { $(form).ajaxSubmit({ beforeSerialize: function(arr, $form, options) { - $("#sales_invoice_format, #sales_quote_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, #last_used_invoice_number, #last_used_quote_number").prop("disabled", false); + $("#sales_invoice_format, #sales_quote_format, #recv_invoice_format, #invoice_default_comments, #invoice_email_message, #last_used_invoice_number, #last_used_quote_number, #work_order_enable, #work_order_format, #last_used_work_order_number").prop("disabled", false); return true; }, success: function(response) { $.notify(response.message, { type: response.success ? 'success' : 'danger'} ); // set back disabled state enable_disable_invoice_enable(); + enable_disable_work_order_enable(); }, dataType:'json' }); diff --git a/application/views/sales/quote.php b/application/views/sales/quote.php index d89552725..427ec4b95 100644 --- a/application/views/sales/quote.php +++ b/application/views/sales/quote.php @@ -40,7 +40,7 @@ if (isset($error_message))
     ' . $this->lang->line('sales_send_quote'); ?>
     ' . $this->lang->line('sales_register'), array('class'=>'btn btn-info btn-sm', 'id'=>'show_sales_button')); ?> -  ' . $this->lang->line('sales_discard_quote'), array('class'=>'btn btn-danger btn-sm', 'id'=>'discard_quote_button')); ?> +  ' . $this->lang->line('sales_discard'), array('class'=>'btn btn-danger btn-sm', 'id'=>'discard_quote_button')); ?>
    diff --git a/application/views/sales/register.php b/application/views/sales/register.php index c0614da4d..dc272dc7b 100644 --- a/application/views/sales/register.php +++ b/application/views/sales/register.php @@ -411,7 +411,7 @@ if(isset($success))
     lang->line('sales_complete_sale'); ?>
    @@ -485,7 +485,7 @@ if(isset($success))
     lang->line('sales_suspend_sale'); ?>
     
    @@ -500,7 +500,7 @@ if(isset($success))
    @@ -535,7 +535,20 @@ if(isset($success)) -
    + +
    + +
    + +
    config->item('invoice_enable') == TRUE) @@ -678,7 +691,12 @@ $(document).ready(function() { $.post('', {sales_print_after_sale: $(this).is(":checked")}); }); - + + $("#price_work_orders").change(function() + { + $.post('', {price_work_orders: $(this).is(":checked")}); + }); + $('#email_receipt').change(function() { $.post('', {email_receipt: $('#email_receipt').is(':checked') ? '1' : '0'}); diff --git a/application/views/sales/suspended.php b/application/views/sales/suspended.php index 86200bbfe..5d0f0bf51 100644 --- a/application/views/sales/suspended.php +++ b/application/views/sales/suspended.php @@ -1,7 +1,7 @@ - + config->item('dinner_table_enable') == TRUE) @@ -22,7 +22,7 @@ { ?> - + config->item('dinner_table_enable') == TRUE) @@ -50,7 +50,7 @@
    lang->line('sales_suspended_sale_id'); ?>lang->line('sales_suspended_doc_id'); ?> lang->line('sales_date'); ?>
    config->item('dateformat'), strtotime($suspended_sale['sale_time']));?> diff --git a/application/views/sales/work_order.php b/application/views/sales/work_order.php new file mode 100644 index 000000000..6dc578a5c --- /dev/null +++ b/application/views/sales/work_order.php @@ -0,0 +1,213 @@ +load->view("partial/header"); ?> + +".$error_message.""; + exit; +} +?> + + + + + +load->view('partial/print_receipt', array('print_after_sale'=>$print_after_sale, 'selected_printer'=>'invoice_printer')); ?> + + + +
    + +
    +
    + + + +
    + + +
    + +
    + + + + + + + + + + + + + + + + +
    lang->line('common_date'); ?>
    lang->line('sales_amount_due'); ?>
    +
    + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + $sales_tax) + { + ?> + + + + + + + + + + + + + $payment) + { + $only_sale_check |= $payment['payment_type'] == $this->lang->line('sales_check'); + $splitpayment = explode(':', $payment['payment_type']); + $show_giftcard_remainder |= $splitpayment[0] == $this->lang->line('sales_giftcard'); + ?> + + + + + + +
    lang->line('sales_item_number'); ?>lang->line('sales_item_name'); ?>lang->line('sales_quantity'); ?>lang->line('sales_price'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
    +
    + + + +load->view("partial/footer"); ?> diff --git a/application/views/sales/work_order_email.php b/application/views/sales/work_order_email.php new file mode 100644 index 000000000..39c920609 --- /dev/null +++ b/application/views/sales/work_order_email.php @@ -0,0 +1,128 @@ + + + + + + + + +".$error_message.""; + exit; +} +?> + +
    + + + + + + + + + + +
    +
    +
    +
    config->item('company'); ?>
    +
    +
    + + + + + + + + + + 0) + { + ?> + + + + + +
    lang->line('sales_work_order_number');?>
    lang->line('common_date'); ?>
    lang->line('sales_amount_due'); ?>
    +
    + + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + $value) { ?> + + + + + + + + + + + +
    lang->line('sales_item_number'); ?>lang->line('sales_item_name'); ?>lang->line('sales_quantity'); ?>lang->line('sales_price'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
    lang->line('sales_sub_total'); ?>
    lang->line('sales_total'); ?>
    + +
    +
    +
    +
    config->item('payment_message')); ?>
    +
    lang->line('sales_comments'). ': ' . (empty($comments) ? $this->config->item('invoice_default_comments') : $comments); ?>
    +
    + config->item('return_policy')); ?> +
    +
    +
    + +
    +
    +
    + + + diff --git a/database/3.1.0_work_orders.sql b/database/3.1.0_work_orders.sql new file mode 100644 index 000000000..a9aa675f1 --- /dev/null +++ b/database/3.1.0_work_orders.sql @@ -0,0 +1,22 @@ +-- Add support for Work Orders + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); + +ALTER TABLE `ospos_sales` + ADD COLUMN `work_order_number` varchar(32) DEFAULT NULL, + ADD COLUMN `sale_type` tinyint(2) NOT NULL DEFAULT 0; + +-- sale_type (0=pos, 1=invoice, 2=work order, 3=quote) + +update `ospos_sales` + set `sale_type` = '3' where quote_number IS NOT NULL; + +update `ospos_sales` + set `sale_type` = '2', `work_order_number` = `quote_number` + where quote_number IS NOT NULL; + +update `ospos_sales` + set `sale_type` = '1' where invoice_number IS NOT NULL; diff --git a/database/database.sql b/database/database.sql index a04f1e56f..92268bbd6 100644 --- a/database/database.sql +++ b/database/database.sql @@ -111,9 +111,10 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('gcaptcha_enable', '0'), ('gcaptcha_secret_key', ''), ('gcaptcha_site_key', ''), -('receiving_calculate_average_price', '0'); - - +('receiving_calculate_average_price', '0'), +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); -- -------------------------------------------------------- -- @@ -563,6 +564,8 @@ CREATE TABLE `ospos_sales` ( `sale_id` int(10) NOT NULL AUTO_INCREMENT, `sale_status` tinyint(2) NOT NULL DEFAULT 0, `dinner_table_id` int(11) NULL, + `work_order_number` varchar(32) DEFAULT NULL, + `sale_type` tinyint(2) NOT NULL DEFAULT 0, PRIMARY KEY (`sale_id`), KEY `customer_id` (`customer_id`), KEY `employee_id` (`employee_id`), diff --git a/database/tables.sql b/database/tables.sql index a7fffb2a4..bbf4c6e37 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -111,7 +111,11 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('gcaptcha_enable', '0'), ('gcaptcha_secret_key', ''), ('gcaptcha_site_key', ''), -('receiving_calculate_average_price', '0'); +('receiving_calculate_average_price', '0'), +('work_order_enable', '0'), +('work_order_format', 'W%y{WSEQ:6}'), +('last_used_work_order_number', '0'); + -- -------------------------------------------------------- @@ -565,6 +569,8 @@ CREATE TABLE `ospos_sales` ( `sale_id` int(10) NOT NULL AUTO_INCREMENT, `sale_status` tinyint(2) NOT NULL DEFAULT 0, `dinner_table_id` int(11) NULL, + `work_order_number` varchar(32) DEFAULT NULL, + `sale_type` tinyint(2) NOT NULL DEFAULT 0, PRIMARY KEY (`sale_id`), KEY `customer_id` (`customer_id`), KEY `employee_id` (`employee_id`), From 4036caf8296199c5aa07b934b0ba2a3e417119d4 Mon Sep 17 00:00:00 2001 From: FrancescoUK Date: Mon, 4 Sep 2017 22:55:45 +0100 Subject: [PATCH 11/12] Add en_GB translations to backoffice feature (#1543 #1539) --- application/language/en-GB/config_lang.php | 4 ++ application/language/en-GB/module_lang.php | 4 ++ application/language/en-GB/sales_lang.php | 13 +++- database/database.sql | 5 ++ database/migrate_phppos_dist.sql | 73 +++++++++++++--------- 5 files changed, 69 insertions(+), 30 deletions(-) diff --git a/application/language/en-GB/config_lang.php b/application/language/en-GB/config_lang.php index e500d2423..e1902e15e 100644 --- a/application/language/en-GB/config_lang.php +++ b/application/language/en-GB/config_lang.php @@ -142,6 +142,7 @@ $lang["config_jsprintsetup_required"] = "Warning! This disabled functionality wi $lang["config_language"] = "Language"; $lang["config_last_used_invoice_number"] = "Last Used Invoice Number"; $lang["config_last_used_quote_number"] = "Last Used Quote Number"; +$lang["config_last_used_work_order_number"] = "Last Used W/O Number"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; @@ -225,6 +226,7 @@ $lang["config_sales_invoice_format"] = "Sales Invoice Format"; $lang["config_sales_quote_format"] = "Sales Quote Format"; $lang["config_saved_successfully"] = "Configuration saved successfully"; $lang["config_saved_unsuccessfully"] = "Configuration saved unsuccessfully"; +$lang["config_show_office_group"] = "Show office icon"; $lang["config_statistics"] = "Send Statistics"; $lang["config_statistics_tooltip"] = "Send statistics for development and feature improvement purposes"; $lang["config_stock_location"] = "Stock location"; @@ -245,3 +247,5 @@ $lang["config_thousands_separator"] = "Thousands Separator"; $lang["config_timezone"] = "Timezone"; $lang["config_top"] = "Top"; $lang["config_website"] = "Website"; +$lang["config_work_order_enable"] = "Work Order Support"; +$lang["config_work_order_format"] = "Work Order Format"; diff --git a/application/language/en-GB/module_lang.php b/application/language/en-GB/module_lang.php index fc6b555f7..8ef821048 100644 --- a/application/language/en-GB/module_lang.php +++ b/application/language/en-GB/module_lang.php @@ -1,5 +1,6 @@ Date: Thu, 7 Sep 2017 22:06:15 +0100 Subject: [PATCH 12/12] Add CSRF issue with suhosin to FAQ with link to #1492 --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e3c35bd5..205b2ae84 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The main features are: 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. The latest 3.x version is a complete overhaul of the original software. -It is now based on Bootstrap 3.x using Bootswatch themes, and still uses CodeIgniter 3.x as framework. +It is now based on Bootstrap 3 using Bootswatch themes, and still uses CodeIgniter 3 as framework. It also has improved functionality and security. Deployed to a Cloud it's a SaaS (Software as a Service) solution. @@ -105,6 +105,7 @@ Local install 9. Enjoy 10. Oops an issue? Please make sure you read the FAQ, wiki page and you checked open and closed issue on GitHub. PHP display_errors is disabled by default. Create an application/config/.env file from the .env.example to enable it in a development environment. + Local install using Docker -------------------------- @@ -185,3 +186,5 @@ FAQ * If the avatar pictures are not shown in Items or at Item save time you get an error, please make sure your public and subdirs are assigned to the correct owner and the access permission is set to 755 * If you have problems with the encryption support or you get an error please make sure `php5-mcrypt` is installed + +* If you have suhosin installed and face an issue with CSRF, please make sure you read [issue #1492](https://github.com/jekkos/opensourcepos/issues/1492)