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 @@ +