diff --git a/application/controllers/Attributes.php b/application/controllers/Attributes.php index 440da8ca9..322af867c 100644 --- a/application/controllers/Attributes.php +++ b/application/controllers/Attributes.php @@ -8,17 +8,17 @@ class Attributes extends Secure_Controller { parent::__construct('attributes'); } - + public function index() { $data['table_headers'] = $this->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. - */ + Returns customer table data rows. This will be called with AJAX. + */ public function search() { $search = $this->input->get('search'); @@ -26,48 +26,48 @@ class Attributes extends Secure_Controller $offset = $this->input->get('offset'); $sort = $this->input->get('sort'); $order = $this->input->get('order'); - + $attributes = $this->Attribute->search($search, $limit, $offset, $sort, $order); $total_rows = $this->Attribute->get_found_rows($search); - + $data_rows = array(); foreach($attributes->result() as $attribute) { $attribute->definition_flags = $this->_get_attributes($attribute->definition_flags); $data_rows[] = get_attribute_definition_data_row($attribute, $this); } - + $data_rows = $this->xss_clean($data_rows); - + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); } - + public function save_attribute_value($attribute_value) { - $success = $this->Attribute->save_value(urldecode($attribute_value), $this->input->post('definition_id'), $this->input->post('item_id'), $this->input->post('attribute_id')); - + $success = $this->Attribute->save_value(urldecode($attribute_value), $this->input->post('definition_id'), $this->input->post('item_id'), $this->input->post('attribute_id')); + echo json_encode(array('success' => $success != 0)); } - + public function delete_attribute_value($attribute_value) { $success = $this->Attribute->delete_value($attribute_value, $this->input->post('definition_id')); - + echo json_encode(array('success' => $success)); } - + public function save_definition($definition_id = -1) { - + $definition_flags = 0; - + $flags = (empty($this->input->post('definition_flags'))) ? array() : $this->input->post('definition_flags'); - + foreach($flags as $flag) { $definition_flags |= $flag; } - + //Save definition data $definition_data = array( 'definition_name' => $this->input->post('definition_name'), @@ -75,57 +75,59 @@ class Attributes extends Secure_Controller 'definition_flags' => $definition_flags, 'definition_fk' => $this->input->post('definition_group') != '' ? $this->input->post('definition_group') : NULL ); - + if ($this->input->post('definition_type') != null) { $definition_data['definition_type'] = DEFINITION_TYPES[$this->input->post('definition_type')]; } - + $definition_name = $this->xss_clean($definition_data['definition_name']); - + if($this->Attribute->save_definition($definition_data, $definition_id)) { //New definition if($definition_id == -1) { $definition_values = json_decode($this->input->post('definition_values')); - + foreach($definition_values as $definition_value) { $this->Attribute->save_value($definition_value, $definition_data['definition_id']); } - + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_adding').' '. - $definition_name, 'id' => $definition_data['definition_id'])); + $definition_name, 'id' => $definition_data['definition_id'])); } - else //Existing definition + //Existing definition + else { echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('attributes_definition_successful_updating').' '. - $definition_name, 'id' => $definition_id)); + $definition_name, 'id' => $definition_id)); } } - else//failure + //Failure + else { echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attributes_definition_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(); @@ -138,7 +140,7 @@ class Attributes extends Secure_Controller } return $definition_flag_names; } - + public function view($definition_id = -1) { $info = $this->Attribute->get_info($definition_id); @@ -146,30 +148,30 @@ class Attributes extends Secure_Controller { $info->$property = $this->xss_clean($value); } - + $data['definition_id'] = $definition_id; $data['definition_values'] = $this->Attribute->get_definition_values($definition_id); $data['definition_group'] = $this->Attribute->get_definitions_by_type(GROUP, $definition_id); $data['definition_group'][''] = $this->lang->line('common_none_selected_text'); $data['definition_info'] = $info; - + $show_all = Attribute::SHOW_IN_ITEMS | Attribute::SHOW_IN_RECEIVINGS | Attribute::SHOW_IN_SALES; $data['definition_flags'] = $this->_get_attributes($show_all); $selected_flags = $info->definition_flags === '' ? $show_all : $info->definition_flags; $data['selected_definition_flags'] = $this->_get_attributes($selected_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'); @@ -180,5 +182,5 @@ class Attributes extends Secure_Controller echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('attributes_definition_cannot_be_deleted'))); } } - + } diff --git a/application/controllers/Items.php b/application/controllers/Items.php index d5ca2d2cc..e55ed851a 100644 --- a/application/controllers/Items.php +++ b/application/controllers/Items.php @@ -7,19 +7,19 @@ class Items extends Secure_Controller public function __construct() { parent::__construct('items'); - + $this->load->library('item_lib'); } - + public function index() { $this->session->set_userdata('allow_temp_items', 0); - + $data['table_headers'] = $this->xss_clean(get_items_manage_table_headers()); - + $data['stock_location'] = $this->xss_clean($this->item_lib->get_item_location()); $data['stock_locations'] = $this->xss_clean($this->Stock_location->get_allowed_locations()); - + // filters that will be loaded in the multiselect dropdown $data['filters'] = array('empty_upc' => $this->lang->line('items_empty_upc_items'), 'low_inventory' => $this->lang->line('items_low_inventory_items'), @@ -28,10 +28,10 @@ class Items extends Secure_Controller 'search_custom' => $this->lang->line('items_search_attributes'), 'is_deleted' => $this->lang->line('items_is_deleted'), 'temporary' => $this->lang->line('items_temp')); - + $this->load->view('items/manage', $data); } - + /* Returns Items table data rows. This will be called with AJAX. */ @@ -42,11 +42,11 @@ class Items extends Secure_Controller $offset = $this->input->get('offset'); $sort = $this->input->get('sort'); $order = $this->input->get('order'); - + $this->item_lib->set_item_location($this->input->get('stock_location')); - + $definition_names = $this->Attribute->get_definitions_by_flags(Attribute::SHOW_IN_ITEMS); - + $filters = array('start_date' => $this->input->get('start_date'), 'end_date' => $this->input->get('end_date'), 'stock_location_id' => $this->item_lib->get_item_location(), @@ -58,15 +58,15 @@ class Items extends Secure_Controller 'is_deleted' => FALSE, 'temporary' => FALSE, 'definition_ids' => array_keys($definition_names)); - + // check if any filter is set in the multiselect dropdown $filledup = array_fill_keys($this->input->get('filters'), TRUE); $filters = array_merge($filters, $filledup); - + $items = $this->Item->search($search, $filters, $limit, $offset, $sort, $order); - + $total_rows = $this->Item->get_found_rows($search, $filters); - + $data_rows = array(); foreach($items->result() as $item) { @@ -76,19 +76,19 @@ class Items extends Secure_Controller $this->_update_pic_filename($item); } } - + echo json_encode(array('total' => $total_rows, 'rows' => $data_rows)); } - + public function pic_thumb($pic_filename) { $this->load->helper('file'); $this->load->library('image_lib'); - + // in this context, $pic_filename always has .ext $ext = pathinfo($pic_filename, PATHINFO_EXTENSION); $images = glob('./uploads/item_pics/' . $pic_filename); - + // make sure we pick only the file name, without extension $base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME); if(sizeof($images) > 0) @@ -111,7 +111,7 @@ class Items extends Secure_Controller $this->output->set_output(file_get_contents($thumb_path)); } } - + /* Gives search suggestions based on what is being searched for */ @@ -119,75 +119,75 @@ class Items extends Secure_Controller { $suggestions = $this->xss_clean($this->Item->get_search_suggestions($this->input->post_get('term'), array('search_custom' => $this->input->post('search_custom'), 'is_deleted' => $this->input->post('is_deleted') != NULL), FALSE)); - + echo json_encode($suggestions); } - + public function suggest() { $suggestions = $this->xss_clean($this->Item->get_search_suggestions($this->input->post_get('term'), array('search_custom' => FALSE, 'is_deleted' => FALSE), TRUE)); - + echo json_encode($suggestions); } - - + + public function suggest_low_sell() { $suggestions = $this->xss_clean($this->Item->get_low_sell_suggestions($this->input->post_get('name'))); - + echo json_encode($suggestions); } - - + + public function suggest_kits() { $suggestions = $this->xss_clean($this->Item->get_kit_search_suggestions($this->input->post_get('term'), array('search_custom' => FALSE, 'is_deleted' => FALSE), TRUE)); - + echo json_encode($suggestions); } - + /* Gives search suggestions based on what is being searched for */ public function suggest_category() { $suggestions = $this->xss_clean($this->Item->get_category_suggestions($this->input->get('term'))); - + echo json_encode($suggestions); } - + /* Gives search suggestions based on what is being searched for */ public function suggest_location() { $suggestions = $this->xss_clean($this->Item->get_location_suggestions($this->input->get('term'))); - + echo json_encode($suggestions); } - + public function get_row($item_ids) { $item_infos = $this->Item->get_multiple_info(explode(":", $item_ids), $this->item_lib->get_item_location()); - + $result = array(); foreach($item_infos->result() as $item_info) { $result[$item_info->item_id] = $this->xss_clean(get_item_data_row($item_info)); } - + echo json_encode($result); } - + public function view($item_id = -1) { if($item_id == -1) { $data = array(); } - + // allow_temp_items is set in the index function of items.php or sales.php $data['allow_temp_item'] = $this->session->userdata('allow_temp_items'); $data['item_tax_info'] = $this->xss_clean($this->Item_taxes->get_info($item_id)); @@ -196,19 +196,19 @@ class Items extends Secure_Controller $data['item_kit_disabled'] = !$this->Employee->has_grant('item_kits', $this->Employee->get_logged_in_employee_info()->person_id); $data['definition_values'] = $this->Attribute->get_attributes_by_item($item_id); $data['definition_names'] = $this->Attribute->get_definition_names(); - + foreach($data['definition_values'] as $definition_id => $definition) { unset($data['definition_names'][$definition_id]); } - + $item_info = $this->Item->get_info($item_id); - + foreach(get_object_vars($item_info) as $property => $value) { $item_info->$property = $this->xss_clean($value); } - + if($data['allow_temp_item'] == 1) { if($item_id != -1) @@ -226,15 +226,15 @@ class Items extends Secure_Controller $data['allow_temp_item'] = 1; } } - + $use_destination_based_tax = (boolean)$this->config->item('use_destination_based_tax'); $data['include_hsn'] = $this->config->item('include_hsn') == '1'; - + if($item_id == -1) { $data['default_tax_1_rate'] = $this->config->item('default_tax_1_rate'); $data['default_tax_2_rate'] = $this->config->item('default_tax_2_rate'); - + $item_info->receiving_quantity = 1; $item_info->reorder_level = 1; $item_info->item_type = ITEM; // standard @@ -249,13 +249,13 @@ class Items extends Secure_Controller $item_info->tax_category_id = $this->config->item('default_tax_category'); } } - + $data['standard_item_locked'] = ($data['item_kit_disabled'] && $item_info->item_type == ITEM_KIT - && !$data['allow_temp_item'] - && !($this->config->item('derive_sale_quantity') == '1')); - + && !$data['allow_temp_item'] + && !($this->config->item('derive_sale_quantity') == '1')); + $data['item_info'] = $item_info; - + $suppliers = array('' => $this->lang->line('items_none')); foreach($this->Supplier->get_all()->result_array() as $row) { @@ -263,7 +263,7 @@ class Items extends Secure_Controller } $data['suppliers'] = $suppliers; $data['selected_supplier'] = $item_info->supplier_id; - + if($data['include_hsn']) { $data['hsn_code'] = $item_info->hsn_code; @@ -272,7 +272,7 @@ class Items extends Secure_Controller { $data['hsn_code'] = ''; } - + if($use_destination_based_tax) { $data['use_destination_based_tax'] = TRUE; @@ -297,7 +297,7 @@ class Items extends Secure_Controller $data['tax_categories'] = array(); $data['tax_category'] = ''; } - + $data['logo_exists'] = $item_info->pic_filename != ''; $ext = pathinfo($item_info->pic_filename, PATHINFO_EXTENSION); if($ext == '') @@ -315,15 +315,15 @@ class Items extends Secure_Controller foreach($stock_locations as $location) { $location = $this->xss_clean($location); - + $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity); $quantity = ($item_id == -1) ? 0 : $quantity; $location_array[$location['location_id']] = array('location_name' => $location['location_name'], 'quantity' => $quantity); $data['stock_locations'] = $location_array; } - + $data['selected_low_sell_item_id'] = $item_info->low_sell_item_id; - + if($item_id != -1 && $item_info->item_id != $item_info->low_sell_item_id) { $low_sell_item_info = $this->Item->get_info($item_info->low_sell_item_id); @@ -333,10 +333,10 @@ class Items extends Secure_Controller { $data['selected_low_sell_item'] = ''; } - + $this->load->view('items/form', $data); } - + public function inventory($item_id = -1) { $item_info = $this->Item->get_info($item_id); @@ -345,21 +345,21 @@ class Items extends Secure_Controller $item_info->$property = $this->xss_clean($value); } $data['item_info'] = $item_info; - + $data['stock_locations'] = array(); $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); foreach($stock_locations as $location) { $location = $this->xss_clean($location); $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity); - + $data['stock_locations'][$location['location_id']] = $location['location_name']; $data['item_quantities'][$location['location_id']] = $quantity; } - + $this->load->view('items/form_inventory', $data); } - + public function count_details($item_id = -1) { $item_info = $this->Item->get_info($item_id); @@ -368,62 +368,62 @@ class Items extends Secure_Controller $item_info->$property = $this->xss_clean($value); } $data['item_info'] = $item_info; - + $data['stock_locations'] = array(); $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); foreach($stock_locations as $location) { $location = $this->xss_clean($location); $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity); - + $data['stock_locations'][$location['location_id']] = $location['location_name']; $data['item_quantities'][$location['location_id']] = $quantity; } - + $this->load->view('items/form_count_details', $data); } - + public function generate_barcodes($item_ids) { $this->load->library('barcode_lib'); - + $item_ids = explode(':', $item_ids); $result = $this->Item->get_multiple_info($item_ids, $this->item_lib->get_item_location())->result_array(); $config = $this->barcode_lib->get_barcode_config(); - + $data['barcode_config'] = $config; - + // check the list of items to see if any item_number field is empty foreach($result as &$item) { $item = $this->xss_clean($item); - + // update the barcode field if empty / NULL with the newly generated barcode if(empty($item['item_number']) && $this->config->item('barcode_generate_if_empty')) { // get the newly generated barcode $barcode_instance = Barcode_lib::barcode_instance($item, $config); $item['item_number'] = $barcode_instance->getData(); - + $save_item = array('item_number' => $item['item_number']); - + // update the item in the database in order to save the barcode field $this->Item->save($save_item, $item['item_id']); } } $data['items'] = $result; - + // display barcodes $this->load->view('barcodes/barcode_sheet', $data); } - + public function attributes($item_id) { $data['item_id'] = $item_id; $definition_ids = json_decode($this->input->post('definition_ids'), TRUE); $data['definition_values'] = $this->Attribute->get_attributes_by_item($item_id) + $this->Attribute->get_values_by_definitions($definition_ids); $data['definition_names'] = $this->Attribute->get_definition_names(); - + foreach($data['definition_values'] as $definition_id => $definition_value) { $attribute_value = $this->Attribute->get_attribute_value($item_id, $definition_id); @@ -432,32 +432,32 @@ class Items extends Secure_Controller $values['attribute_id'] = $attribute_id; $values['attribute_value'] = $attribute_value; $values['selected_value'] = ''; - + if ($definition_value['definition_type'] == DROPDOWN) { $values['values'] = $this->Attribute->get_definition_values($definition_id); $link_value = $this->Attribute->get_link_value($item_id, $definition_id); $values['selected_value'] = (empty($link_value)) ? '' : $link_value->attribute_id; } - + if (!empty($definition_ids[$definition_id])) { $values['selected_value'] = $definition_ids[$definition_id]; } - + unset($data['definition_names'][$definition_id]); } - + $this->load->view('attributes/item', $data); } - + public function bulk_edit() { $suppliers = array('' => $this->lang->line('items_none')); foreach($this->Supplier->get_all()->result_array() as $row) { $row = $this->xss_clean($row); - + $suppliers[$row['person_id']] = $row['company_name']; } $data['suppliers'] = $suppliers; @@ -465,29 +465,29 @@ class Items extends Secure_Controller '' => $this->lang->line('items_do_nothing'), 1 => $this->lang->line('items_change_all_to_allow_alt_desc'), 0 => $this->lang->line('items_change_all_to_not_allow_allow_desc')); - + $data['serialization_choices'] = array( '' => $this->lang->line('items_do_nothing'), 1 => $this->lang->line('items_change_all_to_serialized'), 0 => $this->lang->line('items_change_all_to_unserialized')); - + $this->load->view('items/form_bulk', $data); } - + public function save($item_id = -1) { $upload_success = $this->_handle_image_upload(); $upload_data = $this->upload->data(); - + $receiving_quantity = parse_quantity($this->input->post('receiving_quantity')); $item_type = $this->input->post('item_type') == NULL ? ITEM : $this->input->post('item_type'); - + if($receiving_quantity == '0' && $item_type!= ITEM_TEMP) { $receiving_quantity = '1'; } $default_pack_name = $this->lang->line('items_default_pack_name'); - + //Save item data $item_data = array( 'name' => $this->input->post('name'), @@ -509,14 +509,14 @@ class Items extends Secure_Controller 'deleted' => $this->input->post('is_deleted') != NULL, 'hsn_code' => $this->input->post('hsn_code') == NULL ? '' : $this->input->post('hsn_code') ); - + if($item_data['item_type'] == ITEM_TEMP) { $item_data['stock_type'] = HAS_NO_STOCK; $item_data['receiving_quantity'] = 0; $item_data['reorder_level'] = 0; } - + $x = $this->input->post('tax_category_id'); if(!isset($x)) { @@ -526,7 +526,7 @@ class Items extends Secure_Controller { $item_data['tax_category_id'] = $this->input->post('tax_category_id') == '' ? NULL : $this->input->post('tax_category_id'); } - + if(!empty($upload_data['orig_name'])) { // XSS file image sanity check @@ -535,9 +535,9 @@ class Items extends Secure_Controller $item_data['pic_filename'] = $upload_data['raw_name']; } } - + $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; - + if($this->Item->save($item_data, $item_id)) { $success = TRUE; @@ -548,9 +548,9 @@ class Items extends Secure_Controller $item_id = $item_data['item_id']; $new_item = TRUE; } - + $use_destination_based_tax = (boolean)$this->config->item('use_destination_based_tax'); - + if(!$use_destination_based_tax) { $items_taxes_data = array(); @@ -567,7 +567,7 @@ class Items extends Secure_Controller } $success &= $this->Item_taxes->save($items_taxes_data, $item_id); } - + //Save item quantity $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); foreach($stock_locations as $location) @@ -580,13 +580,13 @@ class Items extends Secure_Controller $location_detail = array('item_id' => $item_id, 'location_id' => $location['location_id'], 'quantity' => $updated_quantity); - - + + $item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location['location_id']); if($item_quantity->quantity != $updated_quantity || $new_item) { $success &= $this->Item_quantity->save($location_detail, $item_id, $location['location_id']); - + $inv_data = array( 'trans_date' => date('Y-m-d H:i:s'), 'trans_items' => $item_id, @@ -595,11 +595,11 @@ class Items extends Secure_Controller 'trans_comment' => $this->lang->line('items_manually_editing_of_quantity'), 'trans_inventory' => $updated_quantity - $item_quantity->quantity ); - + $success &= $this->Inventory->insert($inv_data); } } - + // Save item attributes $attribute_links = $this->input->post('attribute_links') != NULL ? $this->input->post('attribute_links') : array(); $attribute_ids = $this->input->post('attribute_ids'); @@ -613,34 +613,34 @@ class Items extends Secure_Controller } $this->Attribute->save_link($item_id, $definition_id, $attribute_id); } - + if($success && $upload_success) { $message = $this->xss_clean($this->lang->line('items_successful_' . ($new_item ? 'adding' : 'updating')) . ' ' . $item_data['name']); - + echo json_encode(array('success' => TRUE, 'message' => $message, 'id' => $item_id)); } else { $message = $this->xss_clean($upload_success ? $this->lang->line('items_error_adding_updating') . ' ' . $item_data['name'] : strip_tags($this->upload->display_errors())); - + echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => $item_id)); } } else // failure { $message = $this->xss_clean($this->lang->line('items_error_adding_updating') . ' ' . $item_data['name']); - + echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => -1)); } } - + public function check_item_number() { $exists = $this->Item->item_number_exists($this->input->post('item_number'), $this->input->post('item_id')); echo !$exists ? 'true' : 'false'; } - + /* If adding a new item check to see if an item kit with the same name as the item already exists. */ @@ -656,11 +656,11 @@ class Items extends Secure_Controller } echo !$exists ? 'true' : 'false'; } - + private function _handle_image_upload() { /* Let files be uploaded with their original name */ - + // load upload library $config = array('upload_path' => './uploads/item_pics/', 'allowed_types' => 'gif|jpg|png', @@ -670,18 +670,18 @@ class Items extends Secure_Controller ); $this->load->library('upload', $config); $this->upload->do_upload('item_image'); - + return strlen($this->upload->display_errors()) == 0 || !strcmp($this->upload->display_errors(), '
'.$this->lang->line('upload_no_file_selected').'
'); } - + public function remove_logo($item_id) { $item_data = array('pic_filename' => NULL); $result = $this->Item->save($item_data, $item_id); - + echo json_encode(array('success' => $result)); } - + public function save_inventory($item_id = -1) { $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; @@ -695,9 +695,9 @@ class Items extends Secure_Controller 'trans_comment' => $this->input->post('trans_comment'), 'trans_inventory' => parse_quantity($this->input->post('newquantity')) ); - + $this->Inventory->insert($inv_data); - + //Update stock quantity $item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location_id); $item_quantity_data = array( @@ -705,26 +705,26 @@ class Items extends Secure_Controller 'location_id' => $location_id, 'quantity' => $item_quantity->quantity + parse_quantity($this->input->post('newquantity')) ); - + if($this->Item_quantity->save($item_quantity_data, $item_id, $location_id)) { $message = $this->xss_clean($this->lang->line('items_successful_updating') . ' ' . $cur_item_info->name); - + echo json_encode(array('success' => TRUE, 'message' => $message, 'id' => $item_id)); } else//failure { $message = $this->xss_clean($this->lang->line('items_error_adding_updating') . ' ' . $cur_item_info->name); - + echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => -1)); } } - + public function bulk_update() { $items_to_update = $this->input->post('item_ids'); $item_data = array(); - + foreach($_POST as $key => $value) { //This field is nullable, so treat it differently @@ -737,7 +737,7 @@ class Items extends Secure_Controller $item_data["$key"] = $value; } } - + //Item data could be empty if tax information is being updated if(empty($item_data) || $this->Item->update_multiple($item_data, $items_to_update)) { @@ -751,16 +751,16 @@ class Items extends Secure_Controller if(!empty($tax_names[$k]) && is_numeric($tax_percents[$k])) { $tax_updated = TRUE; - + $items_taxes_data[] = array('name' => $tax_names[$k], 'percent' => $tax_percents[$k]); } } - + if($tax_updated) { $this->Item_taxes->save_multiple($items_taxes_data, $items_to_update); } - + echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('items_successful_bulk_edit'), 'id' => $this->xss_clean($items_to_update))); } else @@ -768,11 +768,11 @@ class Items extends Secure_Controller echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_error_updating_multiple'))); } } - + public function delete() { $items_to_delete = $this->input->post('ids'); - + if($this->Item->delete_list($items_to_delete)) { $message = $this->lang->line('items_successful_deleted') . ' ' . count($items_to_delete) . ' ' . $this->lang->line('items_one_or_multiple'); @@ -783,7 +783,7 @@ class Items extends Secure_Controller echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_cannot_be_deleted'))); } } - + /* Items import from csv spreadsheet */ @@ -795,12 +795,12 @@ class Items extends Secure_Controller $data = generate_import_items_csv($allowed_locations,$allowed_attributes); force_download($name, $data, TRUE); } - + public function csv_import() { $this->load->view('items/form_csv_import', NULL); } - + /** * Imports items from CSV formatted file. */ @@ -817,13 +817,13 @@ class Items extends Secure_Controller $line_array = get_csv_file($_FILES['file_path']['tmp_name']); $failCodes = array(); $keys = $line_array[0]; - + $this->db->trans_begin(); for($i = 1; $i < count($line_array); $i++) { $invalidated = FALSE; $line = array_combine($keys,$this->xss_clean($line_array[$i])); //Build a XSS-cleaned associative array with the row to use to assign values - + if(!empty($line)) { $item_data = array( @@ -839,15 +839,15 @@ class Items extends Secure_Controller 'hsn_code' => $line['HSN'], 'pic_filename' => $line['item_image'] ); - + $item_number = $line['Barcode']; - + if($item_number != '') { $item_data['item_number'] = $item_number; $invalidated = $this->Item->item_number_exists($item_number); } - + //Sanity check of data if(!$invalidated) { @@ -858,7 +858,7 @@ class Items extends Secure_Controller { $invalidated = TRUE; } - + //Save to database if(!$invalidated && $this->Item->save($item_data)) { @@ -873,7 +873,7 @@ class Items extends Secure_Controller log_message("ERROR","CSV Item import failed on line ". $failed_row .". This item was not imported."); } } - + if(count($failCodes) > 0) { $message = $this->lang->line('items_csv_import_partially_failed', count($failCodes), implode(', ', $failCodes)); @@ -892,9 +892,9 @@ class Items extends Secure_Controller } } } - + /** - * Checks the entire line of data for errors + * Checks the entire line of data in an import file for errors * * @param array $line * @param array $item_data @@ -910,13 +910,13 @@ class Items extends Secure_Controller $item_data['cost_price'], $item_data['unit_price'] ); - + if(in_array('',$check_for_empty,true)) { log_message("ERROR","Empty required value"); return TRUE; //Return fail on empty required fields } - + //Build array of fields to check for numerics $check_for_numeric_values = array( $item_data['cost_price'], @@ -926,15 +926,15 @@ class Items extends Secure_Controller $line['Tax 1 Percent'], $line['Tax 2 Percent'] ); - + //Add in Stock Location values to check for numeric $allowed_locations = $this->Stock_location->get_allowed_locations(); - + foreach($allowed_locations as $location_id => $location_name) { $check_for_numeric_values[] = $line['location_'. $location_name]; } - + //Check for non-numeric values which require numeric foreach($check_for_numeric_values as $value) { @@ -944,10 +944,10 @@ class Items extends Secure_Controller return TRUE; } } - + //Check Attribute Data $definition_names = $this->Attribute->get_definition_names(); - + foreach($definition_names as $definition_name) { if(!empty($line['attribute_' . $definition_name])) @@ -955,12 +955,12 @@ class Items extends Secure_Controller $attribute_data = $this->Attribute->get_definition_by_name($definition_name)[0]; $attribute_type = $attribute_data['definition_type']; $attribute_value = $line['attribute_' . $definition_name]; - + if($attribute_type == 'DROPDOWN') { $dropdown_values = $this->Attribute->get_definition_values($attribute_data['definition_id']); $dropdown_values[] = ''; - + if(in_array($attribute_value, $dropdown_values) === FALSE) { log_message("ERROR","Value: '$attribute_value' is not an acceptable DROPDOWN value"); @@ -985,11 +985,13 @@ class Items extends Secure_Controller } } } - + return FALSE; } - + //TODO: Figure out if I need to have line 1003 be isset or empty. If zero is a possible answer, then empty will return false negatives. /** + * Saves attribute data found in the CSV import. + * * @param line * @param failCodes * @param attribute_data @@ -997,15 +999,15 @@ class Items extends Secure_Controller private function save_attribute_data($line, $item_data) { $definition_names = $this->Attribute->get_definition_names(); - + foreach($definition_names as $definition_name) { - if(!empty($line['attribute_' . $definition_name])) + if(!isset($line['attribute_' . $definition_name])) { //Create attribute value $attribute_data = $this->Attribute->get_definition_by_name($definition_name)[0]; $status = $this->Attribute->save_value($line['attribute_' . $definition_name], $attribute_data['definition_id'], $item_data['item_id'], FALSE, $attribute_data['definition_type']); - + if($status === FALSE) { return FALSE; @@ -1013,7 +1015,7 @@ class Items extends Secure_Controller } } } - + /** * Saves inventory quantities for the row in the appropriate stock locations. * @@ -1027,26 +1029,26 @@ class Items extends Secure_Controller $emp_info = $this->Employee->get_info($employee_id); $comment = $this->lang->line('items_inventory_CSV_import_quantity'); $allowed_locations = $this->Stock_location->get_allowed_locations(); - + foreach($allowed_locations as $location_id => $location_name) { $item_quantity_data = array( 'item_id' => $item_data['item_id'], 'location_id' => $location_id ); - + $csv_data = array( 'trans_items' => $item_data['item_id'], 'trans_user' => $employee_id, 'trans_comment' => $comment, 'trans_location' => $location_id, ); - + if(!empty($line['location_' . $location_name])) { $item_quantity_data['quantity'] = $line['location_' . $location_name]; $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $location_id); - + $csv_data['trans_inventory'] = $line['location_' . $location_name]; $this->Inventory->insert($csv_data); } @@ -1054,13 +1056,13 @@ class Items extends Secure_Controller { $item_quantity_data['quantity'] = 0; $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $line[$col]); - + $csv_data['trans_inventory'] = 0; $this->Inventory->insert($csv_data); } } } - + /** * Saves the tax data found in the line of the CSV items import file * @@ -1069,24 +1071,24 @@ class Items extends Secure_Controller private function save_tax_data($line, $item_data) { $items_taxes_data = array(); - + if(is_numeric($line['Tax 1 Percent']) && $line['Tax 1 Name'] != '') { $items_taxes_data[] = array('name' => $line['Tax 1 Name'], 'percent' => $line['Tax 1 Percent'] ); } - + if(is_numeric($line['Tax 2 Percent']) && $line['Tax 2 Name'] != '') { $items_taxes_data[] = array('name' => $line['Tax 2 Name'], 'percent' => $line['Tax 2 Percent'] ); } - + if(count($items_taxes_data) > 0) { $this->Item_taxes->save($items_taxes_data, $item_data['item_id']); } } - - + + /** * Guess whether file extension is not in the table field, if it isn't, then it's an old-format (formerly pic_id) field, so we guess the right filename and update the table * @@ -1095,7 +1097,7 @@ class Items extends Secure_Controller private function _update_pic_filename($item) { $filename = pathinfo($item->pic_filename, PATHINFO_FILENAME); - + // if the field is empty there's nothing to check if(!empty($filename)) { diff --git a/application/models/Attribute.php b/application/models/Attribute.php index cc595b9a1..651f4b045 100644 --- a/application/models/Attribute.php +++ b/application/models/Attribute.php @@ -5,8 +5,9 @@ define('DROPDOWN', 'DROPDOWN'); define('DECIMAL', 'DECIMAL'); define('DATE', 'DATE'); define('TEXT', 'TEXT'); +define('CHECKBOX', 'CHECKBOX'); -const DEFINITION_TYPES = [GROUP, DROPDOWN, DECIMAL, TEXT, DATE]; +const DEFINITION_TYPES = [GROUP, DROPDOWN, DECIMAL, TEXT, DATE, CHECKBOX]; /** * Attribute class @@ -17,14 +18,14 @@ class Attribute extends CI_Model const SHOW_IN_ITEMS = 1; const SHOW_IN_SALES = 2; const SHOW_IN_RECEIVINGS = 4; - + public static function get_definition_flags() { $class = new ReflectionClass(__CLASS__); - + return array_flip($class->getConstants()); } - + /* Determines if a given definition_id is an attribute */ @@ -33,10 +34,10 @@ class Attribute extends CI_Model $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'); @@ -50,13 +51,13 @@ class Attribute extends CI_Model else { $this->db->where('definition_id', $definition_id); - + } $this->db->where('item_id', $item_id); - + return ($this->db->get()->num_rows() > 0); } - + /* Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does */ @@ -65,7 +66,7 @@ class Attribute extends CI_Model $this->db->distinct('attribute_id'); $this->db->from('attribute_values'); $this->db->where('attribute_value', $attribute_value); - + $query = $this->db->get(); if ($query->num_rows() > 0) { @@ -73,7 +74,7 @@ class Attribute extends CI_Model } return FALSE; } - + /* Gets information about a particular attribute definition */ @@ -83,9 +84,9 @@ class Attribute extends CI_Model $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(); @@ -94,17 +95,17 @@ class Attribute extends CI_Model { //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 */ @@ -113,22 +114,22 @@ class Attribute extends CI_Model $this->db->select('parent_definition.definition_name AS definition_group, definition.*'); $this->db->from('attribute_definitions AS definition'); $this->db->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left'); - + $this->db->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'); @@ -137,51 +138,51 @@ class Attribute extends CI_Model $this->db->where('receiving_id'); $this->db->where('sale_id'); $this->db->where('deleted', 0); - + $results = $this->db->get()->result_array(); - + return $this->_to_array($results, 'definition_id'); } - + public function get_values_by_definitions($definition_ids) { if(count($definition_ids ? : [])) { $this->db->from('attribute_definitions'); - + $this->db->group_start(); $this->db->where_in('definition_fk', array_keys($definition_ids)); $this->db->or_where_in('definition_id', array_keys($definition_ids)); $this->db->where('definition_type !=', GROUP); $this->db->group_end(); - + $this->db->where('deleted', 0); - + $results = $this->db->get()->result_array(); - + return $this->_to_array($results, 'definition_id'); } - + return array(); } - + public function get_definitions_by_type($attribute_type, $definition_id = -1) { $this->db->from('attribute_definitions'); $this->db->where('definition_type', $attribute_type); $this->db->where('deleted', 0); - + if($definition_id != -1) { $this->db->where('definition_id != ', $definition_id); } - + $this->db->where('definition_fk'); $results = $this->db->get()->result_array(); - + return $this->_to_array($results, 'definition_id', 'definition_name'); } - + public function get_definitions_by_flags($definition_flags) { $this->db->from('attribute_definitions'); @@ -190,11 +191,11 @@ class Attribute extends CI_Model $this->db->where('definition_type <>', GROUP); $this->db->order_by('definition_id'); $results = $this->db->get()->result_array(); - + return $this->_to_array($results, 'definition_id', 'definition_name'); } - - + + /** * Returns an array of attribute definition names and IDs * @@ -205,45 +206,45 @@ class Attribute extends CI_Model { $this->db->from('attribute_definitions'); $this->db->where('deleted', 0); - + if($groups === FALSE) { $this->db->where_not_in('definition_type',GROUP); } - + $results = $this->db->get()->result_array(); - + $definition_name = array(-1 => $this->lang->line('common_none_selected_text')); - + return $definition_name + $this->_to_array($results, 'definition_id', 'definition_name'); } - + public function get_definition_values($definition_id) { $attribute_values = []; - + if($definition_id > -1) { $this->db->from('attribute_links'); $this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id'); $this->db->where('definition_id', $definition_id); $this->db->where('item_id'); - + $results = $this->db->get()->result_array(); - + return $this->_to_array($results, 'attribute_id', 'attribute_value'); } - + return $attribute_values; } - + private function _to_array($results, $key, $value = '') { return array_column(array_map(function($result) use ($key, $value) { return [$result[$key], empty($value) ? $result : $result[$value]]; }, $results), 1, 0); } - + /* Gets total of rows */ @@ -251,10 +252,10 @@ class Attribute extends CI_Model { $this->db->from('attribute_definitions'); $this->db->where('deleted', 0); - + return $this->db->count_all_results(); } - + /* Get number of rows */ @@ -262,11 +263,11 @@ class Attribute extends CI_Model { return $this->search($search)->num_rows(); } - + private function check_data_validity($definition, $from, $to) { $success = FALSE; - + if($from === TEXT) { $this->db->select('item_id,attribute_value'); @@ -274,7 +275,7 @@ class Attribute extends CI_Model $this->db->join('attribute_links', 'attribute_values.attribute_id = attribute_links.attribute_id'); $this->db->where('definition_id',$definition); $success = TRUE; - + if($to === DATE) { foreach($this->db->get()->result_array() as $row) @@ -300,22 +301,22 @@ class Attribute extends CI_Model } return $success; } - + private function convert_definition_type($definition_id, $from_type, $to_type) { $success = FALSE; - + //From TEXT to DATETIME if($from_type === TEXT) { - if($to_type === DATE || $to_type === DECIMAL) + if(in_array($to_type, [DATE, DECIMAL], TRUE)) { $field = ($to_type === DATE ? 'attribute_date' : 'attribute_decimal'); - + if($this->check_data_validity($definition_id, $from_type, $to_type)) { $this->db->trans_start(); - + $query = 'UPDATE ospos_attribute_values '; $query .= 'INNER JOIN ospos_attribute_links '; $query .= 'ON ospos_attribute_values.attribute_id = ospos_attribute_links.attribute_id '; @@ -323,39 +324,39 @@ class Attribute extends CI_Model $query .= 'attribute_value = NULL '; $query .= 'WHERE definition_id = ' . $this->db->escape($definition_id); $success = $this->db->query($query); - + $this->db->trans_complete(); } } - else if($to_type === DROPDOWN) + else if(in_array($to_type, [DROPDOWN, CHECKBOX], TRUE)) { $success = TRUE; } } - + //From DROPDOWN to TEXT else if($from_type === DROPDOWN) { //From DROPDOWN to TEXT $this->db->trans_start(); - + $this->db->from('ospos_attribute_links'); $this->db->where('definition_id',$definition_id); $this->db->where('item_id', NULL); $success = $this->db->delete(); - + $this->db->trans_complete(); } - + //Any other allowed conversion does not get checked here else { $success = TRUE; } - + return $success; } - + /* Inserts or updates a definition */ @@ -363,26 +364,26 @@ class Attribute extends CI_Model { //Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - + //Definition doesn't exist if($definition_id === -1 || !$this->exists($definition_id)) { $success = $this->db->insert('attribute_definitions', $definition_data); $definition_data['definition_id'] = $this->db->insert_id(); } - + //Definition already exists else { $this->db->select('definition_type, definition_name'); $this->db->from('attribute_definitions'); $this->db->where('definition_id', $definition_id); - + $row = $this->db->get()->row(); $from_definition_type = $row->definition_type; $from_definition_name = $row->definition_name; $to_definition_type = $definition_data['definition_type']; - + if($from_definition_type !== $to_definition_type) { if(!$this->convert_definition_type($definition_id,$from_definition_type,$to_definition_type)) @@ -390,19 +391,19 @@ class Attribute extends CI_Model return FALSE; } } - + $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 = FALSE) { $this->db->from('attribute_definitions'); @@ -411,14 +412,14 @@ class Attribute extends CI_Model { $this->db->where('definition_type', $definition_type); } - + return $this->db->get()->result_array(); } - + 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); @@ -431,30 +432,30 @@ class Attribute extends CI_Model { $this->db->insert('attribute_links', array('attribute_id' => $attribute_id, 'item_id' => $item_id, 'definition_id' => $definition_id)); } - + $this->db->trans_complete(); - + return $this->db->trans_status(); } - + public function delete_link($item_id) { $this->db->where('sale_id'); $this->db->where('receiving_id'); - + return $this->db->delete('attribute_links', array('item_id' => $item_id)); } - + public function get_link_value($item_id, $definition_id) { $this->db->where('item_id', $item_id); $this->db->where('definition_id', $definition_id); $this->db->where('sale_id'); $this->db->where('receiving_id'); - + return $this->db->get('attribute_links')->row_object(); } - + public function get_link_values($item_id, $sale_receiving_fk, $id, $definition_flags) { $format = $this->db->escape(dateformat_mysql()); @@ -465,7 +466,7 @@ class Attribute extends CI_Model $this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id'); $this->db->where('definition_type <>', GROUP); $this->db->where('deleted', 0); - + if(!empty($id)) { $this->db->where($sale_receiving_fk, $id); @@ -477,10 +478,10 @@ class Attribute extends CI_Model } $this->db->where('item_id', (int) $item_id); $this->db->where('definition_flags & ', $definition_flags); - + return $this->db->get(); } - + public function get_attribute_value($item_id, $definition_id) { $this->db->from('attribute_values'); @@ -489,10 +490,10 @@ class Attribute extends CI_Model $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( @@ -502,7 +503,7 @@ class Attribute extends CI_Model 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(); @@ -520,20 +521,22 @@ class Attribute extends CI_Model $row_array = (array) $row; $suggestions[] = array('value' => $row_array['attribute_id'], 'label' => $row_array['attribute_value']); } - + return $suggestions; } - + public function save_value($attribute_value, $definition_id, $item_id = FALSE, $attribute_id = FALSE, $definition_type = DROPDOWN) { + //TODO: Right now when you uncheck the checkbox type it should be sending 0 but that's being interpreted funny and erasing the attribute_link altogether for that item. $this->db->trans_start(); - + + //New Attribute if(empty($attribute_id) || empty($item_id)) { - if($definition_type == TEXT || $definition_type == DROPDOWN) + if(in_array($definition_type, [TEXT, DROPDOWN, CHECKBOX], TRUE)) { $attribute_id = $this->value_exists($attribute_value); - + if(empty($attribute_id)) { $this->db->insert('attribute_values', array('attribute_value' => $attribute_value)); @@ -547,7 +550,7 @@ class Attribute extends CI_Model { $this->db->insert('attribute_values', array('attribute_date' => date('Y-m-d', strtotime($attribute_value)))); } - + $attribute_id = $attribute_id ? $attribute_id : $this->db->insert_id(); $this->db->insert('attribute_links', array( @@ -555,23 +558,25 @@ class Attribute extends CI_Model 'item_id' => empty($item_id) ? NULL : $item_id, 'definition_id' => $definition_id)); } + + //Existing Attribute else { $this->db->where('attribute_id', $attribute_id); $this->db->update('attribute_values', array('attribute_value' => $attribute_value)); } - + $this->db->trans_complete(); - + return $attribute_id; } - + public function delete_value($attribute_value, $definition_id) { return $this->db->query("DELETE atrv, atrl FROM " . $this->db->dbprefix('attribute_values') . " atrv, " . $this->db->dbprefix('attribute_links') . " atrl " . "WHERE atrl.attribute_id = atrv.attribute_id AND atrv.attribute_value = " . $this->db->escape($attribute_value) . " AND atrl.definition_id = " . $this->db->escape($definition_id)); } - + /** * Deletes an Attribute definition from the database and associated column in the items_import.csv * @@ -581,14 +586,14 @@ class Attribute extends CI_Model public function delete_definition($definition_id) { $this->db->where('definition_id', $definition_id); - + return $this->db->update('attribute_definitions', array('deleted' => 1)); } - + public function delete_definition_list($definition_ids) { $this->db->where_in('definition_id', $definition_ids); - + return $this->db->update('attribute_definitions', array('deleted' => 1)); } } diff --git a/application/views/attributes/form.php b/application/views/attributes/form.php index bbd7fc4b9..349048ce8 100644 --- a/application/views/attributes/form.php +++ b/application/views/attributes/form.php @@ -6,7 +6,7 @@