mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-01-01 22:17:55 -05:00
CSV import optimizations and code cleanup (#3150)
Optimizations and CSV Import Rework - Replaced " with ' where possible to prevent the parser from being called when not needed. - Replaced == and != with === and !== where possible for bug prevention and speed. - Replaced -1 with NEW_ITEM global constant for code clarity. - Added NEW_ITEM global constant to constants.php. - Refactored CSV import function names for clarity. - Added capability to import a CSV file containing updates. - Replaced array() with [] for speed and consistency. - Removed hungarian notation from two private functions. - Refactored QueryBuilder functions to place table name in the get() function call. - Replaced (int) cast with call to intval() for speed. - Replaced == and != with === and !== where possible to prevent bugs and for speed. - Replaced array() with [] for speed and consistency. - Fixed search_custom call Optimizations and bugfixes for attributes used in csv_import - Reordered where statements in queries to match composite index on attribute_links table. - fixed value_exists() to account for different attribute types. - Removed hungarian notation on private function. - Replaced array() with [] for speed and consistency. - Replaced != with <> in SQL for consistency. - Removed from() calls in querybuilder where possible to reduce function calls. - Add get_items_by_value() - Reworked check_data_validity() - Remove unneeded comments - Refactor functions for code clarity. - Use $this->db->dbprefix() where possible instead of hand-writing ospos_... - Removed unneeded column from query. - Replaced (int) cast with intval() call for speed. - Added get_attribute_values() - Fixed issue with date format locale not being used - Refactored save_value to respect different attribute_types - Added delete_orphaned_links() to remove attribute_links that are no longer linked to any items - Added get_attributes_by_definition() - Added attribute_cleanup() Optimizations used in csv_import - replaced array() with [] for consistency and speed. - Removed hungarian notation in private functions. - Replaced " with ' where possible to prevent the parser from being called. - Minor formatting - Refactored if statement to tertiary notation for cleaner implementation. - Replaced " for ' where possible to prevent the parser from being called. - Added the Id column in the generate_import_items_csv() template so that users can submit an update to an existing item. - Removed unused key=>value pairs in foreach loops for speed. - Removed unneeded comments where the function name was self-explanatory. - Rework get_csv_file() for speed. - Rework bom_exists() for speed. - Replaced array() with [] for speed and consistency. - Replaced == with === where possible to prevent bugs and for speed. - Reworked valid_date() and valid_decimal helper functions for speed and accuracy according to the locale_format instead of a fixed format. - Minor Reformatting for clarity. - Replaced " for ' to prevent the parser from being called. - Refactored function call names to reflect new names. - Added missing ; in - Used String interpolation where useful. - Spelling fix in comment Requested Review Changes - Fixed indentation in Items.php - Fixed indentation in Attribute.php - Refactored variable out of long line of code to make it more readable.
This commit is contained in:
@@ -110,6 +110,7 @@ define('ITEM', 0);
|
||||
define('ITEM_KIT', 1);
|
||||
define('ITEM_AMOUNT_ENTRY', 2);
|
||||
define('ITEM_TEMP', 3);
|
||||
define('NEW_ITEM', -1);
|
||||
|
||||
define('PRINT_ALL', 0);
|
||||
define('PRINT_PRICED', 1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
require_once("Secure_Controller.php");
|
||||
require_once('Secure_Controller.php');
|
||||
|
||||
class Attributes extends Secure_Controller
|
||||
{
|
||||
@@ -30,10 +30,10 @@ class Attributes extends Secure_Controller
|
||||
$attributes = $this->Attribute->search($search, $limit, $offset, $sort, $order);
|
||||
$total_rows = $this->Attribute->get_found_rows($search);
|
||||
|
||||
$data_rows = array();
|
||||
$data_rows = [];
|
||||
foreach($attributes->result() as $attribute)
|
||||
{
|
||||
$attribute->definition_flags = $this->_get_attributes($attribute->definition_flags);
|
||||
$attribute->definition_flags = $this->get_attributes($attribute->definition_flags);
|
||||
$data_rows[] = get_attribute_definition_data_row($attribute, $this);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class Attributes extends Secure_Controller
|
||||
{
|
||||
$definition_flags = 0;
|
||||
|
||||
$flags = (empty($this->input->post('definition_flags'))) ? array() : $this->input->post('definition_flags');
|
||||
$flags = (empty($this->input->post('definition_flags'))) ? [] : $this->input->post('definition_flags');
|
||||
|
||||
foreach($flags as $flag)
|
||||
{
|
||||
@@ -129,15 +129,15 @@ class Attributes extends Secure_Controller
|
||||
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);
|
||||
$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)
|
||||
private function get_attributes($definition_flags = 0)
|
||||
{
|
||||
$definition_flag_names = array();
|
||||
$definition_flag_names = [];
|
||||
foreach (Attribute::get_definition_flags() as $id => $term)
|
||||
{
|
||||
if ($id & $definition_flags)
|
||||
@@ -163,11 +163,11 @@ class Attributes extends Secure_Controller
|
||||
$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);
|
||||
$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);
|
||||
$data['selected_definition_flags'] = $this->get_attributes($selected_flags);
|
||||
|
||||
$this->load->view("attributes/form", $data);
|
||||
$this->load->view('attributes/form', $data);
|
||||
}
|
||||
|
||||
public function delete_value($attribute_id)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,20 @@
|
||||
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Generates the header content for the import_items.csv file
|
||||
*
|
||||
* @return string Comma separated headers for the CSV file
|
||||
*/
|
||||
function generate_import_items_csv($stock_locations,$attributes)
|
||||
{
|
||||
$csv_headers = pack("CCC",0xef,0xbb,0xbf); //Encode the Byte-Order Mark (BOM) so that UTF-8 File headers display properly in Microsoft Excel
|
||||
$csv_headers .= 'Barcode,"Item Name",Category,"Supplier ID","Cost Price","Unit Price","Tax 1 Name","Tax 1 Percent","Tax 2 Name","Tax 2 Percent","Reorder Level",Description,"Allow Alt Description","Item has Serial Number",item_image,HSN';
|
||||
$csv_headers = pack('CCC',0xef,0xbb,0xbf); //Encode the Byte-Order Mark (BOM) so that UTF-8 File headers display properly in Microsoft Excel
|
||||
$csv_headers .= 'Id,Barcode,"Item Name",Category,"Supplier ID","Cost Price","Unit Price","Tax 1 Name","Tax 1 Percent","Tax 2 Name","Tax 2 Percent","Reorder Level",Description,"Allow Alt Description","Item has Serial Number",Image,HSN';
|
||||
$csv_headers .= generate_stock_location_headers($stock_locations);
|
||||
$csv_headers .= generate_attribute_headers($attributes);
|
||||
|
||||
return $csv_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of stock location names as a string
|
||||
*
|
||||
* @return string Comma-separated list of stock location names
|
||||
*/
|
||||
function generate_stock_location_headers($locations)
|
||||
{
|
||||
$location_headers = "";
|
||||
$location_headers = '';
|
||||
|
||||
foreach($locations as $location_id => $location_name)
|
||||
foreach($locations as $location_name)
|
||||
{
|
||||
$location_headers .= ',"location_' . $location_name . '"';
|
||||
}
|
||||
@@ -32,14 +22,9 @@ function generate_stock_location_headers($locations)
|
||||
return $location_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of attribute names as a string
|
||||
*
|
||||
* @return string Comma-separated list of attribute names
|
||||
*/
|
||||
function generate_attribute_headers($attribute_names)
|
||||
{
|
||||
$attribute_headers = "";
|
||||
$attribute_headers = '';
|
||||
unset($attribute_names[-1]);
|
||||
|
||||
foreach($attribute_names as $attribute_name)
|
||||
@@ -50,61 +35,59 @@ function generate_attribute_headers($attribute_names)
|
||||
return $attribute_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents of a given CSV formatted file into a two-dimensional array
|
||||
*
|
||||
* @param string $file_name Name of the file to read.
|
||||
* @return boolean|array[][] two-dimensional array with the file contents or FALSE on failure.
|
||||
*/
|
||||
function get_csv_file($file_name)
|
||||
{
|
||||
ini_set("auto_detect_line_endings", true);
|
||||
//TODO: current implementation reads the entire file in. This is memory intensive for large files.
|
||||
//We may want to rework the CSV import feature to read the file in chunks, process it and continue.
|
||||
//It must be done in a way that does not significantly negatively affect performance.
|
||||
ini_set('auto_detect_line_endings', true);
|
||||
|
||||
$csv_rows = FALSE;
|
||||
|
||||
if(($csv_file = fopen($file_name,'r')) !== FALSE)
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$CI->load->helper('security');
|
||||
|
||||
$csv_rows = [];
|
||||
|
||||
//Skip Byte-Order Mark
|
||||
if(bom_exists($csv_file) === TRUE)
|
||||
{
|
||||
fseek($csv_file, 3);
|
||||
}
|
||||
|
||||
while (($data = fgetcsv($csv_file)) !== FALSE)
|
||||
$headers = fgetcsv($csv_file);
|
||||
|
||||
while(($row = fgetcsv($csv_file)) !== FALSE)
|
||||
{
|
||||
//Skip empty lines
|
||||
if(array(null) !== $data)
|
||||
//Skip empty lines
|
||||
if($row !== array(null))
|
||||
{
|
||||
$line_array[] = $data;
|
||||
$csv_rows[] = array_combine($headers, $CI->security->xss_clean($row));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
|
||||
fclose($csv_file);
|
||||
}
|
||||
|
||||
return $line_array;
|
||||
return $csv_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the first three characters of a file for the Byte-Order Mark then returns the file position to the first character.
|
||||
*
|
||||
* @param object $file_handle File handle to check
|
||||
* @return bool Returns TRUE if the BOM exists and FALSE otherwise.
|
||||
*/
|
||||
function bom_exists(&$file_handle)
|
||||
{
|
||||
$str = fread($file_handle,3);
|
||||
$result = FALSE;
|
||||
$candidate = fread($file_handle, 3);
|
||||
|
||||
rewind($file_handle);
|
||||
|
||||
$bom = pack("CCC", 0xef, 0xbb, 0xbf);
|
||||
$bom = pack('CCC', 0xef, 0xbb, 0xbf);
|
||||
|
||||
if (0 === strncmp($str, $bom, 3))
|
||||
if (0 === strncmp($candidate, $bom, 3))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
$result = TRUE;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
?>
|
||||
@@ -249,7 +249,7 @@ function get_payment_options()
|
||||
$config = get_instance()->config;
|
||||
$lang = get_instance()->lang;
|
||||
|
||||
$payments = array();
|
||||
$payments = [];
|
||||
|
||||
|
||||
if($config->item('payment_options_order') == 'debitcreditcash')
|
||||
@@ -388,7 +388,7 @@ function to_quantity_decimals($number)
|
||||
return to_decimals($number, 'quantity_decimals');
|
||||
}
|
||||
|
||||
function to_decimals($number, $decimals=NULL, $type=\NumberFormatter::DECIMAL)
|
||||
function to_decimals($number, $decimals = NULL, $type=\NumberFormatter::DECIMAL)
|
||||
{
|
||||
// ignore empty strings and return
|
||||
// NOTE: do not change it to empty otherwise tables will show a 0 with no decimal nor currency symbol
|
||||
@@ -424,7 +424,6 @@ function parse_tax($number)
|
||||
function parse_decimals($number, $decimals = NULL)
|
||||
{
|
||||
// ignore empty strings and return
|
||||
|
||||
if(empty($number))
|
||||
{
|
||||
return $number;
|
||||
@@ -442,7 +441,7 @@ function parse_decimals($number, $decimals = NULL)
|
||||
|
||||
$config = get_instance()->config;
|
||||
|
||||
if($decimals == NULL)
|
||||
if($decimals === NULL)
|
||||
{
|
||||
$decimals = $config->item('currency_decimals');
|
||||
}
|
||||
@@ -600,12 +599,13 @@ function dateformat_bootstrap($php_format)
|
||||
|
||||
function valid_date($date)
|
||||
{
|
||||
return preg_match('/^([0-9]{2,4})-([0-1][0-9])-([0-3][0-9])(?:( [0-2][0-9]):([0-5][0-9]):([0-5][0-9]))?$/', $date);
|
||||
$config = get_instance()->Appconfig;
|
||||
return (DateTime::createFromFormat($config->get('dateformat'), $date));
|
||||
}
|
||||
|
||||
function valid_decimal($decimal)
|
||||
{
|
||||
return preg_match('/^(\d*\.)?\d+$/', $decimal);
|
||||
return (preg_match('/^(\d*\.)?\d+$/', $decimal) === 1);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -21,18 +21,24 @@ class Attribute extends CI_Model
|
||||
*/
|
||||
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);
|
||||
return ($this->db->get('attribute_definitions')->num_rows() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an attribute_link row exists given an item_id and optionally a definition_id
|
||||
* @param int $item_id
|
||||
* @param boolean $definition_id
|
||||
* @return boolean TRUE if at least one attribute_link exists or FALSE if no attributes exist.
|
||||
*/
|
||||
public function link_exists($item_id, $definition_id = FALSE)
|
||||
{
|
||||
$this->db->where('item_id', $item_id);
|
||||
$this->db->where('sale_id');
|
||||
$this->db->where('receiving_id');
|
||||
$this->db->from('attribute_links');
|
||||
|
||||
if(empty($definition_id))
|
||||
{
|
||||
$this->db->where('definition_id <>');
|
||||
@@ -43,25 +49,38 @@ class Attribute extends CI_Model
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
}
|
||||
|
||||
$this->db->where('item_id', $item_id);
|
||||
|
||||
return ($this->db->get()->num_rows() > 0);
|
||||
return ($this->db->get('attribute_links')->num_rows() > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does
|
||||
* Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does
|
||||
*/
|
||||
public function value_exists($attribute_value)
|
||||
public function value_exists($attribute_value, $definition_type = TEXT)
|
||||
{
|
||||
$this->db->distinct('attribute_id');
|
||||
$this->db->from('attribute_values');
|
||||
$this->db->where('attribute_value', $attribute_value);
|
||||
switch($definition_type)
|
||||
{
|
||||
case DATE:
|
||||
$data_type = 'date';
|
||||
$attribute_date_value = DateTime::createFromFormat($this->Appconfig->get('dateformat'), $attribute_value);
|
||||
$attribute_value = $attribute_date_value->format('Y-m-d');
|
||||
break;
|
||||
case DECIMAL:
|
||||
$data_type = 'decimal';
|
||||
break;
|
||||
default:
|
||||
$data_type = 'value';
|
||||
break;
|
||||
}
|
||||
|
||||
$query = $this->db->get();
|
||||
if ($query->num_rows() > 0)
|
||||
$this->db->select('attribute_id');
|
||||
$this->db->where("attribute_$data_type", $attribute_value);
|
||||
$query = $this->db->get('attribute_values');
|
||||
|
||||
if($query->num_rows() > 0)
|
||||
{
|
||||
return $query->row()->attribute_id;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -86,7 +105,7 @@ 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
|
||||
//Get all the fields from attribute_definitions table
|
||||
foreach($this->db->list_fields('attribute_definitions') as $field)
|
||||
{
|
||||
$item_obj->$field = '';
|
||||
@@ -106,9 +125,10 @@ class Attribute extends CI_Model
|
||||
$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->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);
|
||||
|
||||
@@ -122,68 +142,63 @@ class Attribute extends CI_Model
|
||||
|
||||
public function get_attributes_by_item($item_id)
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id');
|
||||
$this->db->where('item_id', $item_id);
|
||||
$this->db->where('receiving_id');
|
||||
$this->db->where('sale_id');
|
||||
$this->db->where('receiving_id');
|
||||
$this->db->where('deleted', 0);
|
||||
$this->db->order_by('definition_name','ASC');
|
||||
$this->db->order_by('definition_name', 'ASC');
|
||||
|
||||
$results = $this->db->get()->result_array();
|
||||
$results = $this->db->get('attribute_definitions')->result_array();
|
||||
|
||||
return $this->_to_array($results, 'definition_id');
|
||||
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->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();
|
||||
$results = $this->db->get('attribute_definitions')->result_array();
|
||||
|
||||
return $this->_to_array($results, 'definition_id');
|
||||
return $this->to_array($results, 'definition_id');
|
||||
}
|
||||
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
public function get_definitions_by_type($attribute_type, $definition_id = NO_DEFINITION_ID)
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->where('definition_type', $attribute_type);
|
||||
$this->db->where('deleted', 0);
|
||||
$this->db->where('definition_fk');
|
||||
|
||||
if($definition_id != CATEGORY_DEFINITION_ID)
|
||||
{
|
||||
$this->db->where('definition_id != ', $definition_id);
|
||||
$this->db->where('definition_id <>', $definition_id);
|
||||
}
|
||||
|
||||
$this->db->where('definition_fk');
|
||||
$results = $this->db->get()->result_array();
|
||||
$results = $this->db->get('attribute_definitions')->result_array();
|
||||
|
||||
return $this->_to_array($results, 'definition_id', 'definition_name');
|
||||
return $this->to_array($results, 'definition_id', 'definition_name');
|
||||
}
|
||||
|
||||
public function get_definitions_by_flags($definition_flags)
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->where('definition_flags &', $definition_flags);
|
||||
$this->db->where('deleted', 0);
|
||||
$this->db->where('definition_type <>', GROUP);
|
||||
$this->db->order_by('definition_id');
|
||||
$results = $this->db->get()->result_array();
|
||||
$results = $this->db->get('attribute_definitions')->result_array();
|
||||
|
||||
return $this->_to_array($results, 'definition_id', 'definition_name');
|
||||
return $this->to_array($results, 'definition_id', 'definition_name');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +209,6 @@ class Attribute extends CI_Model
|
||||
*/
|
||||
public function get_definition_names($groups = TRUE)
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->where('deleted', 0);
|
||||
$this->db->order_by('definition_name','ASC');
|
||||
|
||||
@@ -203,11 +217,10 @@ class Attribute extends CI_Model
|
||||
$this->db->where_not_in('definition_type',GROUP);
|
||||
}
|
||||
|
||||
$results = $this->db->get()->result_array();
|
||||
|
||||
$results = $this->db->get('attribute_definitions')->result_array();
|
||||
$definition_name = array(-1 => $this->lang->line('common_none_selected_text'));
|
||||
|
||||
return $definition_name + $this->_to_array($results, 'definition_id', 'definition_name');
|
||||
return $definition_name + $this->to_array($results, 'definition_id', 'definition_name');
|
||||
}
|
||||
|
||||
public function get_definition_values($definition_id)
|
||||
@@ -216,23 +229,22 @@ class Attribute extends CI_Model
|
||||
|
||||
if($definition_id > 0 || $definition_id == CATEGORY_DEFINITION_ID)
|
||||
{
|
||||
$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');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
$this->db->order_by('attribute_value','ASC');
|
||||
|
||||
$results = $this->db->get()->result_array();
|
||||
$results = $this->db->get('attribute_links')->result_array();
|
||||
|
||||
return $this->_to_array($results, 'attribute_id', 'attribute_value');
|
||||
return $this->to_array($results, 'attribute_id', 'attribute_value');
|
||||
}
|
||||
|
||||
return $attribute_values;
|
||||
}
|
||||
|
||||
private function _to_array($results, $key, $value = '')
|
||||
private function to_array($results, $key, $value = '')
|
||||
{
|
||||
return array_column(array_map(function($result) use ($key, $value) {
|
||||
return array_column(array_map(function($result) use ($key, $value){
|
||||
return [$result[$key], empty($value) ? $result : $result[$value]];
|
||||
}, $results), 1, 0);
|
||||
}
|
||||
@@ -242,10 +254,9 @@ class Attribute extends CI_Model
|
||||
*/
|
||||
public function get_total_rows()
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->where('deleted', 0);
|
||||
|
||||
return $this->db->count_all_results();
|
||||
return $this->db->count_all_results('attribute_definitions');
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -256,73 +267,83 @@ class Attribute extends CI_Model
|
||||
return $this->search($search)->num_rows();
|
||||
}
|
||||
|
||||
private function check_data_validity($definition, $from, $to)
|
||||
private function check_data_validity($definition_id, $from, $to)
|
||||
{
|
||||
$success = FALSE;
|
||||
|
||||
if($from === TEXT)
|
||||
{
|
||||
$this->db->select('item_id,attribute_value');
|
||||
$this->db->from('attribute_values');
|
||||
$this->db->join('attribute_links', 'attribute_values.attribute_id = attribute_links.attribute_id');
|
||||
$this->db->where('definition_id',$definition);
|
||||
$success = TRUE;
|
||||
|
||||
if($to === DATE)
|
||||
$this->db->distinct()->select('attribute_value');
|
||||
$this->db->join('attribute_links', 'attribute_values.attribute_id = attribute_links.attribute_id');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
foreach($this->db->get('attribute_values')->result() as $attribute)
|
||||
{
|
||||
foreach($this->db->get()->result_array() as $row)
|
||||
switch($to)
|
||||
{
|
||||
if(valid_date($row['attribute_value']) === FALSE)
|
||||
{
|
||||
log_message('ERROR', 'item_id: ' . $row['item_id'] . ' with attribute_value: ' . $row['attribute_value'] . ' cannot be converted to datetime');
|
||||
$success = FALSE;
|
||||
}
|
||||
case DATE:
|
||||
$success = valid_date($attribute->attribute_value);
|
||||
break;
|
||||
case DECIMAL:
|
||||
$success = valid_decimal($attribute->attribute_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if($to === DECIMAL)
|
||||
{
|
||||
foreach($this->db->get()->result_array() as $row)
|
||||
|
||||
if($success === FALSE)
|
||||
{
|
||||
if(valid_decimal($row['attribute_value']) === FALSE)
|
||||
$affected_items = $this->get_items_by_value($attribute->attribute_value, $definition_id);
|
||||
foreach($affected_items as $affected_item)
|
||||
{
|
||||
log_message('ERROR', 'item_id: ' . $row['item_id'] . ' with attribute_value: ' . $row['attribute_value'] . ' cannot be converted to decimal');
|
||||
$success = FALSE;
|
||||
$affected_items[] = $affected_item['item_id'];
|
||||
}
|
||||
|
||||
log_message('ERROR', "Attribute_value: '$attribute->attribute_value' cannot be converted to $to. Affected Items: ". implode(',', $affected_items));
|
||||
unset($affected_items);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
private function convert_definition_type($definition_id, $from_type, $to_type)
|
||||
/**
|
||||
* Returns all item_ids with a specific attribute_value and attribute_definition
|
||||
* @param string $attribute_value
|
||||
* @param int $definition_id
|
||||
* @return array
|
||||
*/
|
||||
private function get_items_by_value($attribute_value, $definition_id)
|
||||
{
|
||||
$this->db->select('item_id');
|
||||
$this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
$this->db->where('attribute_value', $attribute_value);
|
||||
return $this->db->get('attribute_links')->result_array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts data in attribute_values and attribute_links tables associated with the conversion of one attribute type to another.
|
||||
* @param int $definition_id
|
||||
* @param string $from_type
|
||||
* @param string $to_type
|
||||
* @return boolean
|
||||
*/
|
||||
private function convert_definition_data($definition_id, $from_type, $to_type)
|
||||
{
|
||||
$success = FALSE;
|
||||
|
||||
//From TEXT
|
||||
if($from_type === TEXT)
|
||||
{
|
||||
//To DATETIME or 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 ';
|
||||
$query .= 'SET '. $field .'= attribute_value, ';
|
||||
$query .= 'attribute_value = NULL ';
|
||||
$query .= 'WHERE definition_id = ' . $this->db->escape($definition_id);
|
||||
$success = $this->db->query($query);
|
||||
|
||||
$this->db->trans_complete();
|
||||
$attributes_to_convert = $this->get_attributes_by_definition($definition_id);
|
||||
$success = $this->attribute_cleanup($attributes_to_convert, $definition_id, $to_type);
|
||||
}
|
||||
}
|
||||
|
||||
//To DROPDOWN or CHECKBOX
|
||||
else if($to_type === DROPDOWN)
|
||||
{
|
||||
$success = TRUE;
|
||||
@@ -333,57 +354,44 @@ class Attribute extends CI_Model
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$query = 'UPDATE ospos_attribute_values values ';
|
||||
$query .= 'INNER JOIN ospos_attribute_links links ';
|
||||
$query .= 'ON values.attribute_id = links.attribute_id ';
|
||||
$query .= "SET links.attribute_id = IF((values.attribute_value IN('FALSE','0','') OR (values.attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
|
||||
$query .= 'WHERE definition_id = ' . $this->db->escape($definition_id);
|
||||
$query = 'UPDATE '. $this->db->dbprefix('attribute_links') .' links ';
|
||||
$query .= 'JOIN '. $this->db->dbprefix('attribute_values') .' vals ';
|
||||
$query .= 'ON vals.attribute_id = links.attribute_id ';
|
||||
$query .= "SET links.attribute_id = IF((attribute_value IN('FALSE','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
|
||||
$query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
|
||||
$success = $this->db->query($query);
|
||||
|
||||
$this->db->trans_complete();
|
||||
}
|
||||
}
|
||||
|
||||
//From DROPDOWN
|
||||
else if($from_type === DROPDOWN)
|
||||
{
|
||||
//To TEXT
|
||||
if(in_array($to_type, [TEXT, CHECKBOX], TRUE))
|
||||
{
|
||||
$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();
|
||||
|
||||
//To CHECKBOX
|
||||
if($to_type === CHECKBOX)
|
||||
{
|
||||
$checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$query = 'UPDATE ospos_attribute_values vals ';
|
||||
$query .= 'INNER JOIN ospos_attribute_links links ';
|
||||
$query = 'UPDATE '. $this->db->dbprefix('attribute_links') .' links ';
|
||||
$query .= 'JOIN '. $this->db->dbprefix('attribute_values') .' vals ';
|
||||
$query .= 'ON vals.attribute_id = links.attribute_id ';
|
||||
$query .= "SET links.attribute_id = IF((vals.attribute_value IN('FALSE','0','') OR (vals.attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
|
||||
$query .= 'WHERE links.definition_id = ' . $this->db->escape($definition_id);
|
||||
$query .= "SET links.attribute_id = IF((attribute_value IN('FALSE','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
|
||||
$query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
|
||||
$success = $this->db->query($query);
|
||||
|
||||
$this->db->trans_complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//From any other type
|
||||
else
|
||||
{
|
||||
$success = TRUE;
|
||||
}
|
||||
|
||||
$this->delete_orphaned_links($definition_id);
|
||||
$this->delete_orphaned_values();
|
||||
return $success;
|
||||
}
|
||||
|
||||
@@ -410,7 +418,6 @@ class Attribute extends CI_Model
|
||||
*/
|
||||
public function save_definition(&$definition_data, $definition_id = NO_DEFINITION_ID)
|
||||
{
|
||||
//Run these queries as a transaction, we want to make sure we do all or nothing
|
||||
$this->db->trans_start();
|
||||
|
||||
//Definition doesn't exist
|
||||
@@ -418,7 +425,7 @@ class Attribute extends CI_Model
|
||||
{
|
||||
if($this->exists($definition_id,TRUE))
|
||||
{
|
||||
$success = $this->undelete($definition_id);
|
||||
$success = $this->undelete_definition($definition_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -430,26 +437,27 @@ class Attribute extends CI_Model
|
||||
//Definition already exists
|
||||
else
|
||||
{
|
||||
$this->db->select('definition_type, definition_name');
|
||||
$this->db->from('attribute_definitions');
|
||||
//Get current definition type and name
|
||||
$this->db->select('definition_type');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
$row = $this->db->get()->row();
|
||||
$row = $this->db->get('attribute_definitions')->row();
|
||||
$from_definition_type = $row->definition_type;
|
||||
$from_definition_name = $row->definition_name;
|
||||
$to_definition_type = $definition_data['definition_type'];
|
||||
|
||||
//Update the definition values
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
$success = $this->db->update('attribute_definitions', $definition_data);
|
||||
$definition_data['definition_id'] = $definition_id;
|
||||
|
||||
if($from_definition_type !== $to_definition_type)
|
||||
{
|
||||
if(!$this->convert_definition_type($definition_id,$from_definition_type,$to_definition_type))
|
||||
if($this->convert_definition_data($definition_id, $from_definition_type, $to_definition_type) === FALSE)
|
||||
{
|
||||
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();
|
||||
@@ -461,14 +469,14 @@ class Attribute extends CI_Model
|
||||
|
||||
public function get_definition_by_name($definition_name, $definition_type = FALSE)
|
||||
{
|
||||
$this->db->from('attribute_definitions');
|
||||
$this->db->where('definition_name', $definition_name);
|
||||
|
||||
if($definition_type != FALSE)
|
||||
{
|
||||
$this->db->where('definition_type', $definition_type);
|
||||
}
|
||||
|
||||
return $this->db->get()->result_array();
|
||||
return $this->db->get('attribute_definitions')->result_array();
|
||||
}
|
||||
|
||||
public function save_link($item_id, $definition_id, $attribute_id)
|
||||
@@ -485,7 +493,10 @@ class Attribute extends CI_Model
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->insert('attribute_links', array('attribute_id' => $attribute_id, 'item_id' => $item_id, 'definition_id' => $definition_id));
|
||||
$this->db->insert('attribute_links', array(
|
||||
'attribute_id' => $attribute_id,
|
||||
'item_id' => $item_id,
|
||||
'definition_id' => $definition_id));
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
@@ -493,20 +504,30 @@ class Attribute extends CI_Model
|
||||
return $this->db->trans_status();
|
||||
}
|
||||
|
||||
public function delete_link($item_id)
|
||||
public function delete_link($item_id, $definition_id = FALSE)
|
||||
{
|
||||
$delete_data = array('item_id' => $item_id);
|
||||
|
||||
//Exclude rows where sale_id or receiving_id has a value
|
||||
$this->db->where('sale_id');
|
||||
$this->db->where('receiving_id');
|
||||
|
||||
return $this->db->delete('attribute_links', array('item_id' => $item_id));
|
||||
if(!empty($definition_id))
|
||||
{
|
||||
$delete_data += ['definition_id' => $definition_id];
|
||||
}
|
||||
|
||||
$success = $this->db->delete('attribute_links', $delete_data);
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
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');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
return $this->db->get('attribute_links')->row_object();
|
||||
}
|
||||
@@ -516,11 +537,11 @@ class Attribute extends CI_Model
|
||||
$format = $this->db->escape(dateformat_mysql());
|
||||
$this->db->select("GROUP_CONCAT(attribute_value SEPARATOR ', ') AS attribute_values");
|
||||
$this->db->select("GROUP_CONCAT(DATE_FORMAT(attribute_date, $format) SEPARATOR ', ') AS attribute_dtvalues");
|
||||
$this->db->from('attribute_links');
|
||||
$this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
|
||||
$this->db->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
|
||||
$this->db->where('definition_type <>', GROUP);
|
||||
$this->db->where('deleted', 0);
|
||||
$this->db->where('item_id', intval($item_id));
|
||||
|
||||
if(!empty($id))
|
||||
{
|
||||
@@ -532,37 +553,47 @@ class Attribute extends CI_Model
|
||||
$this->db->where('receiving_id');
|
||||
}
|
||||
|
||||
$this->db->where('item_id', (int) $item_id);
|
||||
$this->db->where('definition_flags & ', $definition_flags);
|
||||
|
||||
return $this->db->get();
|
||||
return $this->db->get('attribute_links');
|
||||
}
|
||||
|
||||
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('item_id', intval($item_id));
|
||||
$this->db->where('sale_id');
|
||||
$this->db->where('receiving_id');
|
||||
$this->db->where('item_id', (int) $item_id);
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
return $this->db->get()->row_object();
|
||||
return $this->db->get('attribute_values')->row_object();
|
||||
}
|
||||
|
||||
public function get_attribute_values($item_id)
|
||||
{
|
||||
$this->db->select('attribute_values.attribute_value, attribute_values.attribute_decimal, attribute_values.attribute_date, attribute_links.definition_id');
|
||||
$this->db->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
|
||||
$this->db->where('item_id', intval($item_id));
|
||||
|
||||
$results = $this->db->get('attribute_links')->result_array();
|
||||
|
||||
return $this->to_array($results, 'definition_id');
|
||||
}
|
||||
|
||||
|
||||
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'
|
||||
'INSERT INTO ' . $this->db->dbprefix('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();
|
||||
$suggestions = [];
|
||||
$this->db->distinct();
|
||||
$this->db->select('attribute_value, attribute_values.attribute_id');
|
||||
$this->db->from('attribute_definitions AS definition');
|
||||
@@ -586,25 +617,32 @@ class Attribute extends CI_Model
|
||||
{
|
||||
$this->db->trans_start();
|
||||
|
||||
$locale_date_format = $this->Appconfig->get('dateformat');
|
||||
|
||||
//New Attribute
|
||||
if(empty($attribute_id) || empty($item_id))
|
||||
{
|
||||
if(in_array($definition_type, [TEXT, DROPDOWN, CHECKBOX], TRUE))
|
||||
{
|
||||
$attribute_id = $this->value_exists($attribute_value);
|
||||
//Update attribute_value
|
||||
$attribute_id = $this->value_exists($attribute_value, $definition_type);
|
||||
|
||||
if(empty($attribute_id))
|
||||
if($attribute_id === FALSE)
|
||||
{
|
||||
switch($definition_type)
|
||||
{
|
||||
$this->db->insert('attribute_values', array('attribute_value' => $attribute_value));
|
||||
case DATE:
|
||||
$data_type = 'date';
|
||||
$attribute_date_value = DateTime::createFromFormat($locale_date_format, $attribute_value);
|
||||
$attribute_value = $attribute_date_value->format('Y-m-d');
|
||||
break;
|
||||
case DECIMAL:
|
||||
$data_type = 'decimal';
|
||||
break;
|
||||
default:
|
||||
$data_type = 'value';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if($definition_type == DECIMAL)
|
||||
{
|
||||
$this->db->insert('attribute_values', array('attribute_decimal' => $attribute_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->insert('attribute_values', array('attribute_date' => date('Y-m-d', strtotime($attribute_value))));
|
||||
|
||||
$this->db->insert('attribute_values', array("attribute_$data_type" => $attribute_value));
|
||||
}
|
||||
|
||||
$attribute_id = $attribute_id ? $attribute_id : $this->db->insert_id();
|
||||
@@ -614,24 +652,26 @@ 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);
|
||||
switch($definition_type)
|
||||
{
|
||||
case DATE:
|
||||
$data_type = 'date';
|
||||
$attribute_date_value = DateTime::createFromFormat($locale_date_format, $attribute_value);
|
||||
$attribute_value = $attribute_date_value->format('Y-m-d');
|
||||
break;
|
||||
case DECIMAL:
|
||||
$data_type = 'decimal';
|
||||
break;
|
||||
default:
|
||||
$data_type = 'value';
|
||||
break;
|
||||
}
|
||||
|
||||
if(in_array($definition_type, [TEXT, DROPDOWN], TRUE))
|
||||
{
|
||||
$this->db->update('attribute_values', array('attribute_value' => $attribute_value));
|
||||
}
|
||||
else if($definition_type == DECIMAL)
|
||||
{
|
||||
$this->db->update('attribute_values', array('attribute_decimal' => $attribute_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->update('attribute_values', array('attribute_date' => date('Y-m-d', strtotime($attribute_value))));
|
||||
}
|
||||
$this->db->where('attribute_id', $attribute_id);
|
||||
$this->db->update('attribute_values', array("attribute_$data_type" => $attribute_value));
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
@@ -641,14 +681,14 @@ class Attribute extends CI_Model
|
||||
|
||||
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));
|
||||
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
|
||||
*
|
||||
* @param unknown $definition_id Attribute definition ID to remove.
|
||||
* @param int $definition_id Attribute definition ID to remove.
|
||||
* @return boolean TRUE if successful and FALSE if there is a failure
|
||||
*/
|
||||
public function delete_definition($definition_id)
|
||||
@@ -666,6 +706,33 @@ class Attribute extends CI_Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any attribute_links for a specific definition that do not have an item_id associated with them and are not DROPDOWN types
|
||||
*
|
||||
* @param int $definition_id
|
||||
* @return boolean TRUE is returned if the delete was successful or FALSE if there were any failures
|
||||
*/
|
||||
public function delete_orphaned_links($definition_id)
|
||||
{
|
||||
$this->db->select('definition_type');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
$definition = $this->db->get('attribute_definitions')->row();
|
||||
|
||||
if($definition->definition_type != DROPDOWN)
|
||||
{
|
||||
$this->db->trans_start();
|
||||
|
||||
$this->db->where('item_id');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
$this->db->delete('attribute_links');
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
return $this->db->trans_status();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes any orphaned values that do not have associated links
|
||||
* @param int $definition_id
|
||||
* @return boolean TRUE is returned if the delete was successful or FALSE if there were any failures
|
||||
@@ -693,6 +760,48 @@ class Attribute extends CI_Model
|
||||
{
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
return $this->db->update('attribute_definitions', array('deleted'=>0));
|
||||
return $this->db->update('attribute_definitions', array('deleted' => 0));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array attributes attributes that need to be fixed
|
||||
* @param int $definition_id
|
||||
* @param string $definition_type This dictates what column should be populated in any new attribute_values that are created
|
||||
*/
|
||||
public function attribute_cleanup($attributes, $definition_id, $definition_type)
|
||||
{
|
||||
$this->db->trans_begin();
|
||||
|
||||
foreach($attributes as $attribute)
|
||||
{
|
||||
$new_attribute_id = $this->save_value($attribute['attribute_value'], $definition_id, FALSE, $attribute['attribute_id'], $definition_type);
|
||||
|
||||
if($this->save_link($attribute['item_id'], $definition_id, $new_attribute_id) == FALSE)
|
||||
{
|
||||
log_message('Error', 'Transaction failed');
|
||||
$this->db->trans_rollback();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
$success = $this->delete_orphaned_links($definition_id);
|
||||
|
||||
$this->db->trans_commit();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all attribute_ids and item_ids assigned to that definition_id
|
||||
*
|
||||
* @param int $definition_id
|
||||
* @return array All attribute_id and item_id pairs in the attribute_links table with that attribute definition_id
|
||||
*/
|
||||
public function get_attributes_by_definition($definition_id)
|
||||
{
|
||||
$this->db->select('attribute_links.attribute_id, item_id, attribute_value, attribute_decimal, attribute_date');
|
||||
$this->db->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
|
||||
$this->db->where('definition_id', $definition_id);
|
||||
|
||||
return $this->db->get('attribute_links')->result_array();
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,15 @@ class Item extends CI_Model
|
||||
{
|
||||
// check if $item_id is a number and not a string starting with 0
|
||||
// because cases like 00012345 will be seen as a number where it is a barcode
|
||||
if(ctype_digit($item_id) && substr($item_id, 0, 1) != '0')
|
||||
if(ctype_digit($item_id) && substr($item_id, 0, 1) !== '0')
|
||||
{
|
||||
$this->db->from('items');
|
||||
$this->db->where('item_id', (int) $item_id);
|
||||
if($ignore_deleted == FALSE)
|
||||
$this->db->where('item_id', intval($item_id));
|
||||
if($ignore_deleted === FALSE)
|
||||
{
|
||||
$this->db->where('deleted', $deleted);
|
||||
}
|
||||
|
||||
return ($this->db->get()->num_rows() == 1);
|
||||
return ($this->db->get('items')->num_rows() === 1);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@@ -37,16 +36,15 @@ class Item extends CI_Model
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->db->from('items');
|
||||
$this->db->where('item_number', (string) $item_number);
|
||||
// check if $item_id is a number and not a string starting with 0
|
||||
// because cases like 00012345 will be seen as a number where it is a barcode
|
||||
if(ctype_digit($item_id) && substr($item_id, 0, 1) != '0')
|
||||
{
|
||||
$this->db->where('item_id !=', (int) $item_id);
|
||||
$this->db->where('item_id !=', intval($item_id));
|
||||
}
|
||||
|
||||
return $this->db->get()->num_rows() >= 1;
|
||||
return ($this->db->get('items')->num_rows() >= 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -82,7 +80,7 @@ class Item extends CI_Model
|
||||
public function search($search, $filters, $rows = 0, $limit_from = 0, $sort = 'items.name', $order = 'asc', $count_only = FALSE)
|
||||
{
|
||||
// get_found_rows case
|
||||
if($count_only == TRUE)
|
||||
if($count_only === TRUE)
|
||||
{
|
||||
$this->db->select('COUNT(DISTINCT items.item_id) AS count');
|
||||
}
|
||||
@@ -208,7 +206,7 @@ class Item extends CI_Model
|
||||
}
|
||||
|
||||
// get_found_rows case
|
||||
if($count_only == TRUE)
|
||||
if($count_only === TRUE)
|
||||
{
|
||||
return $this->db->get()->row()->count;
|
||||
}
|
||||
@@ -262,13 +260,12 @@ class Item extends CI_Model
|
||||
$this->db->select('GROUP_CONCAT(attribute_value SEPARATOR \'|\') AS attribute_values');
|
||||
$this->db->select('GROUP_CONCAT(attribute_decimal SEPARATOR \'|\') AS attribute_dvalues');
|
||||
$this->db->select('GROUP_CONCAT(attribute_date SEPARATOR \'|\') AS attribute_dtvalues');
|
||||
$this->db->from('items');
|
||||
$this->db->join('attribute_links', 'attribute_links.item_id = items.item_id', 'left');
|
||||
$this->db->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left');
|
||||
$this->db->where('items.item_id', $item_id);
|
||||
$this->db->group_by('items.item_id');
|
||||
|
||||
$query = $this->db->get();
|
||||
$query = $this->db->get('items');
|
||||
|
||||
if($query->num_rows() == 1)
|
||||
{
|
||||
@@ -294,17 +291,14 @@ class Item extends CI_Model
|
||||
*/
|
||||
public function get_info_by_id_or_number($item_id, $include_deleted = TRUE)
|
||||
{
|
||||
$this->db->from('items');
|
||||
|
||||
$this->db->group_start();
|
||||
|
||||
$this->db->where('items.item_number', $item_id);
|
||||
|
||||
// check if $item_id is a number and not a string starting with 0
|
||||
// because cases like 00012345 will be seen as a number where it is a barcode
|
||||
if(ctype_digit($item_id) && substr($item_id, 0, 1) != '0')
|
||||
{
|
||||
$this->db->or_where('items.item_id', (int) $item_id);
|
||||
$this->db->or_where('items.item_id', intval($item_id));
|
||||
}
|
||||
|
||||
$this->db->group_end();
|
||||
@@ -318,7 +312,7 @@ class Item extends CI_Model
|
||||
// due to barcode and item_id clash
|
||||
$this->db->limit(1);
|
||||
|
||||
$query = $this->db->get();
|
||||
$query = $this->db->get('items');
|
||||
|
||||
if($query->num_rows() == 1)
|
||||
{
|
||||
@@ -390,10 +384,16 @@ class Item extends CI_Model
|
||||
$this->db->where('item_id', $item_data['item_id']);
|
||||
$this->db->update('items', array('low_sell_item_id'=>$item_data['item_id']));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$item_data['item_id'] = $item_id;
|
||||
}
|
||||
|
||||
$this->db->where('item_id', $item_id);
|
||||
|
||||
@@ -546,7 +546,7 @@ class Item extends CI_Model
|
||||
|
||||
public function get_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
$non_kit = array(ITEM, ITEM_AMOUNT_ENTRY);
|
||||
|
||||
$this->db->select($this->get_search_suggestion_format('item_id, name, pack_name'));
|
||||
@@ -614,16 +614,16 @@ class Item extends CI_Model
|
||||
}
|
||||
|
||||
//Search by custom fields
|
||||
if($filters['search_custom'] != FALSE)
|
||||
if($filters['search_custom'] !== FALSE)
|
||||
{
|
||||
$this->db->from('attribute_links');
|
||||
$this->db->join('attribute_values','attribute_links.attribute_id = attribute_values.attribute_id');
|
||||
$this->db->join('attribute_values', '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)
|
||||
foreach($this->db->get('attribute_links')->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
|
||||
}
|
||||
@@ -642,7 +642,7 @@ class Item extends CI_Model
|
||||
|
||||
public function get_stock_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
$non_kit = array(ITEM, ITEM_AMOUNT_ENTRY);
|
||||
|
||||
$this->db->select($this->get_search_suggestion_format('item_id, name, pack_name'));
|
||||
@@ -716,16 +716,16 @@ class Item extends CI_Model
|
||||
}
|
||||
|
||||
//Search by custom fields
|
||||
if($filters['search_custom'] != FALSE)
|
||||
if($filters['search_custom'] !== FALSE)
|
||||
{
|
||||
$this->db->from('attribute_links');
|
||||
$this->db->join('attribute_links.attribute_id = attribute_values.attribute_id');
|
||||
$this->db->join('attribute_values', '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)
|
||||
|
||||
foreach($this->db->get('attribute_links')->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
|
||||
}
|
||||
@@ -743,16 +743,15 @@ class Item extends CI_Model
|
||||
|
||||
public function get_kit_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
$non_kit = array(ITEM, ITEM_AMOUNT_ENTRY);
|
||||
|
||||
$this->db->select('item_id, name');
|
||||
$this->db->from('items');
|
||||
$this->db->where('deleted', $filters['is_deleted']);
|
||||
$this->db->where('item_type', ITEM_KIT);
|
||||
$this->db->like('name', $search);
|
||||
$this->db->order_by('name', 'asc');
|
||||
foreach($this->db->get()->result() as $row)
|
||||
foreach($this->db->get('items')->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('value' => $row->item_id, 'label' => $row->name);
|
||||
}
|
||||
@@ -778,6 +777,7 @@ class Item extends CI_Model
|
||||
$this->db->distinct();
|
||||
$this->db->like('category', $search);
|
||||
$this->db->order_by('category', 'asc');
|
||||
|
||||
foreach($this->db->get()->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('label' => $row->category);
|
||||
@@ -787,10 +787,12 @@ class Item extends CI_Model
|
||||
$this->db->select('company_name');
|
||||
$this->db->from('suppliers');
|
||||
$this->db->like('company_name', $search);
|
||||
|
||||
// restrict to non deleted companies only if is_deleted is FALSE
|
||||
$this->db->where('deleted', $filters['is_deleted']);
|
||||
$this->db->distinct();
|
||||
$this->db->order_by('company_name', 'asc');
|
||||
|
||||
foreach($this->db->get()->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('label' => $row->company_name);
|
||||
@@ -813,31 +815,19 @@ class Item extends CI_Model
|
||||
}
|
||||
|
||||
//Search by custom fields
|
||||
if($filters['search_custom'] != FALSE)
|
||||
if($filters['search_custom'] !== FALSE)
|
||||
{
|
||||
// This section is currently never used but custom fields are replaced with attributes
|
||||
// therefore in case this feature is required a proper query needs to be written here
|
||||
/*
|
||||
$this->db->from('items');
|
||||
$this->db->group_start();
|
||||
$this->db->where('item_type', ITEM_KIT);
|
||||
$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->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)
|
||||
|
||||
foreach($this->db->get('attribute_links')->result() as $row)
|
||||
{
|
||||
$suggestions[] = array('value' => $row->item_id, 'label' => $row->name);
|
||||
$suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,7 +842,7 @@ class Item extends CI_Model
|
||||
|
||||
public function get_low_sell_suggestions($search)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
|
||||
$this->db->select($this->get_search_suggestion_format('item_id, pack_name'));
|
||||
$this->db->from('items');
|
||||
@@ -870,7 +860,7 @@ class Item extends CI_Model
|
||||
|
||||
public function get_category_suggestions($search)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
$this->db->distinct();
|
||||
$this->db->select('category');
|
||||
$this->db->from('items');
|
||||
@@ -887,7 +877,7 @@ class Item extends CI_Model
|
||||
|
||||
public function get_location_suggestions($search)
|
||||
{
|
||||
$suggestions = array();
|
||||
$suggestions = [];
|
||||
$this->db->distinct();
|
||||
$this->db->select('location');
|
||||
$this->db->from('items');
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<ul id="error_message_box" class="error_message_box"></ul>
|
||||
|
||||
<?php echo form_open_multipart('items/do_csv_import/', array('id'=>'csv_form', 'class'=>'form-horizontal')); ?>
|
||||
<?php echo form_open_multipart('items/import_csv_file/', array('id'=>'csv_form', 'class'=>'form-horizontal')); ?>
|
||||
<fieldset id="item_basic_info">
|
||||
<div class="form-group form-group-sm">
|
||||
<div class="col-xs-12">
|
||||
<a href="<?php echo site_url('items/csv'); ?>"><?php echo $this->lang->line('common_download_import_template'); ?></a>
|
||||
<a href="<?php echo site_url('items/generate_csv_file'); ?>"><?php echo $this->lang->line('common_download_import_template'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<div class='col-xs-12'>
|
||||
<div class="fileinput fileinput-new input-group" data-provides="fileinput">
|
||||
<div class="form-control" data-trigger="fileinput"><i class="glyphicon glyphicon-file fileinput-exists"></i><span class="fileinput-filename"></span></div>
|
||||
<span class="input-group-addon input-sm btn btn-default btn-file"><span class="fileinput-new"><?php echo $this->lang->line("common_import_select_file"); ?></span><span class="fileinput-exists"><?php echo $this->lang->line("common_import_change_file"); ?></span><input type="file" id="file_path" name="file_path" accept=".csv"></span>
|
||||
<a href="#" class="input-group-addon input-sm btn btn-default fileinput-exists" data-dismiss="fileinput"><?php echo $this->lang->line("common_import_remove_file"); ?></a>
|
||||
<span class="input-group-addon input-sm btn btn-default btn-file"><span class="fileinput-new"><?php echo $this->lang->line('common_import_select_file'); ?></span><span class="fileinput-exists"><?php echo $this->lang->line('common_import_change_file'); ?></span><input type="file" id="file_path" name="file_path" accept=".csv"></span>
|
||||
<a href="#" class="input-group-addon input-sm btn btn-default fileinput-exists" data-dismiss="fileinput"><?php echo $this->lang->line('common_import_remove_file'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php $this->load->view("partial/header"); ?>
|
||||
<?php $this->load->view('partial/header'); ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function()
|
||||
@@ -17,7 +17,7 @@ $(document).ready(function()
|
||||
table_support.refresh();
|
||||
});
|
||||
|
||||
// load the preset datarange picker
|
||||
// load the preset daterange picker
|
||||
<?php $this->load->view('partial/daterangepicker'); ?>
|
||||
// set the beginning of time as starting date
|
||||
$('#daterangepicker').data('daterangepicker').setStartDate("<?php echo date($this->config->item('dateformat'), mktime(0,0,0,01,01,2010));?>");
|
||||
@@ -58,28 +58,28 @@ $(document).ready(function()
|
||||
</script>
|
||||
|
||||
<div id="title_bar" class="btn-toolbar print_hide">
|
||||
<button class='btn btn-info btn-sm pull-right modal-dlg' data-btn-submit='<?php echo $this->lang->line('common_submit') ?>' data-href='<?php echo site_url($controller_name."/csv_import"); ?>'
|
||||
<button class='btn btn-info btn-sm pull-right modal-dlg' data-btn-submit='<?php echo $this->lang->line('common_submit') ?>' data-href='<?php echo site_url("$controller_name/csv_import"); ?>'
|
||||
title='<?php echo $this->lang->line('items_import_items_csv'); ?>'>
|
||||
<span class="glyphicon glyphicon-import"> </span><?php echo $this->lang->line('common_import_csv'); ?>
|
||||
<span class="glyphicon glyphicon-import"> </span><?php echo $this->lang->line('common_import_csv'); ?>
|
||||
</button>
|
||||
|
||||
<button class='btn btn-info btn-sm pull-right modal-dlg' data-btn-new='<?php echo $this->lang->line('common_new') ?>' data-btn-submit='<?php echo $this->lang->line('common_submit') ?>' data-href='<?php echo site_url($controller_name."/view"); ?>'
|
||||
<button class='btn btn-info btn-sm pull-right modal-dlg' data-btn-new='<?php echo $this->lang->line('common_new') ?>' data-btn-submit='<?php echo $this->lang->line('common_submit') ?>' data-href='<?php echo site_url("$controller_name/view"); ?>'
|
||||
title='<?php echo $this->lang->line($controller_name . '_new'); ?>'>
|
||||
<span class="glyphicon glyphicon-tag"> </span><?php echo $this->lang->line($controller_name. '_new'); ?>
|
||||
<span class="glyphicon glyphicon-tag"> </span><?php echo $this->lang->line($controller_name. '_new'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="toolbar">
|
||||
<div class="pull-left form-inline" role="toolbar">
|
||||
<button id="delete" class="btn btn-default btn-sm print_hide">
|
||||
<span class="glyphicon glyphicon-trash"> </span><?php echo $this->lang->line("common_delete"); ?>
|
||||
<span class="glyphicon glyphicon-trash"> </span><?php echo $this->lang->line('common_delete'); ?>
|
||||
</button>
|
||||
<button id="bulk_edit" class="btn btn-default btn-sm modal-dlg print_hide", data-btn-submit='<?php echo $this->lang->line('common_submit') ?>', data-href='<?php echo site_url($controller_name."/bulk_edit"); ?>'
|
||||
<button id="bulk_edit" class="btn btn-default btn-sm modal-dlg print_hide", data-btn-submit='<?php echo $this->lang->line('common_submit') ?>', data-href='<?php echo site_url("$controller_name/bulk_edit"); ?>'
|
||||
title='<?php echo $this->lang->line('items_edit_multiple_items'); ?>'>
|
||||
<span class="glyphicon glyphicon-edit"> </span><?php echo $this->lang->line("items_bulk_edit"); ?>
|
||||
<span class="glyphicon glyphicon-edit"> </span><?php echo $this->lang->line("items_bulk_edit"); ?>
|
||||
</button>
|
||||
<button id="generate_barcodes" class="btn btn-default btn-sm print_hide" data-href='<?php echo site_url($controller_name."/generate_barcodes"); ?>' title='<?php echo $this->lang->line('items_generate_barcodes');?>'>
|
||||
<span class="glyphicon glyphicon-barcode"> </span><?php echo $this->lang->line("items_generate_barcodes"); ?>
|
||||
<button id="generate_barcodes" class="btn btn-default btn-sm print_hide" data-href='<?php echo site_url("$controller_name/generate_barcodes"); ?>' title='<?php echo $this->lang->line('items_generate_barcodes');?>'>
|
||||
<span class="glyphicon glyphicon-barcode"> </span><?php echo $this->lang->line('items_generate_barcodes'); ?>
|
||||
</button>
|
||||
<?php echo form_input(array('name'=>'daterangepicker', 'class'=>'form-control input-sm', 'id'=>'daterangepicker')); ?>
|
||||
<?php echo form_multiselect('filters[]', $filters, '', array('id'=>'filters', 'class'=>'selectpicker show-menu-arrow', 'data-none-selected-text'=>$this->lang->line('common_none_selected_text'), 'data-selected-text-format'=>'count > 1', 'data-style'=>'btn-default btn-sm', 'data-width'=>'fit')); ?>
|
||||
@@ -96,4 +96,4 @@ $(document).ready(function()
|
||||
<table id="table"></table>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view("partial/footer"); ?>
|
||||
<?php $this->load->view('partial/footer'); ?>
|
||||
|
||||
Reference in New Issue
Block a user