From df61ee09bb8fef8189ed85b10c94e832e45000c0 Mon Sep 17 00:00:00 2001 From: jekkos Date: Fri, 22 Sep 2017 22:12:58 +0200 Subject: [PATCH] Add item attributes functionality (#68) --- application/config/autoload.php | 2 +- application/controllers/Attributes.php | 195 +++++++++ application/controllers/Config.php | 12 +- application/controllers/Items.php | 55 +-- application/helpers/tabular_helper.php | 30 ++ .../language/ar-EG/attributes_lang.php | 25 ++ application/language/ar-EG/config_lang.php | 10 - application/language/ar-EG/items_lang.php | 1 - application/language/ar-EG/module_lang.php | 2 + .../language/az-AZ/attributes_lang.php | 25 ++ application/language/az-AZ/config_lang.php | 8 - application/language/az-AZ/items_lang.php | 1 - application/language/az-AZ/module_lang.php | 2 + .../language/de-CH/attributes_lang.php | 25 ++ application/language/de-CH/config_lang.php | 10 - application/language/de-CH/items_lang.php | 1 - application/language/de-CH/module_lang.php | 2 + application/language/de/attributes_lang.php | 25 ++ application/language/de/module_lang.php | 2 + .../language/en-GB/attributes_lang.php | 25 ++ application/language/en-GB/config_lang.php | 10 - application/language/en-GB/items_lang.php | 1 - .../language/en-US/attributes_lang.php | 25 ++ application/language/en-US/config_lang.php | 10 - application/language/en-US/items_lang.php | 1 - application/language/en/attributes_lang.php | 25 ++ application/language/es/attributes_lang.php | 25 ++ application/language/es/config_lang.php | 10 - application/language/es/items_lang.php | 1 - application/language/es/module_lang.php | 2 + application/language/fr/attributes_lang.php | 25 ++ application/language/fr/config_lang.php | 10 - application/language/fr/items_lang.php | 1 - application/language/fr/module_lang.php | 1 + .../language/hr-HR/attributes_lang.php | 25 ++ application/language/hr-HR/config_lang.php | 10 - application/language/hr-HR/items_lang.php | 3 +- application/language/hr-HR/module_lang.php | 2 + .../language/hu-HU/attributes_lang.php | 25 ++ application/language/hu-HU/config_lang.php | 10 - application/language/hu-HU/items_lang.php | 3 +- application/language/hu-HU/module_lang.php | 2 + application/language/id/attributes_lang.php | 25 ++ application/language/id/datepicker_lang.php | 1 + .../language/nl-BE/attributes_lang.php | 25 ++ application/language/nl-BE/items_lang.php | 1 - application/language/nl-BE/module_lang.php | 1 + .../language/pt-BR/attributes_lang.php | 25 ++ application/language/ru/attributes_lang.php | 25 ++ application/language/ru/config_lang.php | 10 - application/language/ru/items_lang.php | 1 - application/language/ru/module_lang.php | 2 + application/language/sv/attributes_lang.php | 25 ++ application/language/sv/config_lang.php | 10 - application/language/sv/items_lang.php | 1 - application/language/sv/module_lang.php | 2 + application/language/th/attributes_lang.php | 25 ++ application/language/th/config_lang.php | 10 - application/language/th/items_lang.php | 3 +- application/language/th/module_lang.php | 2 + application/language/tr/attributes_lang.php | 25 ++ application/language/tr/config_lang.php | 10 - application/language/tr/items_lang.php | 3 +- application/language/tr/module_lang.php | 2 + application/language/zh/attributes_lang.php | 25 ++ application/language/zh/config_lang.php | 10 - application/language/zh/items_lang.php | 3 +- application/language/zh/module_lang.php | 2 + application/libraries/Receiving_lib.php | 7 +- application/libraries/Sale_lib.php | 8 +- .../migrations/20180220100000_attributes.php | 20 + .../migrations/sqlscripts/attributes.sql | 184 ++++++++ application/models/Attribute.php | 408 ++++++++++++++++++ application/models/Item.php | 104 ++--- application/models/Item_kit.php | 14 +- application/models/Receiving.php | 4 +- application/models/Sale.php | 18 +- .../models/reports/Detailed_receivings.php | 6 +- application/views/attributes/form.php | 173 ++++++++ application/views/attributes/item.php | 69 +++ application/views/attributes/manage.php | 37 ++ application/views/configs/general_config.php | 110 ----- application/views/items/form.php | 361 ++++++++-------- application/views/partial/header.php | 6 +- application/views/receivings/receipt.php | 2 +- application/views/receivings/receiving.php | 2 +- application/views/sales/invoice.php | 2 +- application/views/sales/receipt_default.php | 2 +- application/views/sales/receipt_email.php | 2 +- application/views/sales/receipt_short.php | 2 +- application/views/sales/register.php | 2 +- bower.json | 3 + database/3.0_to_attributes.sql | 191 ++++++++ database/3.1.0_to_attributes.sql | 191 ++++++++ database/constraints.sql | 18 +- database/tables.sql | 82 +++- design/ospos_categories.mwb | Bin 29876 -> 30219 bytes design/ospos_categories.mwb.bak | Bin 0 -> 30114 bytes import_items.csv | 4 +- license/.licenses | 28 ++ public/images/menubar/attributes.png | Bin 0 -> 1529 bytes 101 files changed, 2397 insertions(+), 622 deletions(-) create mode 100644 application/controllers/Attributes.php create mode 100644 application/language/ar-EG/attributes_lang.php create mode 100644 application/language/az-AZ/attributes_lang.php create mode 100644 application/language/de-CH/attributes_lang.php create mode 100644 application/language/de/attributes_lang.php create mode 100644 application/language/en-GB/attributes_lang.php create mode 100644 application/language/en-US/attributes_lang.php create mode 100644 application/language/en/attributes_lang.php create mode 100644 application/language/es/attributes_lang.php create mode 100644 application/language/fr/attributes_lang.php create mode 100644 application/language/hr-HR/attributes_lang.php create mode 100644 application/language/hu-HU/attributes_lang.php create mode 100644 application/language/id/attributes_lang.php create mode 100644 application/language/nl-BE/attributes_lang.php create mode 100644 application/language/pt-BR/attributes_lang.php create mode 100644 application/language/ru/attributes_lang.php create mode 100644 application/language/sv/attributes_lang.php create mode 100644 application/language/th/attributes_lang.php create mode 100644 application/language/tr/attributes_lang.php create mode 100644 application/language/zh/attributes_lang.php create mode 100644 application/migrations/20180220100000_attributes.php create mode 100644 application/migrations/sqlscripts/attributes.sql create mode 100644 application/models/Attribute.php create mode 100644 application/views/attributes/form.php create mode 100644 application/views/attributes/item.php create mode 100644 application/views/attributes/manage.php create mode 100644 database/3.0_to_attributes.sql create mode 100644 database/3.1.0_to_attributes.sql create mode 100644 design/ospos_categories.mwb.bak create mode 100644 license/.licenses create mode 100644 public/images/menubar/attributes.png diff --git a/application/config/autoload.php b/application/config/autoload.php index a7b554177..d6a82548b 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -132,4 +132,4 @@ $autoload['language'] = array(); | | $autoload['model'] = array('first_model' => 'first'); */ -$autoload['model'] = array('Appconfig', 'Person', 'Customer', 'Employee', 'Module', 'Item', 'Item_taxes', 'Sale', 'Supplier', 'Inventory', 'Receiving', 'Giftcard', 'Item_kit', 'Item_kit_items', 'Stock_location', 'Item_quantity', 'Dinner_table', 'Customer_rewards', 'Rewards', 'Tax', 'Expense_category', 'Expense', 'Cashup'); +$autoload['model'] = array('Appconfig', 'Person', 'Customer', 'Employee', 'Module', 'Item', 'Item_taxes', 'Sale', 'Supplier', 'Inventory', 'Receiving', 'Giftcard', 'Item_kit', 'Item_kit_items', 'Stock_location', 'Item_quantity', 'Dinner_table', 'Customer_rewards', 'Rewards', 'Tax', 'Expense_category', 'Expense', 'Cashup', 'Attribute'); diff --git a/application/controllers/Attributes.php b/application/controllers/Attributes.php new file mode 100644 index 000000000..e7557cd55 --- /dev/null +++ b/application/controllers/Attributes.php @@ -0,0 +1,195 @@ +xss_clean(get_attribute_definition_manage_table_headers()); + + $this->load->view('attributes/manage', $data); + } + + /* + Returns customer table data rows. This will be called with AJAX. + */ + public function search() + { + $search = $this->input->get('search'); + $limit = $this->input->get('limit'); + $offset = $this->input->get('offset'); + $sort = $this->input->get('sort'); + $order = $this->input->get('order'); + + $attributes = $this->Attribute->search($search, $limit, $offset, $sort, $order); + $total_rows = $this->Attribute->get_found_rows($search); + + $data_rows = array(); + foreach($attributes->result() as $attribute) + { + $attribute->definition_flags = $this->_get_attributes($attribute->definition_flags); + $data_rows[] = get_attribute_definition_data_row($attribute, $this); + } + + $data_rows = $this->xss_clean($data_rows); + + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); + } + + public function save_attribute_link($item_id) + { + if (!empty($this->input->post('attribute_id'))) + { + $success = $this->Attribute->save_link($item_id, $this->input->post('definition_id'), $this->input->post('attribute_id')); + } + else + { + $success = $this->Attribute->set_selected_category($item_id, $this->input->post('definition_id')); + } + + echo json_encode(array('success' => $success)); + } + + public function delete_attribute_link($item_id) + { + $success = $this->Attribute->delete_link($item_id); + + echo json_encode(array('success' => $success)); + } + + public function save_attribute_value($attribute_value) + { + $success = $this->Attribute->save_value($attribute_value, $this->input->post('definition_id'), $this->input->post('item_id'), $this->input->post('attribute_id')); + + echo json_encode(array('success' => $success)); + } + + public function delete_attribute_value($attribute_value) + { + $success = $this->Attribute->delete_value($attribute_value, $this->input->post('$definition_id')); + + echo json_encode(array('success' => $success)); + } + + public function save_definition($definition_id = -1) + { + $definition_flags = 0; + foreach($this->input->post('definition_flags') as $flag) + { + $definition_flags |= $flag; + } + + //Save definition data + $definition_data = array( + 'definition_name' => $this->input->post('definition_name'), + 'definition_type' => DEFINITION_TYPES[$this->input->post('definition_type')], + 'definition_flags' => $definition_flags, + 'definition_fk' => $this->input->post('definition_parent') != '' ? $this->input->post('definition_parent') : NULL + ); + + $definition_name = $this->xss_clean($definition_data['definition_name']); + + if($this->Attribute->save_definition($definition_data, $definition_id)) + { + //New definition + if($definition_id == -1) + { + $definition_values = json_decode($this->input->post('definition_values')); + + foreach($definition_values as $definition_value) + { + $this->Attribute->save_value($definition_value, $definition_data['definition_id']); + } + + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_adding').' '. + $definition_name, 'id' => $definition_data['definition_id'])); + } + else //Existing definition + { + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_updating').' '. + $definition_name, 'id' => $definition_id)); + } + } + else//failure + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attribute_definitions_error_adding_updating').' '. + $definition_name, 'id' => -1)); + } + } + + public function suggest_attribute($definition_id) + { + $suggestions = $this->xss_clean($this->Attribute->get_suggestions($definition_id, $this->input->get('term'))); + + echo json_encode($suggestions); + } + + public function get_row($row_id) + { + $attribute_definition_info = $this->Attribute->get_info($row_id); + $attribute_definition_info->definition_flags = $this->_get_attributes($attribute_definition_info->definition_flags); + $data_row = $this->xss_clean(get_attribute_definition_data_row($attribute_definition_info)); + + echo json_encode($data_row); + } + + private function _get_attributes($definition_flags = 0) + { + $definition_flag_names = array(); + foreach (Attribute::get_definition_flags() as $id => $term) + { + if (empty($definition_flags) || ($id & $definition_flags)) + { + $definition_flag_names[$id] = $this->lang->line('attributes_' . strtolower($term) . '_visibility'); + } + } + return $definition_flag_names; + } + + public function view($definition_id = -1) + { + $info = $this->Attribute->get_info($definition_id); + foreach(get_object_vars($info) as $property => $value) + { + $info->$property = $this->xss_clean($value); + } + + $data['definition_id'] = $definition_id; + $data['definition_values'] = $this->Attribute->get_definition_values($definition_id); + $data['definition_parent'] = $this->Attribute->get_definitions_by_type(CATEGORY, $definition_id); + $data['definition_parent'][''] = $this->lang->line('common_none_selected_text'); + $data['definition_info'] = $info; + + $data['definition_flags'] = $this->_get_attributes(); + $data['selected_definition_flags'] = $this->_get_attributes($info->definition_flags); + + $this->load->view("attributes/form", $data); + } + + public function delete_value($attribute_id) + { + return $this->Attribute->delete_value($attribute_id); + } + + public function delete() + { + $attributes_to_delete = $this->input->post('ids'); + + if($this->Attribute->delete_definition_list($attributes_to_delete)) + { + $message = $this->lang->line('attributes_definition_successful_deleted') . ' ' . count($attributes_to_delete) . ' ' . $this->lang->line('attributes_definition_one_or_multiple'); + echo json_encode(array('success' => TRUE, 'message' => $message)); + } + else + { + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attributes_definition_cannot_be_deleted'))); + } + } + +} \ No newline at end of file diff --git a/application/controllers/Config.php b/application/controllers/Config.php index 6bc838c7e..72855b6a1 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -299,18 +299,8 @@ class Config extends Secure_Controller 'suggestions_second_column' => $this->input->post('suggestions_second_column'), 'suggestions_third_column' => $this->input->post('suggestions_third_column'), 'giftcard_number' => $this->input->post('giftcard_number'), - 'derive_sale_quantity' => $this->input->post('derive_sale_quantity') != NULL, + 'derive_sale_quantity' => $this->input->post('derive_sale_quantity') != NULL 'multi_pack_enabled' => $this->input->post('multi_pack_enabled') != NULL, - 'custom1_name' => $this->input->post('custom1_name'), - 'custom2_name' => $this->input->post('custom2_name'), - 'custom3_name' => $this->input->post('custom3_name'), - 'custom4_name' => $this->input->post('custom4_name'), - 'custom5_name' => $this->input->post('custom5_name'), - 'custom6_name' => $this->input->post('custom6_name'), - 'custom7_name' => $this->input->post('custom7_name'), - 'custom8_name' => $this->input->post('custom8_name'), - 'custom9_name' => $this->input->post('custom9_name'), - 'custom10_name' => $this->input->post('custom10_name') ); $this->Module->set_show_office_group($this->input->post('show_office_group') != NULL); diff --git a/application/controllers/Items.php b/application/controllers/Items.php index 6a5395fb8..b445eedf7 100644 --- a/application/controllers/Items.php +++ b/application/controllers/Items.php @@ -25,7 +25,7 @@ class Items extends Secure_Controller 'low_inventory' => $this->lang->line('items_low_inventory_items'), 'is_serialized' => $this->lang->line('items_serialized_items'), 'no_description' => $this->lang->line('items_no_description_items'), - 'search_custom' => $this->lang->line('items_search_custom_items'), + 'search_custom' => $this->lang->line('items_search_attributes'), 'is_deleted' => $this->lang->line('items_is_deleted'), 'temporary' => $this->lang->line('items_temp')); @@ -164,16 +164,6 @@ class Items extends Secure_Controller echo json_encode($suggestions); } - - /* - Gives search suggestions based on what is being searched for - */ - public function suggest_custom() - { - $suggestions = $this->xss_clean($this->Item->get_custom_suggestions($this->input->post('term'), $this->input->post('field_no'))); - - echo json_encode($suggestions); - } public function get_row($item_ids) { @@ -201,6 +191,12 @@ class Items extends Secure_Controller $data['default_tax_1_rate'] = ''; $data['default_tax_2_rate'] = ''; $data['item_kits_enabled'] = $this->Employee->has_grant('item_kits', $this->Employee->get_logged_in_employee_info()->person_id); + $data['definition_values'] = $this->Attribute->get_attributes_by_item($item_id); + $categories = array(-1 => $this->lang->line('common_none_selected_text')); + $categories = $categories + $this->Attribute->get_definitions_by_type(CATEGORY); + $selected_category = $this->Attribute->get_selected_category($item_id); + $data['selected_category'] = empty($selected_category) ? NULL : $selected_category->definition_id; + $data['categories'] = $categories; $item_info = $this->Item->get_info($item_id); foreach(get_object_vars($item_info) as $property => $value) @@ -235,6 +231,7 @@ class Items extends Secure_Controller $item_info->receiving_quantity = 1; $item_info->reorder_level = 1; $item_info->item_type = ITEM; // standard + $item_info->item_id = $item_id; $item_info->stock_type = HAS_STOCK; $item_info->tax_category_id = 1; // Standard $item_info->qty_per_pack = 1; @@ -389,6 +386,13 @@ class Items extends Secure_Controller $this->load->view('barcodes/barcode_sheet', $data); } + public function attributes($item_id, $definition_id) + { + $data['item_id'] = $item_id; + $data['definition_values'] = $this->Attribute->get_values_by_parent($definition_id); + $this->load->view('attributes/item', $data); + } + public function bulk_edit() { $suppliers = array('' => $this->lang->line('items_none')); @@ -444,17 +448,7 @@ class Items extends Secure_Controller 'qty_per_pack' => $this->input->post('qty_per_pack') == NULL ? 1 : $this->input->post('qty_per_pack'), 'pack_name' => $this->input->post('pack_name') == NULL ? $default_pack_name : $this->input->post('pack_name'), 'low_sell_item_id' => $this->input->post('low_sell_item_id') == NULL ? -1 : $this->input->post('low_sell_item_id'), - 'deleted' => $this->input->post('is_deleted') != NULL, - 'custom1' => $this->input->post('custom1') == NULL ? '' : $this->input->post('custom1'), - 'custom2' => $this->input->post('custom2') == NULL ? '' : $this->input->post('custom2'), - 'custom3' => $this->input->post('custom3') == NULL ? '' : $this->input->post('custom3'), - 'custom4' => $this->input->post('custom4') == NULL ? '' : $this->input->post('custom4'), - 'custom5' => $this->input->post('custom5') == NULL ? '' : $this->input->post('custom5'), - 'custom6' => $this->input->post('custom6') == NULL ? '' : $this->input->post('custom6'), - 'custom7' => $this->input->post('custom7') == NULL ? '' : $this->input->post('custom7'), - 'custom8' => $this->input->post('custom8') == NULL ? '' : $this->input->post('custom8'), - 'custom9' => $this->input->post('custom9') == NULL ? '' : $this->input->post('custom9'), - 'custom10' => $this->input->post('custom10') == NULL ? '' : $this->input->post('custom10') + 'deleted' => $this->input->post('is_deleted') != NULL ); if($item_data['item_type'] == ITEM_TEMP) @@ -748,8 +742,7 @@ class Items extends Secure_Controller // XSS file data sanity check $data = $this->xss_clean($data); - /* haven't touched this so old templates will work, or so I guess... */ - if(sizeof($data) >= 23) + if(sizeof($data) >= 18) { $item_data = array( 'name' => $data[1], @@ -760,17 +753,7 @@ class Items extends Secure_Controller 'reorder_level' => $data[10], 'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : NULL, 'allow_alt_description' => $data[12] != '' ? '1' : '0', - 'is_serialized' => $data[13] != '' ? '1' : '0', - 'custom1' => $data[14], - 'custom2' => $data[15], - 'custom3' => $data[16], - 'custom4' => $data[17], - 'custom5' => $data[18], - 'custom6' => $data[19], - 'custom7' => $data[20], - 'custom8' => $data[21], - 'custom9' => $data[22], - 'custom10' => $data[23] + 'is_serialized' => $data[13] != '' ? '1' : '0' ); /* we could do something like this, however, the effectiveness of @@ -778,7 +761,7 @@ class Items extends Secure_Controller into that directory, so you really can do whatever you want, this probably needs further discussion */ - $pic_file = $data[24]; + $pic_file = $data[19]; /*if(strcmp('.htaccess', $pic_file)==0) { $pic_file=''; diff --git a/application/helpers/tabular_helper.php b/application/helpers/tabular_helper.php index 770037081..041115e5e 100644 --- a/application/helpers/tabular_helper.php +++ b/application/helpers/tabular_helper.php @@ -523,6 +523,36 @@ function get_item_kit_data_row($item_kit) )); } +function get_attribute_definition_manage_table_headers() +{ + $CI =& get_instance(); + + $headers = array( + array('definition_id' => $CI->lang->line('attributes_definition_id')), + array('definition_name' => $CI->lang->line('attributes_definition_name')), + array('definition_type' => $CI->lang->line('attributes_definition_type')), + array('definition_flags' => $CI->lang->line('attributes_definition_flags')), + array('category' => $CI->lang->line('attributes_category')), + ); + + return transform_headers($headers); +} + +function get_attribute_definition_data_row($attribute) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + + return array ( + 'definition_id' => $attribute->definition_id, + 'definition_name' => $attribute->definition_name, + 'definition_type' => $attribute->definition_type, + 'category' => $attribute->parent_name, + 'definition_flags' => count($attribute->definition_flags) == 0 ? $CI->lang->line('common_none_selected_text') : implode(', ', $attribute->definition_flags), + 'edit' => anchor("$controller_name/view/$attribute->definition_id", '', + array('class'=>'modal-dlg', 'data-btn-submit' => $CI->lang->line('common_submit'), 'title'=>$CI->lang->line($controller_name.'_update')) + )); +} /* Get the header for the expense categories tabular view diff --git a/application/language/ar-EG/attributes_lang.php b/application/language/ar-EG/attributes_lang.php new file mode 100644 index 000000000..00229b05e --- /dev/null +++ b/application/language/ar-EG/attributes_lang.php @@ -0,0 +1,25 @@ +CI->session->unset_userdata('recv_stock_destination'); } - public function add_item($item_id, $quantity = 1, $item_location = NULL, $discount_type = 0, $discount = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $receiving_quantity = NULL, $include_deleted = FALSE) + public function add_item($item_id, $quantity = 1, $item_location = NULL, $discount_type = 0, $discount = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $receiving_quantity = NULL, $receiving_id = NULL, $include_deleted = FALSE) { //make sure item exists in database. if(!$this->CI->Item->exists($item_id, $include_deleted)) @@ -240,6 +240,7 @@ class Receiving_lib 'name' => $item_info->name, 'description' => $description != NULL ? $description: $item_info->description, 'serialnumber' => $serialnumber != NULL ? $serialnumber: '', + 'attribute_values' => $this->CI->Attribute->get_link_values($item_id, 'receiving_id', $receiving_id, Attribute::SHOW_IN_RECEIVINGS)->attribute_values, 'allow_alt_description' => $item_info->allow_alt_description, 'is_serialized' => $item_info->is_serialized, 'quantity' => $quantity, @@ -319,7 +320,7 @@ class Receiving_lib foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) { - $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_type, $row->discount, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, TRUE); + $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_type, $row->discount, $row->item_unit_price, $row->description, $row->serialnumber, $receiving_id, $row->receiving_quantity, TRUE); } $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); @@ -344,7 +345,7 @@ class Receiving_lib foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_type, $row->discount, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, TRUE); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_type, $row->discount, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, TRUE); } $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php index 8ecd6fcb3..5db5b995d 100644 --- a/application/libraries/Sale_lib.php +++ b/application/libraries/Sale_lib.php @@ -696,10 +696,9 @@ class Sale_lib $this->CI->session->unset_userdata('sales_rewards_remainder'); } - public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0, $discount_type = 0, $price_mode = PRICE_MODE_STANDARD, $kit_price_option = NULL, $kit_print_option = NULL, $price_override = NULL, $description = NULL, $serialnumber = NULL, $include_deleted = FALSE, $print_option = NULL ) + public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0, $discount_type = 0, $price_mode = PRICE_MODE_STANDARD, $kit_price_option = NULL, $kit_print_option = NULL, $price_override = NULL, $description = NULL, $serialnumber = NULL, $sale_id = NULL, $include_deleted = FALSE, $print_option = NULL ) { $item_info = $this->CI->Item->get_info_by_id_or_number($item_id, $include_deleted); - //make sure item exists if(empty($item_info)) { @@ -844,6 +843,7 @@ class Sale_lib 'line' => $insertkey, 'name' => $item_info->name, 'item_number' => $item_info->item_number, + 'attribute_values' => $this->CI->Attribute->get_link_values($item_id, 'sale_id', $sale_id, Attribute::SHOW_IN_SALES)->attribute_values, 'description' => $description != NULL ? $description : $item_info->description, 'serialnumber' => $serialnumber != NULL ? $serialnumber : '', 'allow_alt_description' => $item_info->allow_alt_description, @@ -1019,7 +1019,7 @@ class Sale_lib foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, TRUE, $row->print_option); } foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row) @@ -1047,7 +1047,7 @@ class Sale_lib $this->empty_cart(); foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, TRUE, $row->print_option); } return $this->CI->session->userdata('sales_cart'); diff --git a/application/migrations/20180220100000_attributes.php b/application/migrations/20180220100000_attributes.php new file mode 100644 index 000000000..521e7b15d --- /dev/null +++ b/application/migrations/20180220100000_attributes.php @@ -0,0 +1,20 @@ + diff --git a/application/migrations/sqlscripts/attributes.sql b/application/migrations/sqlscripts/attributes.sql new file mode 100644 index 000000000..35e8d6ba1 --- /dev/null +++ b/application/migrations/sqlscripts/attributes.sql @@ -0,0 +1,184 @@ + +CREATE TABLE IF NOT EXISTS `ospos_attribute_definitions` ( + `definition_id` INT(10) NOT NULL AUTO_INCREMENT, + `definition_name` VARCHAR(255) NOT NULL, + `definition_type` VARCHAR(45) NOT NULL, + `definition_flags` TINYINT(4) NOT NULL, + `definition_fk` INT(10) NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`definition_id`), + KEY `definition_fk` (`definition_fk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_values` ( + `attribute_id` INT NOT NULL AUTO_INCREMENT, + `attribute_value` VARCHAR(45) NULL, + PRIMARY KEY (`attribute_id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_links` ( + `attribute_id` INT NULL, + `definition_id` INT NOT NULL, + `item_id` INT NULL, + `sale_id` INT NULL, + `receiving_id` INT NULL, + KEY `attribute_id` (`attribute_id`), + KEY `definition_id` (`definition_id`), + KEY `item_id` (`item_id`), + KEY `sale_id` (`sale_id`), + KEY `receiving_id` (`receiving_id`), + UNIQUE `attribute_links_uq1` (`attribute_id`, `definition_id`, `item_id`, `sale_id`, `receiving_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +ALTER TABLE `ospos_attribute_definitions` + ADD CONSTRAINT `fk_ospos_attribute_definitions_ibfk_1` FOREIGN KEY (`definition_fk`) REFERENCES `ospos_attribute_definitions` (`definition_id`); + + +ALTER TABLE `ospos_attribute_links` + ADD CONSTRAINT `ospos_attribute_links_ibfk_1` FOREIGN KEY (`definition_id`) REFERENCES `ospos_attribute_definitions` (`definition_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `ospos_attribute_values` (`attribute_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_4` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_5` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + + +UPDATE `ospos_modules` SET `sort` = 120 WHERE `name_lang_key` = 'module_config'; + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES + ('module_attributes', 'module_attributes_desc', 110, 'attributes'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES + ('attributes', 'attributes'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES + ('attributes', 1, 'office'); + +-- migrate custom fields to text attributes +-- NOTE: items with custom attributes won't keep their selected category!! +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom1_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom2_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom3_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom4_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom5_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom6_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom7_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom8_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom9_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom10_name'; + +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom1_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom1 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom2_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom2 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom3_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom3 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom4_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom4 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom5_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom5 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom6_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom6 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom7_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom7 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom8_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom8 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom9_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom9 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom10_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom10 IS NOT NULL; + +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom1 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom2 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom3 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom4 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom5 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom6 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom7 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom8 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom9 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom10 FROM ospos_items; + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom1 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom1_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom2 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom2_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom3 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom3_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom4 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom4_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom5 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom5_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom6 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom6_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom7 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom7_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom8 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom8_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom9 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom9_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom10 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom10_name')); + +ALTER TABLE `ospos_items` + DROP COLUMN `custom1`, + DROP COLUMN `custom2`, + DROP COLUMN `custom3`, + DROP COLUMN `custom4`, + DROP COLUMN `custom5`, + DROP COLUMN `custom6`, + DROP COLUMN `custom7`, + DROP COLUMN `custom8`, + DROP COLUMN `custom9`, + DROP COLUMN `custom10`; \ No newline at end of file diff --git a/application/models/Attribute.php b/application/models/Attribute.php new file mode 100644 index 000000000..a8975a1a8 --- /dev/null +++ b/application/models/Attribute.php @@ -0,0 +1,408 @@ +getConstants()); + } + + /* + Determines if a given definition_id is an attribute + */ + public function exists($definition_id, $deleted = FALSE) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_id', $definition_id); + $this->db->where('deleted', $deleted); + + return ($this->db->get()->num_rows() == 1); + } + + public function link_exists($item_id, $definition_id = FALSE) + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->from('attribute_links'); + if (empty($definition_id)) + { + $this->db->where('definition_id <>'); + $this->db->where('attribute_id'); + } + else + { + $this->db->where('definition_id', $definition_id); + + } + $this->db->where('item_id', $item_id); + return $this->db->get()->num_rows() > 0; + } + + /* + Gets information about a particular attribute definition + */ + public function get_info($definition_id) + { + $this->db->select('parent_definition.definition_name AS parent_name, definition.*'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left'); + $this->db->where('definition.definition_id', $definition_id); + + $query = $this->db->get(); + + if($query->num_rows() == 1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $item_id is NOT an item + $item_obj = new stdClass(); + + //Get all the fields from items table + foreach($this->db->list_fields('attribute_definitions') as $field) + { + $item_obj->$field = ''; + } + + return $item_obj; + } + } + + /* + Performs a search on attribute definitions + */ + public function search($search, $rows = 0, $limit_from = 0, $sort = 'definition.definition_name', $order = 'asc') + { + $this->db->select('parent_definition.definition_name AS parent_name, definition.*'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left'); + + $this->db->group_start(); + $this->db->like('definition.definition_name', $search); + $this->db->or_like('definition.definition_type', $search); + $this->db->group_end(); + $this->db->where('definition.deleted', 0); + $this->db->order_by($sort, $order); + + if($rows > 0) + { + $this->db->limit($rows, $limit_from); + } + + return $this->db->get(); + } + + public function get_attributes_by_item($item_id) + { + $this->db->from('attribute_definitions'); + $this->db->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id'); + $this->db->where('item_id', $item_id); + $this->db->where('deleted', 0); + + return $this->db->get()->result_array(); + } + + public function get_values_by_parent($definition_fk) + { + $this->db->from('attribute_definitions'); + if ($definition_fk != -1) + { + $this->db->where('definition_fk', $definition_fk); + } + else + { + $this->db->where('definition_fk'); + } + $this->db->where('deleted', 0); + + return $this->db->get()->result_array(); + } + + public function get_definitions_by_type($attribute_type, $definition_id = -1) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_type', $attribute_type); + $this->db->where('deleted', 0); + + if ($definition_id != -1) + { + $this->db->where('definition_id != ', $definition_id); + } + + $this->db->where('definition_fk'); + $results = $this->db->get()->result_array(); + + $attribute_definitions = array(); + foreach($results as $result) + { + $attribute_definitions[$result['definition_id']] = $result['definition_name']; + } + return $attribute_definitions; + } + + public function get_definition_values($definition_id) + { + $attribute_values = []; + + if ($definition_id > -1) + { + $this->db->from('attribute_links'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->where('definition_id', $definition_id); + $this->db->where('item_id'); + + $results = $this->db->get()->result_array(); + + $attribute_definitions = array(); + foreach($results as $result) + { + $attribute_definitions[$result['attribute_id']] = $result['attribute_value']; + } + return $attribute_definitions; + } + return $attribute_values; + } + + /* + Gets total of rows + */ + public function get_total_rows() + { + $this->db->from('attribute_definitions'); + $this->db->where('deleted', 0); + + return $this->db->count_all_results(); + } + + /* + Get number of rows + */ + public function get_found_rows($search) + { + return $this->search($search)->num_rows(); + } + + /* + Inserts or updates a definition + */ + public function save_definition(&$definition_data, $definition_id = -1) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + if($definition_id === -1 || !$this->exists($definition_id)) + { + $success = $this->db->insert('attribute_definitions', $definition_data); + $definition_data['definition_id'] = $this->db->insert_id(); + } + else + { + $this->db->where('definition_id', $definition_id); + $success = $this->db->update('attribute_definitions', $definition_data); + $definition_data['definition_id'] = $definition_id; + } + + $this->db->trans_complete(); + + $success &= $this->db->trans_status(); + + return $success; + } + + public function get_definition_by_name($definition_name, $definition_type) + { + $this->db->from('attribute_definitions'); + $this->db->where('definition_name', $definition_name); + $this->db->where('definition_type', $definition_type); + return $this->db->get()->row_object(); + } + + public function save_link($item_id, $definition_id, $attribute_id) + { + $this->db->trans_start(); + if ($this->link_exists($item_id, $definition_id)) + { + $this->db->where('definition_id', $definition_id); + $this->db->where('item_id', $item_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->update('attribute_links', array('attribute_id' => $attribute_id)); + } + else + { + $this->db->insert('attribute_links', array('attribute_id' => $attribute_id, 'item_id' => $item_id, 'definition_id' => $definition_id)); + } + + $this->db->trans_complete(); + return $this->db->trans_status(); + } + + public function delete_link($item_id) + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + return $this->db->delete('attribute_links', array('item_id' => $item_id)); + } + + public function set_selected_category($item_id, $definition_id) + { + $this->db->trans_start(); + + if ($this->link_exists($item_id)) + { + $this->db->where('item_id', $item_id); + $this->db->where('attribute_id'); + $this->db->update('attribute_links', array('definition_id' => $definition_id)); + } + else + { + $this->db->insert('attribute_links', array('item_id' => $item_id, 'definition_id' => $definition_id)); + } + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } + + public function get_selected_category($item_id) + { + $this->db->from('attribute_links'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->where('item_id', $item_id); + $this->db->where('definition_type', CATEGORY); + $this->db->where('definition_fk'); + return $this->db->get()->row(); + } + + public function get_link_value($item_id, $definition_id) + { + $this->db->where('item_id', $item_id); + $this->db->where('definition_id', $definition_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + return $this->db->get('attribute_links')->row_object(); + } + + public function get_link_values($item_id, $sale_receiving_fk, $id, $definition_flags) + { + $this->db->select('GROUP_CONCAT(attribute_value SEPARATOR ",") AS attribute_values'); + $this->db->from('attribute_links'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->where('definition_type <>', CATEGORY); + if (!empty($id)) + { + $this->db->where($sale_receiving_fk, $id); + } + else + { + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + } + $this->db->where('item_id', (int) $item_id); + $this->db->where('definition_flags & ', $definition_flags); + return $this->db->get()->row_object(); + } + + public function get_attribute_value($item_id, $definition_id) + { + $this->db->from('attribute_values'); + $this->db->join('attribute_links', 'attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->where('definition_id', $definition_id); + $this->db->where('sale_id'); + $this->db->where('receiving_id'); + $this->db->where('item_id', (int) $item_id); + return $this->db->get()->row_object(); + } + + public function copy_attribute_links($item_id, $sale_receiving_fk, $id) + { + $this->db->query( + 'INSERT INTO ospos_attribute_links (item_id, definition_id, attribute_id, ' . $sale_receiving_fk . ') + SELECT ' . $this->db->escape($item_id) . ', definition_id, attribute_id, ' . $this->db->escape($id) . ' + FROM ' . $this->db->dbprefix('attribute_links') . ' + WHERE item_id = ' . $this->db->escape($item_id) . ' AND sale_id IS NULL AND receiving_id IS NULL' + ); + } + + public function get_suggestions($definition_id, $term) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('attribute_value'); + $this->db->from('attribute_definitions AS definition'); + $this->db->join('attribute_links', 'attribute_links.definition_id = definition.definition_id'); + $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); + $this->db->like('attribute_value', $term); + $this->db->where('deleted', 0); + $this->db->where('definition.definition_id', $definition_id); + $this->db->order_by('attribute_value'); + foreach($this->db->get()->result() as $row) + { + $row_array = (array) $row; + $suggestions[] = array('label' => $row_array['attribute_value']); + } + + return $suggestions; + } + + public function save_value($attribute_value, $definition_id, $item_id = FALSE, $attribute_id = FALSE) + { + $this->db->trans_start(); + + if (empty($attribute_id) || empty($item_id)) + { + $this->db->insert('attribute_values', array('attribute_value' => $attribute_value)); + $attribute_id = $this->db->insert_id(); + + $this->db->insert('attribute_links', array( + 'attribute_id' => empty($attribute_id) ? NULL : $attribute_id, + 'item_id' => empty($item_id) ? NULL : $item_id, + 'definition_id' => $definition_id)); + } + else + { + $this->db->where('attribute_id', $attribute_id); + $this->db->update('attribute_values', array('attribute_value' => $attribute_value)); + } + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } + + public function delete_value($attribute_value, $definition_id) + { + return $this->db->query("DELETE atrv, atrl FROM " . $this->db->dbprefix('attribute_values') . " atrv, " . $this->db->dbprefix('attribute_links') . " atrl " . + "WHERE atrl.attribute_id = atrv.attribute_id AND atrv.attribute_value = " . $this->db->escape($attribute_value) . " AND atrl.definition_id = " . $this->db->escape($definition_id)); + } + + public function delete_definition($definition_id) + { + $this->db->where('definition_id', $definition_id); + + return $this->db->update('attribute_definitions', array('deleted' => 1)); + } + + public function delete_definition_list($definition_ids) + { + $this->db->where_in('definition_id', $definition_ids); + + return $this->db->update('attribute_definitions', array('deleted' => 1)); + } + + +} \ No newline at end of file diff --git a/application/models/Item.php b/application/models/Item.php index ca324bdc3..e074dd75d 100644 --- a/application/models/Item.php +++ b/application/models/Item.php @@ -130,16 +130,6 @@ class Item extends CI_Model $this->db->select('MAX(items.is_serialized) AS is_serialized'); $this->db->select('MAX(items.pack_name) AS pack_name'); $this->db->select('MAX(items.deleted) AS deleted'); - $this->db->select('MAX(items.custom1) AS custom1'); - $this->db->select('MAX(items.custom2) AS custom2'); - $this->db->select('MAX(items.custom3) AS custom3'); - $this->db->select('MAX(items.custom4) AS custom4'); - $this->db->select('MAX(items.custom5) AS custom5'); - $this->db->select('MAX(items.custom6) AS custom6'); - $this->db->select('MAX(items.custom7) AS custom7'); - $this->db->select('MAX(items.custom8) AS custom8'); - $this->db->select('MAX(items.custom9) AS custom9'); - $this->db->select('MAX(items.custom10) AS custom10'); $this->db->select('MAX(suppliers.person_id) AS person_id'); $this->db->select('MAX(suppliers.company_name) AS company_name'); @@ -190,24 +180,15 @@ class Item extends CI_Model $this->db->like('name', $search); $this->db->or_like('item_number', $search); $this->db->or_like('items.item_id', $search); + $this->db->or_like('definition_name', $search); $this->db->or_like('company_name', $search); $this->db->or_like('items.category', $search); $this->db->group_end(); } else { - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); + $this->db->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->like('attribute_value', $search); } } @@ -380,18 +361,40 @@ class Item extends CI_Model return FALSE; } + private function create_temp_table() + { + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('item_categories') . + ' (PRIMARY KEY(item_id, sale_id, receiving_id, definition_id), INDEX(item_id, sale_id, receiving_id, definition_id)) + ( + SELECT definition_name AS category, definition_type, attribute_links.item_id, + sale_id, receiving_id, attribute_links.definition_id + FROM ' . $this->db->dbprefix('attribute_links') . ' AS attribute_links + INNER JOIN ' . $this->db->dbprefix('attribute_definitions') . ' AS attribute_definitions + ON attribute_definitions.definition_id = attribute_links.definition_id AND definition_type = \'CATEGORY\' + WHERE sale_id IS NULL AND receiving_id IS NULL + )' + ); + } + /* Gets information about multiple items */ public function get_multiple_info($item_ids, $location_id) { + $this->create_temp_table(); + + $this->db->select('items.*'); + $this->db->select('company_name'); + $this->db->select('category'); + $this->db->select('quantity'); $this->db->from('items'); $this->db->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left'); $this->db->join('item_quantities', 'item_quantities.item_id = items.item_id', 'left'); + $this->db->join('item_categories', 'item_categories.item_id = items.item_id', 'left'); $this->db->where('location_id', $location_id); $this->db->where_in('items.item_id', $item_ids); - return $this->db->get(); + return $this->db->get(); } /* @@ -638,19 +641,11 @@ class Item extends CI_Model //Search by custom fields if($filters['search_custom'] != FALSE) { - $this->db->from('items'); - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); + $this->db->from('attribute_links'); + $this->db->join('attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->like('attribute_value', $search); + $this->db->where('definition_type', TEXT); $this->db->where('deleted', $filters['is_deleted']); $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later foreach($this->db->get()->result() as $row) @@ -748,20 +743,11 @@ class Item extends CI_Model //Search by custom fields if($filters['search_custom'] != FALSE) { - $this->db->from('items'); - $this->db->group_start(); - $this->db->like('custom1', $search); - $this->db->or_like('custom2', $search); - $this->db->or_like('custom3', $search); - $this->db->or_like('custom4', $search); - $this->db->or_like('custom5', $search); - $this->db->or_like('custom6', $search); - $this->db->or_like('custom7', $search); - $this->db->or_like('custom8', $search); - $this->db->or_like('custom9', $search); - $this->db->or_like('custom10', $search); - $this->db->group_end(); - $this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later + $this->db->from('attribute_links'); + $this->db->join('attribute_links.attribute_id = attribute_values.attribute_id'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); + $this->db->like('attribute_value', $search); + $this->db->where('definition_type', TEXT); $this->db->where('stock_type', '0'); // stocked items only $this->db->where('deleted', $filters['is_deleted']); foreach($this->db->get()->result() as $row) @@ -937,24 +923,6 @@ class Item extends CI_Model return $suggestions; } - public function get_custom_suggestions($search, $field_no) - { - $suggestions = array(); - $this->db->distinct(); - $this->db->select('custom'.$field_no); - $this->db->from('items'); - $this->db->like('custom'.$field_no, $search); - $this->db->where('deleted', 0); - $this->db->order_by('custom'.$field_no, 'asc'); - foreach($this->db->get()->result() as $row) - { - $row_array = (array) $row; - $suggestions[] = array('label' => $row_array['custom'.$field_no]); - } - - return $suggestions; - } - public function get_categories() { $this->db->select('category'); diff --git a/application/models/Item_kit.php b/application/models/Item_kit.php index 06c3ed9dc..15e100cb1 100644 --- a/application/models/Item_kit.php +++ b/application/models/Item_kit.php @@ -62,7 +62,7 @@ class Item_kit extends CI_Model kit_discount_type, price_option, print_option, - category, + definition_name, supplier_id, item_number, cost_price, @@ -73,21 +73,13 @@ class Item_kit extends CI_Model allow_alt_description, is_serialized, items.deleted, - custom1, - custom2, - custom3, - custom4, - custom5, - custom6, - custom7, - custom8, - custom9, - custom10, item_type, stock_type'); $this->db->from('item_kits'); $this->db->join('items', 'item_kits.item_id = items.item_id', 'left'); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id', 'left'); + $this->db->join('attribute_definitions', 'attribute_links.definition_id = attribute_definitions.definition_id AND definition_type = \'CATEGORY\'', 'left'); $this->db->where('item_kit_id', $item_kit_id); $query = $this->db->get(); diff --git a/application/models/Receiving.php b/application/models/Receiving.php index b9c87047a..02f87455c 100644 --- a/application/models/Receiving.php +++ b/application/models/Receiving.php @@ -59,7 +59,7 @@ class Receiving extends CI_Model return $this->db->update('receivings', $receiving_data); } - public function save($items, $supplier_id, $employee_id, $comment, $reference, $payment_type, $receiving_id = FALSE) + public function save($items, $supplier_id, $employee_id, $comment, $reference, $payment_type) { if(count($items) == 0) { @@ -127,6 +127,8 @@ class Receiving extends CI_Model $this->Inventory->insert($inv_data); + $this->Attribute->copy_attribute_links($item['item_id'], 'receiving_id', $receiving_id); + $supplier = $this->Supplier->get_info($supplier_id); } diff --git a/application/models/Sale.php b/application/models/Sale.php index 6a19f7fba..d23e45860 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -692,8 +692,10 @@ class Sale extends CI_Model $this->Inventory->insert($inv_data); } - // Calculate taxes and save the tax information for the sale. Return the result for printing + $this->Attribute->copy_attribute_links($item['item_id'], 'sale_id', $sale_id); + // Calculate taxes and save the tax information for the sale. Return the result for printing + $customer = $this->Customer->get_info($customer_id); if($customer_id == -1 || $customer->taxable) { if($this->config->item('tax_included')) @@ -935,14 +937,16 @@ class Sale extends CI_Model item_location, print_option, ' . $this->Item->get_item_name('name') . ', - category, + definition_name, item_type, stock_type'); $this->db->from('sales_items AS sales_items'); $this->db->join('items AS items', 'sales_items.item_id = items.item_id'); + $this->db->join('attribute_links', 'items.item_id = attribute_links.item_id AND sales_items.sale_id = attribute_links.sale_id', 'left'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id', 'left'); $this->db->where('sales_items.sale_id', $sale_id); - // Entry sequence (this will render kits in the expected sequence) + // Entry sequenate (this will render kits in the expected sequence) if($this->config->item('line_sequence') == '0') { $this->db->order_by('line', 'asc'); @@ -958,7 +962,7 @@ class Sale extends CI_Model // Group by Item Category elseif($this->config->item('line_sequence') == '2') { - $this->db->order_by('category', 'asc'); + $this->db->order_by('definition_name', 'asc'); $this->db->order_by('sales_items.description', 'asc'); $this->db->order_by('items.name', 'asc'); $this->db->order_by('items.qty_per_pack', 'asc'); @@ -1189,7 +1193,7 @@ class Sale extends CI_Model items.item_id AS item_id, MAX(' . $this->Item->get_item_name() . ') AS name, MAX(items.item_number) AS item_number, - MAX(items.category) AS category, + MAX(definition_name) AS category, MAX(items.supplier_id) AS supplier_id, MAX(sales_items.quantity_purchased) AS quantity_purchased, MAX(sales_items.item_cost_price) AS item_cost_price, @@ -1214,6 +1218,10 @@ class Sale extends CI_Model ON sales_items.sale_id = sales.sale_id INNER JOIN ' . $this->db->dbprefix('items') . ' AS items ON sales_items.item_id = items.item_id + LEFT OUTER JOIN ' . $this->db->dbprefix('attribute_links') . ' AS attribute_links + ON attribute_links.item_id = items.item_id AND attribute_links.sale_id = sales_items.sale_id + LEFT OUTER JOIN ' . $this->db->dbprefix('attribute_definitions') . ' AS attribute_definitions + ON attribute_definitions.definition_id = attribute_links.definition_id AND definition_type = \'CATEGORY\' LEFT OUTER JOIN ' . $this->db->dbprefix('sales_payments_temp') . ' AS payments ON sales_items.sale_id = payments.sale_id LEFT OUTER JOIN ' . $this->db->dbprefix('suppliers') . ' AS supplier diff --git a/application/models/reports/Detailed_receivings.php b/application/models/reports/Detailed_receivings.php index 695eb7498..c034e6962 100644 --- a/application/models/reports/Detailed_receivings.php +++ b/application/models/reports/Detailed_receivings.php @@ -97,10 +97,12 @@ class Detailed_receivings extends Report foreach($data['summary'] as $key=>$value) { - $this->db->select('name, item_number, category, quantity_purchased, serialnumber,total, discount, discount_type, item_location, receivings_items_temp.receiving_quantity'); + $this->db->select('name, item_number, category, quantity_purchased, serialnumber, total, discount, discount_type, item_location, receivings_items_temp.receiving_quantity'); $this->db->from('receivings_items_temp'); $this->db->join('items', 'receivings_items_temp.item_id = items.item_id'); - $this->db->where('receiving_id = '.$value['receiving_id']); + $this->db->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id = receivings_items_temp.receiving_id', 'left'); + $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id AND definition_type = \'CATEGORY\'', 'left'); + $this->db->where('receivings_items_temp.receiving_id', $value['receiving_id']); $data['details'][$key] = $this->db->get()->result_array(); } diff --git a/application/views/attributes/form.php b/application/views/attributes/form.php new file mode 100644 index 000000000..14a902089 --- /dev/null +++ b/application/views/attributes/form.php @@ -0,0 +1,173 @@ +
lang->line('common_fields_required_message'); ?>
+ + + +'attribute_form', 'class'=>'form-horizontal')); ?> +
+ +
+ lang->line('attributes_definition_name'), 'definition_name', array('class' => 'control-label col-xs-3')); ?> +
+ 'definition_name', + 'class'=>'form-control input-sm', + 'value'=>$definition_info->definition_name) + );?> +
+
+ +
+ lang->line('attributes_definition_type'), 'definition_type', array('class'=>'control-label col-xs-3')); ?> +
+ definition_type == CATEGORY; ?> + definition_type, DEFINITION_TYPES), 'id="definition_type" class="form-control" ' . ($disable_definition_type ? 'disabled="disabled"' : ''));?> +
+
+ +
+ lang->line('attributes_category'), 'definition_parent', array('class' => 'control-label col-xs-3')); ?> +
+ definition_fk, 'id="definition_parent" class="form-control" ' . (empty($definition_parent) ? 'disabled="disabled"' : ''));?> +
+
+ + + + + + + +
+ + + \ No newline at end of file diff --git a/application/views/attributes/item.php b/application/views/attributes/item.php new file mode 100644 index 000000000..a3dad96e5 --- /dev/null +++ b/application/views/attributes/item.php @@ -0,0 +1,69 @@ + + +
+ 'control-label col-xs-3')); ?> +
+
+ + $definition_name, + 'value' => date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($definition_value['attribute_value'])), + 'class' => 'form-control input-sm', + 'data-definition-id' => $definition_value['definition_id'], + 'readonly' => 'true')); + } + else if ($definition_value['definition_type'] == DROPDOWN) + { + $values = $this->Attribute->get_definition_values($definition_id); + $selected_value = $this->Attribute->get_link_value($item_id, $definition_id); + echo form_dropdown($definition_name, $values, (empty($selected_value) ? NULL : $selected_value->attribute_id), "class='form-control' data-definition-id='$definition_id'"); + } + else if ($definition_value['definition_type'] == TEXT) + { + $attribute_value = $this->Attribute->get_attribute_value($item_id, $definition_id); + $value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? NULL : $attribute_value->attribute_value; + $id = (empty($attribute_value) || empty($attribute_value->attribute_id)) ? NULL : $attribute_value->attribute_id; + echo form_input($definition_name, $value, "class='form-control' data-attribute-id='$id'"); + } + ?> +
+
+
+ + + + diff --git a/application/views/attributes/manage.php b/application/views/attributes/manage.php new file mode 100644 index 000000000..d36f32bda --- /dev/null +++ b/application/views/attributes/manage.php @@ -0,0 +1,37 @@ +load->view("partial/header"); ?> + + + + + +
+ +
+ +
+
+
+ +load->view("partial/footer"); ?> diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php index 129deabd7..a20fa2759 100644 --- a/application/views/configs/general_config.php +++ b/application/views/configs/general_config.php @@ -235,116 +235,6 @@ -
- lang->line('config_custom1'), 'config_custom1', array('class' => 'control-label col-xs-2')); ?> -
- 'custom1_name', - 'id' => 'custom1_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom1_name'))); ?> -
-
- -
- lang->line('config_custom2'), 'config_custom2', array('class' => 'control-label col-xs-2')); ?> -
- 'custom2_name', - 'id' => 'custom2_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom2_name'))); ?> -
-
- -
- lang->line('config_custom3'), 'config_custom3', array('class' => 'control-label col-xs-2')); ?> -
- 'custom3_name', - 'id' => 'custom3_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom3_name'))); ?> -
-
- -
- lang->line('config_custom4'), 'config_custom4', array('class' => 'control-label col-xs-2')); ?> -
- 'custom4_name', - 'id' => 'custom4_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom4_name'))); ?> -
-
- -
- lang->line('config_custom5'), 'config_custom5', array('class' => 'control-label col-xs-2')); ?> -
- 'custom5_name', - 'id' => 'custom5_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom5_name'))); ?> -
-
- -
- lang->line('config_custom6'), 'config_custom6', array('class' => 'control-label col-xs-2')); ?> -
- 'custom6_name', - 'id' => 'custom6_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom6_name'))); ?> -
-
- -
- lang->line('config_custom7'), 'config_custom7', array('class' => 'control-label col-xs-2')); ?> -
- 'custom7_name', - 'id' => 'custom7_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom7_name'))); ?> -
-
- -
- lang->line('config_custom8'), 'config_custom8', array('class' => 'control-label col-xs-2')); ?> -
- 'custom8_name', - 'id' => 'custom8_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom8_name'))); ?> -
-
- -
- lang->line('config_custom9'), 'config_custom9', array('class' => 'control-label col-xs-2')); ?> -
- 'custom9_name', - 'id' => 'custom9_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom9_name'))); ?> -
-
- -
- lang->line('config_custom10'), 'config_custom10', array('class' => 'control-label col-xs-2')); ?> -
- 'custom10_name', - 'id' => 'custom10_name', - 'class' => 'form-control input-sm', - 'value' => $this->config->item('custom10_name'))); ?> -
-
-
lang->line('config_backup_database'), 'config_backup_database', array('class' => 'control-label col-xs-2')); ?>
diff --git a/application/views/items/form.php b/application/views/items/form.php index 66303fb80..eaa360773 100644 --- a/application/views/items/form.php +++ b/application/views/items/form.php @@ -46,6 +46,10 @@
+
+ load->view('attributes/item', array('item_id' => $item_info->item_id)); ?> +
+
lang->line('items_stock_type'), 'stock_type', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> @@ -387,44 +391,20 @@
- - config->item('custom'.$i.'_name') != NULL) - { - $item_arr = (array)$item_info; - ?> -
- config->item('custom'.$i.'_name'), 'custom'.$i, array('class'=>'control-label col-xs-3')); ?> -
- 'custom'.$i, - 'id'=>'custom'.$i, - 'class'=>'form-control input-sm', - 'value'=>$item_arr['custom'.$i]) - );?> -
-
- + diff --git a/application/views/partial/header.php b/application/views/partial/header.php index 01767b8bd..b7533f8fb 100644 --- a/application/views/partial/header.php +++ b/application/views/partial/header.php @@ -77,7 +77,7 @@ - + @@ -120,7 +120,7 @@ - + @@ -141,4 +141,4 @@
- + diff --git a/application/views/receivings/receipt.php b/application/views/receivings/receipt.php index f28296538..6a87be2e6 100644 --- a/application/views/receivings/receipt.php +++ b/application/views/receivings/receipt.php @@ -78,7 +78,7 @@ { ?> - +    x diff --git a/application/views/receivings/receiving.php b/application/views/receivings/receiving.php index 516c472e3..9aa96cd6f 100644 --- a/application/views/receivings/receiving.php +++ b/application/views/receivings/receiving.php @@ -136,7 +136,7 @@ if (isset($success)) ');?> -
+
diff --git a/application/views/sales/invoice.php b/application/views/sales/invoice.php index 85ac25149..10c966700 100755 --- a/application/views/sales/invoice.php +++ b/application/views/sales/invoice.php @@ -129,7 +129,7 @@ $(document).ready(function() ?> - + diff --git a/application/views/sales/receipt_default.php b/application/views/sales/receipt_default.php index 4197e4985..9dca474ef 100644 --- a/application/views/sales/receipt_default.php +++ b/application/views/sales/receipt_default.php @@ -69,7 +69,7 @@ { ?> - + config->item('receipt_show_total_discount') ? 'total' : 'discounted_total')]); ?> diff --git a/application/views/sales/receipt_email.php b/application/views/sales/receipt_email.php index a3391193d..b1e1f67e0 100644 --- a/application/views/sales/receipt_email.php +++ b/application/views/sales/receipt_email.php @@ -64,7 +64,7 @@ { ?> - + config->item('receipt_show_total_discount') ? 'total' : 'discounted_total')]); ?> diff --git a/application/views/sales/receipt_short.php b/application/views/sales/receipt_short.php index 199bc894c..488ec532b 100644 --- a/application/views/sales/receipt_short.php +++ b/application/views/sales/receipt_short.php @@ -66,7 +66,7 @@ { ?> - + config->item('receipt_show_total_discount') ? 'total' : 'discounted_total')]); ?> diff --git a/application/views/sales/register.php b/application/views/sales/register.php index 7fde2d58c..760e1199f 100644 --- a/application/views/sales/register.php +++ b/application/views/sales/register.php @@ -156,7 +156,7 @@ if(isset($success)) ?> - +

diff --git a/bower.json b/bower.json index a8924473a..e6ab56739 100644 --- a/bower.json +++ b/bower.json @@ -46,6 +46,9 @@ "bootstrap-tagsinput": "~0.8.0", "bootstrap-toggle": "^2.2.2" }, + "resolutions": { + "jquery": "~1.12.4" + }, "overrides": { "jquery-ui": { "main": [ diff --git a/database/3.0_to_attributes.sql b/database/3.0_to_attributes.sql new file mode 100644 index 000000000..1af1970ff --- /dev/null +++ b/database/3.0_to_attributes.sql @@ -0,0 +1,191 @@ + +CREATE TABLE IF NOT EXISTS `ospos_attribute_definitions` ( + `definition_id` INT(10) NOT NULL AUTO_INCREMENT, + `definition_name` VARCHAR(255) NOT NULL, + `definition_type` VARCHAR(45) NOT NULL, + `definition_flags` TINYINT(4) NOT NULL, + `definition_fk` INT(10) NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`definition_id`), + KEY `definition_fk` (`definition_fk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_values` ( + `attribute_id` INT NOT NULL AUTO_INCREMENT, + `attribute_value` VARCHAR(45) NULL, + PRIMARY KEY (`attribute_id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_links` ( + `attribute_id` INT NULL, + `definition_id` INT NOT NULL, + `item_id` INT NULL, + `sale_id` INT NULL, + `receiving_id` INT NULL, + KEY `attribute_id` (`attribute_id`), + KEY `definition_id` (`definition_id`), + KEY `item_id` (`item_id`), + KEY `sale_id` (`sale_id`), + KEY `receiving_id` (`receiving_id`), + UNIQUE `attribute_links_uq1` (`attribute_id`, `definition_id`, `item_id`, `sale_id`, `receiving_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +ALTER TABLE `ospos_attribute_definitions` + ADD CONSTRAINT `fk_ospos_attribute_definitions_ibfk_1` FOREIGN KEY (`definition_fk`) REFERENCES `ospos_attribute_definitions` (`definition_id`); + + +ALTER TABLE `ospos_attribute_links` + ADD CONSTRAINT `ospos_attribute_links_ibfk_1` FOREIGN KEY (`definition_id`) REFERENCES `ospos_attribute_definitions` (`definition_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `ospos_attribute_values` (`attribute_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_4` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_5` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + + +UPDATE `ospos_modules` SET `sort` = 120 WHERE `name_lang_key` = 'module_config'; + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES + ('module_attributes', 'module_attributes_desc', 110, 'attributes'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES + ('attributes', 'attributes'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES + ('attributes', 1); + +-- migrate categories to attribute table +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT category, 'CATEGORY' from ospos_items; +INSERT INTO `ospos_attribute_links` (item_id, definition_id) + SELECT item_id, definition_id FROM ospos_items + JOIN ospos_attribute_definitions ON ospos_attribute_definitions.definition_name = ospos_items.category; + +-- migrate custom fields to text attributes +-- NOTE: items with custom attributes won't keep their selected category!! +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom1'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom2'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom3'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom4'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom5'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom6'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom7'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom8'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom9'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config where `key` = 'custom10'; + +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom1_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom1 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom2_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom2 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom3_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom3 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom4_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom4 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom5_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom5 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom6_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom6 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom7_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom7 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom8_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom8 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom9_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom9 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom10_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom10 IS NOT NULL; + +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom1 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom2 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom3 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom4 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom5 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom6 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom7 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom8 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom9 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT custom10 FROM ospos_items; + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom1 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom1_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom2 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom2_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom3 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom3_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom4 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom4_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom5 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom5_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom6 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom6_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom7 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom7_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom8 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom8_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom9 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom9_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom10 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom10_name')); + +ALTER TABLE `ospos_items` + DROP COLUMN `custom1`, + DROP COLUMN `custom2`, + DROP COLUMN `custom3`, + DROP COLUMN `custom4`, + DROP COLUMN `custom5`, + DROP COLUMN `custom6`, + DROP COLUMN `custom7`, + DROP COLUMN `custom8`, + DROP COLUMN `custom9`, + DROP COLUMN `custom10`, + DROP COLUMN `category`; \ No newline at end of file diff --git a/database/3.1.0_to_attributes.sql b/database/3.1.0_to_attributes.sql new file mode 100644 index 000000000..95e4dfbdb --- /dev/null +++ b/database/3.1.0_to_attributes.sql @@ -0,0 +1,191 @@ + +CREATE TABLE IF NOT EXISTS `ospos_attribute_definitions` ( + `definition_id` INT(10) NOT NULL AUTO_INCREMENT, + `definition_name` VARCHAR(255) NOT NULL, + `definition_type` VARCHAR(45) NOT NULL, + `definition_flags` TINYINT(4) NOT NULL, + `definition_fk` INT(10) NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`definition_id`), + KEY `definition_fk` (`definition_fk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_values` ( + `attribute_id` INT NOT NULL AUTO_INCREMENT, + `attribute_value` VARCHAR(45) NULL, + PRIMARY KEY (`attribute_id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE IF NOT EXISTS `ospos_attribute_links` ( + `attribute_id` INT NULL, + `definition_id` INT NOT NULL, + `item_id` INT NULL, + `sale_id` INT NULL, + `receiving_id` INT NULL, + KEY `attribute_id` (`attribute_id`), + KEY `definition_id` (`definition_id`), + KEY `item_id` (`item_id`), + KEY `sale_id` (`sale_id`), + KEY `receiving_id` (`receiving_id`), + UNIQUE `attribute_links_uq1` (`attribute_id`, `definition_id`, `item_id`, `sale_id`, `receiving_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +ALTER TABLE `ospos_attribute_definitions` + ADD CONSTRAINT `fk_ospos_attribute_definitions_ibfk_1` FOREIGN KEY (`definition_fk`) REFERENCES `ospos_attribute_definitions` (`definition_id`); + + +ALTER TABLE `ospos_attribute_links` + ADD CONSTRAINT `ospos_attribute_links_ibfk_1` FOREIGN KEY (`definition_id`) REFERENCES `ospos_attribute_definitions` (`definition_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `ospos_attribute_values` (`attribute_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_4` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_5` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + + +UPDATE `ospos_modules` SET `sort` = 120 WHERE `name_lang_key` = 'module_config'; + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES + ('module_attributes', 'module_attributes_desc', 110, 'attributes'); + +INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES + ('attributes', 'attributes'); + +INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES + ('attributes', 1); + +-- migrate categories to attribute table +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT DISTINCT category, 'CATEGORY' from ospos_items; +INSERT INTO `ospos_attribute_links` (item_id, definition_id) + SELECT item_id, definition_id FROM ospos_items + JOIN ospos_attribute_definitions ON ospos_attribute_definitions.definition_name = ospos_items.category; + +-- migrate custom fields to text attributes +-- NOTE: items with custom attributes won't keep their selected category!! +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom1_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom2_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom3_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom4_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom5_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom6_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom7_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom8_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom9_name'; +INSERT INTO `ospos_attribute_definitions` (definition_name, definition_type) SELECT `value`, 'TEXT' FROM ospos_app_config WHERE `key` = 'custom10_name'; + +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom1_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom1 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom2_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom2 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom3_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom3 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom4_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom4 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom5_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom5 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom6_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom6 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom7_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom7 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom8_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom8 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom9_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom9 IS NOT NULL; +INSERT INTO ospos_attribute_links (definition_id, item_id) SELECT definition_id, item_id FROM ospos_attribute_definitions, ospos_app_config, ospos_items + WHERE ospos_app_config.`key` = 'custom10_name' AND ospos_app_config.`value` = ospos_attribute_definitions.definition_name AND custom10 IS NOT NULL; + +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom1 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom2 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom3 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom4 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom5 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom6 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom7 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom8 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom9 FROM ospos_items; +INSERT INTO ospos_attribute_values (attribute_value) SELECT DISTINCT custom10 FROM ospos_items; + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom1 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom1_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom2 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom2_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom3 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom3_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom4 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom4_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom5 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom5_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom6 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom6_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom7 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom7_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom8 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom8_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom9 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom9_name')); + +UPDATE ospos_attribute_links + INNER JOIN ospos_items ON ospos_attribute_links.item_id = ospos_items.item_id + INNER JOIN ospos_attribute_values ON attribute_value = custom10 + SET ospos_attribute_links.attribute_id = ospos_attribute_values.attribute_id + WHERE definition_id IN (SELECT definition_id FROM ospos_attribute_definitions + WHERE definition_name = (SELECT `value` FROM ospos_app_config WHERE `key` = 'custom10_name')); + +ALTER TABLE `ospos_items` + DROP COLUMN `custom1`, + DROP COLUMN `custom2`, + DROP COLUMN `custom3`, + DROP COLUMN `custom4`, + DROP COLUMN `custom5`, + DROP COLUMN `custom6`, + DROP COLUMN `custom7`, + DROP COLUMN `custom8`, + DROP COLUMN `custom9`, + DROP COLUMN `custom10`, + DROP COLUMN `category`; diff --git a/database/constraints.sql b/database/constraints.sql index a293fc690..65d7f51fe 100644 --- a/database/constraints.sql +++ b/database/constraints.sql @@ -118,6 +118,22 @@ ALTER TABLE `ospos_suppliers` ALTER TABLE `ospos_giftcards` ADD CONSTRAINT `ospos_giftcards_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`); +-- +-- Constraints for table `ospos_attribute_definitions` +-- +ALTER TABLE `ospos_attribute_definitions` + ADD CONSTRAINT `fk_ospos_attribute_definitions_ibfk_1` FOREIGN KEY (`definition_fk`) REFERENCES `ospos_attribute_definitions` (`definition_id`); + +-- +-- Constraints for table `ospos_attribute_links` +-- +ALTER TABLE `ospos_attribute_links` + ADD CONSTRAINT `ospos_attribute_links_ibfk_1` FOREIGN KEY (`definition_id`) REFERENCES `ospos_attribute_definitions` (`definition_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `ospos_attribute_values` (`attribute_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_attribute_links_ibfk_4` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_attribute_links_ibfk_5` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`) ON DELETE CASCADE; + -- -- Constraints for table `ospos_customers_points` -- @@ -130,4 +146,4 @@ ALTER TABLE `ospos_customers_points` -- Constraints for table `ospos_sales_reward_points` -- ALTER TABLE `ospos_sales_reward_points` - ADD CONSTRAINT `ospos_sales_reward_points_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + ADD CONSTRAINT `ospos_sales_reward_points_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_items` (`sale_id`); diff --git a/database/tables.sql b/database/tables.sql index 6a63bfbbc..32d304fb0 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -229,7 +229,6 @@ CREATE TABLE `ospos_inventory` ( CREATE TABLE `ospos_items` ( `name` varchar(255) NOT NULL, - `category` varchar(255) NOT NULL, `supplier_id` int(11) DEFAULT NULL, `item_number` varchar(255) DEFAULT NULL, `description` varchar(255) NOT NULL, @@ -248,16 +247,6 @@ CREATE TABLE `ospos_items` ( `pack_name` varchar(8) DEFAULT '', `low_sell_item_id` int(10) DEFAULT 0, `deleted` int(1) NOT NULL DEFAULT '0', - `custom1` VARCHAR(255) DEFAULT NULL, - `custom2` VARCHAR(255) DEFAULT NULL, - `custom3` VARCHAR(255) DEFAULT NULL, - `custom4` VARCHAR(255) DEFAULT NULL, - `custom5` VARCHAR(255) DEFAULT NULL, - `custom6` VARCHAR(255) DEFAULT NULL, - `custom7` VARCHAR(255) DEFAULT NULL, - `custom8` VARCHAR(255) DEFAULT NULL, - `custom9` VARCHAR(255) DEFAULT NULL, - `custom10` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`item_id`), KEY `item_number` (`item_number`), KEY `supplier_id` (`supplier_id`) @@ -363,7 +352,7 @@ CREATE TABLE `ospos_modules` ( -- INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES -('module_config', 'module_config_desc', 110, 'config'), +('module_config', 'module_config_desc', 120, 'config'), ('module_customers', 'module_customers_desc', 10, 'customers'), ('module_employees', 'module_employees_desc', 80, 'employees'), ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), @@ -376,7 +365,8 @@ INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_i ('module_reports', 'module_reports_desc', 50, 'reports'), ('module_sales', 'module_sales_desc', 70, 'sales'), ('module_suppliers', 'module_suppliers_desc', 40, 'suppliers'), -('module_taxes', 'module_taxes_desc', 105, 'taxes'); +('module_taxes', 'module_taxes_desc', 105, 'taxes'), +('module_attributes', 'module_attributes_desc', 110, 'attributes'); -- -------------------------------------------------------- @@ -452,7 +442,8 @@ INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES ('sales', 'sales'), ('config', 'config'), ('suppliers', 'suppliers'), -('taxes', 'taxes'); +('taxes', 'taxes'), +('attributes', 'attributes'); @@ -507,6 +498,7 @@ INSERT INTO `ospos_grants` (`permission_id`, `person_id`, `menu_group`) VALUES ('suppliers', 1, 'home'), ('taxes', 1, 'office'), ('office', 1, 'home'), +('attributes', 1, 'office'), ('home', 1, 'office'); -- @@ -809,6 +801,68 @@ CREATE TABLE IF NOT EXISTS `ospos_tax_code_rates` ( -- +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_attribute_definitions` +-- + +CREATE TABLE IF NOT EXISTS `ospos_attribute_definitions` ( + `definition_id` INT(10) NOT NULL AUTO_INCREMENT, + `definition_name` VARCHAR(255) NOT NULL, + `definition_type` VARCHAR(45) NOT NULL, + `definition_flags` TINYINT(4) NOT NULL, + `definition_fk` INT(10) NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`definition_id`), + KEY `definition_fk` (`definition_fk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; + +-- +-- Dumping data for table `ospos_attribute_definitions` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_attribute_values` +-- + +CREATE TABLE IF NOT EXISTS `ospos_attribute_values` ( + `attribute_id` INT NOT NULL AUTO_INCREMENT, + `attribute_value` VARCHAR(45) NULL, + PRIMARY KEY (`attribute_id`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; + + +-- +-- Dumping data for table `ospos_attribute_values` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_attribute_links` +-- + +CREATE TABLE IF NOT EXISTS `ospos_attribute_links` ( + `attribute_id` INT NULL, + `definition_id` INT NOT NULL, + `item_id` INT NULL, + `sale_id` INT NULL, + `receiving_id` INT NULL, + KEY `attribute_id` (`attribute_id`), + KEY `definition_id` (`definition_id`), + KEY `item_id` (`item_id`), + KEY `sale_id` (`sale_id`), + KEY `receiving_id` (`receiving_id`), + UNIQUE `attribute_links_uq1` (`attribute_id`, `definition_id`, `item_id`, `sale_id`, `receiving_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; + +-- +-- Dumping data for table `ospos_attribute_links` +-- + -- -------------------------------------------------------- -- diff --git a/design/ospos_categories.mwb b/design/ospos_categories.mwb index d13a13b715160cf6363bdd34b1192e4c388f40d7..755f934310d504f17f5a12b239488136a6231a2f 100644 GIT binary patch literal 30219 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 diff --git a/design/ospos_categories.mwb.bak b/design/ospos_categories.mwb.bak new file mode 100644 index 0000000000000000000000000000000000000000..50d274a08293cef2d748011b13089a228bfa57df GIT binary patch literal 30114 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 literal 0 HcmV?d00001