diff --git a/Dockerfile b/Dockerfile index d536ef467..0f27b870b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM php:5-apache +FROM php:7.0.15-apache MAINTAINER jekkos RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ php5-apcu \ @@ -7,7 +7,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ libmcrypt-dev RUN a2enmod rewrite -RUN docker-php-ext-install mysql mysqli bcmath intl gd sockets mbstring mcrypt +RUN docker-php-ext-install mysqli bcmath intl gd sockets mbstring mcrypt RUN echo "date.timezone = \"\${PHP_TIMEZONE}\"" > /usr/local/etc/php/conf.d/timezone.ini RUN echo -e “$(hostname -i)\t$(hostname) $(hostname).localhost” >> /etc/hosts diff --git a/LICENSE b/LICENSE index 99391a1e9..c7993cd5b 100644 --- a/LICENSE +++ b/LICENSE @@ -12,6 +12,7 @@ Copyright (c) 2015 Toni Haryanto (aka yllumi) Copyright (c) 2016-2017 Ramkrishna Mondal (aka RamkrishnaMondal) Copyright (c) 2016 Rinaldy@dbarber (aka rnld26) Copyright (c) 2016 Jorge Colmenarez (aka jlctmaster), frontuari.com +Copyright (c) 2017 Steve Ireland Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/application/controllers/Config.php b/application/controllers/Config.php index 483090e6f..e4154cde7 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -9,6 +9,7 @@ class Config extends Secure_Controller parent::__construct('config'); $this->load->library('barcode_lib'); + $this->load->library('sale_lib'); } /* @@ -194,7 +195,8 @@ class Config extends Secure_Controller $data['stock_locations'] = $this->Stock_location->get_all()->result_array(); $data['support_barcode'] = $this->barcode_lib->get_list_barcodes(); $data['logo_exists'] = $this->config->item('company_logo') != ''; - + $data['line_sequence_options'] = $this->sale_lib->get_line_sequence_options(); + $data = $this->xss_clean($data); // load all the license statements, they are already XSS cleaned in the private function @@ -373,7 +375,6 @@ class Config extends Secure_Controller private function _clear_session_state() { - $this->load->library('sale_lib'); $this->sale_lib->clear_sale_location(); $this->sale_lib->clear_all(); $this->load->library('receiving_lib'); @@ -415,9 +416,9 @@ class Config extends Secure_Controller echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); } - public function save_barcode() - { - $batch_save_data = array( + public function save_barcode() + { + $batch_save_data = array( 'barcode_type' => $this->input->post('barcode_type'), 'barcode_quality' => $this->input->post('barcode_quality'), 'barcode_width' => $this->input->post('barcode_width'), @@ -432,17 +433,17 @@ class Config extends Secure_Controller 'barcode_page_cellspacing' => $this->input->post('barcode_page_cellspacing'), 'barcode_generate_if_empty' => $this->input->post('barcode_generate_if_empty') != NULL, 'barcode_content' => $this->input->post('barcode_content') - ); - - $result = $this->Appconfig->batch_save($batch_save_data); - $success = $result ? TRUE : FALSE; + ); + + $result = $this->Appconfig->batch_save($batch_save_data); + $success = $result ? TRUE : FALSE; - echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); - } - - public function save_receipt() - { - $batch_save_data = array ( + echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); + } + + public function save_receipt() + { + $batch_save_data = array ( 'receipt_template' => $this->input->post('receipt_template'), 'receipt_show_taxes' => $this->input->post('receipt_show_taxes') != NULL, 'receipt_show_total_discount' => $this->input->post('receipt_show_total_discount') != NULL, @@ -457,27 +458,28 @@ class Config extends Secure_Controller 'print_right_margin' => $this->input->post('print_right_margin') ); - $result = $this->Appconfig->batch_save($batch_save_data); - $success = $result ? TRUE : FALSE; + $result = $this->Appconfig->batch_save($batch_save_data); + $success = $result ? TRUE : FALSE; - echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); - } + echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); + } - public function save_invoice() - { - $batch_save_data = array ( + public function save_invoice() + { + $batch_save_data = array ( 'invoice_enable' => $this->input->post('invoice_enable') != NULL, 'sales_invoice_format' => $this->input->post('sales_invoice_format'), 'recv_invoice_format' => $this->input->post('recv_invoice_format'), 'invoice_default_comments' => $this->input->post('invoice_default_comments'), - 'invoice_email_message' => $this->input->post('invoice_email_message') + 'invoice_email_message' => $this->input->post('invoice_email_message'), + 'line_sequence' => $this->input->post('line_sequence') ); - $result = $this->Appconfig->batch_save($batch_save_data); - $success = $result ? TRUE : FALSE; + $result = $this->Appconfig->batch_save($batch_save_data); + $success = $result ? TRUE : FALSE; - echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); - } + echo json_encode(array('success' => $success, 'message' => $this->lang->line('config_saved_' . ($success ? '' : 'un') . 'successfully'))); + } public function remove_logo() { @@ -485,22 +487,22 @@ class Config extends Secure_Controller echo json_encode(array('success' => $result)); } - - private function _handle_logo_upload() - { - $this->load->helper('directory'); - // load upload library - $config = array('upload_path' => './uploads/', - 'allowed_types' => 'gif|jpg|png', - 'max_size' => '1024', - 'max_width' => '800', - 'max_height' => '680', - 'file_name' => 'company_logo'); - $this->load->library('upload', $config); - $this->upload->do_upload('company_logo'); + private function _handle_logo_upload() + { + $this->load->helper('directory'); - return strlen($this->upload->display_errors()) == 0 || !strcmp($this->upload->display_errors(), '

'.$this->lang->line('upload_no_file_selected').'

'); + // load upload library + $config = array('upload_path' => './uploads/', + 'allowed_types' => 'gif|jpg|png', + 'max_size' => '1024', + 'max_width' => '800', + 'max_height' => '680', + 'file_name' => 'company_logo'); + $this->load->library('upload', $config); + $this->upload->do_upload('company_logo'); + + return strlen($this->upload->display_errors()) == 0 || !strcmp($this->upload->display_errors(), '

'.$this->lang->line('upload_no_file_selected').'

'); } private function _check_encryption() @@ -557,35 +559,35 @@ class Config extends Secure_Controller return TRUE; } - - public function backup_db() - { - $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; - if($this->Employee->has_module_grant('config', $employee_id)) - { - $this->load->dbutil(); - $prefs = array( + public function backup_db() + { + $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; + if($this->Employee->has_module_grant('config', $employee_id)) + { + $this->load->dbutil(); + + $prefs = array( 'format' => 'zip', 'filename' => 'ospos.sql' - ); - - $backup = $this->dbutil->backup($prefs); - - $file_name = 'ospos-' . date("Y-m-d-H-i-s") .'.zip'; - $save = 'uploads/' . $file_name; - $this->load->helper('download'); - while(ob_get_level()) - { - ob_end_clean(); - } + ); - force_download($file_name, $backup); - } - else - { - redirect('no_access/config'); - } - } + $backup = $this->dbutil->backup($prefs); + + $file_name = 'ospos-' . date("Y-m-d-H-i-s") .'.zip'; + $save = 'uploads/' . $file_name; + $this->load->helper('download'); + while(ob_get_level()) + { + ob_end_clean(); + } + + force_download($file_name, $backup); + } + else + { + redirect('no_access/config'); + } + } } ?> diff --git a/application/controllers/Item_kits.php b/application/controllers/Item_kits.php index 07498a20f..6950b377a 100644 --- a/application/controllers/Item_kits.php +++ b/application/controllers/Item_kits.php @@ -84,23 +84,35 @@ class Item_kits extends Secure_Controller public function view($item_kit_id = -1) { $info = $this->Item_kit->get_info($item_kit_id); + + if($item_kit_id == -1) + { + $info->price_option = '0'; + $info->print_option = '0'; + } foreach(get_object_vars($info) as $property => $value) { $info->$property = $this->xss_clean($value); } + $data['item_kit_info'] = $info; - + $items = array(); foreach($this->Item_kit_items->get_info($item_kit_id) as $item_kit_item) { + $item['kit_sequence'] = $this->xss_clean($item_kit_item['kit_sequence']); $item['name'] = $this->xss_clean($this->Item->get_info($item_kit_item['item_id'])->name); $item['item_id'] = $this->xss_clean($item_kit_item['item_id']); $item['quantity'] = $this->xss_clean($item_kit_item['quantity']); - + $items[] = $item; } + $data['item_kit_items'] = $items; + $data['selected_kit_item_id'] = $info->kit_item_id; + $data['selected_kit_item'] = ($item_kit_id > 0 && isset($info->kit_item_id)) ? $info->item_name : ''; + $this->load->view("item_kits/form", $data); } @@ -108,36 +120,54 @@ class Item_kits extends Secure_Controller { $item_kit_data = array( 'name' => $this->input->post('name'), + 'item_id' => $this->input->post('kit_item_id'), + 'kit_discount_percent' => $this->input->post('kit_discount_percent'), + 'price_option' => $this->input->post('price_option'), + 'print_option' => $this->input->post('print_option'), 'description' => $this->input->post('description') ); if($this->Item_kit->save($item_kit_data, $item_kit_id)) { $success = TRUE; + $new_item = FALSE; //New item kit if ($item_kit_id == -1) { $item_kit_id = $item_kit_data['item_kit_id']; + $new_item = TRUE; } - if($this->input->post('item_kit_item') != NULL) + if($this->input->post('item_kit_qty') != NULL) { $item_kit_items = array(); - foreach($this->input->post('item_kit_item') as $item_id => $quantity) + foreach($this->input->post('item_kit_qty') as $item_id => $quantity) { + $seq = $this->input->post('item_kit_seq[' . $item_id . ']'); $item_kit_items[] = array( 'item_id' => $item_id, - 'quantity' => $quantity + 'quantity' => $quantity, + 'kit_sequence' => $seq ); } - $success = $this->Item_kit_items->save($item_kit_items, $item_kit_id); } + $success = $this->Item_kit_items->save($item_kit_items, $item_kit_id); + $item_kit_data = $this->xss_clean($item_kit_data); - echo json_encode(array('success' => $success, - 'message' => $this->lang->line('item_kits_successful_adding').' '.$item_kit_data['name'], 'id' => $item_kit_id)); + if($new_item) + { + echo json_encode(array('success' => $success, + 'message' => $this->lang->line('item_kits_successful_adding').' '.$item_kit_data['name'], 'id' => $item_kit_id)); + + } + else + { + echo json_encode(array('success' => $success, + 'message' => $this->lang->line('item_kits_successful_updating').' '.$item_kit_data['name'], 'id' => $item_kit_id)); + } } else//failure { @@ -182,7 +212,7 @@ class Item_kits extends Secure_Controller } $data['items'] = $result; - $barcode_config = $this->barcode_lib->get_barcode_config(); + $barcode_config = $this->barcode_lib->get_barcode_config(); // in case the selected barcode type is not Code39 or Code128 we set by default Code128 // the rationale for this is that EAN codes cannot have strings as seed, so 'KIT ' is not allowed if($barcode_config['barcode_type'] != 'Code39' && $barcode_config['barcode_type'] != 'Code128') @@ -195,4 +225,4 @@ class Item_kits extends Secure_Controller $this->load->view("barcodes/barcode_sheet", $data); } } -?> \ No newline at end of file +?> diff --git a/application/controllers/Items.php b/application/controllers/Items.php index e101ad477..770fa791f 100644 --- a/application/controllers/Items.php +++ b/application/controllers/Items.php @@ -190,9 +190,11 @@ class Items extends Secure_Controller { $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 = 0; $item_info->reorder_level = 0; + $item_info->item_type = '0'; // standard + $item_info->stock_type = '0'; // stock } $data['item_info'] = $item_info; @@ -225,19 +227,19 @@ class Items extends Secure_Controller } $data['image_path'] = sizeof($images) > 0 ? base_url($images[0]) : ''; $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); - foreach($stock_locations as $location) - { + 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; - } + } $this->load->view('items/form', $data); } - + public function inventory($item_id = -1) { $item_info = $this->Item->get_info($item_id); @@ -247,16 +249,16 @@ class Items extends Secure_Controller } $data['item_info'] = $item_info; - $data['stock_locations'] = array(); - $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); - foreach($stock_locations as $location) - { + $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; - } + $data['stock_locations'][$location['location_id']] = $location['location_name']; + $data['item_quantities'][$location['location_id']] = $quantity; + } $this->load->view('items/form_inventory', $data); } @@ -270,16 +272,16 @@ class Items extends Secure_Controller } $data['item_info'] = $item_info; - $data['stock_locations'] = array(); - $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); - foreach($stock_locations as $location) - { + $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; - } + $data['stock_locations'][$location['location_id']] = $location['location_name']; + $data['item_quantities'][$location['location_id']] = $quantity; + } $this->load->view('items/form_count_details', $data); } @@ -351,6 +353,8 @@ class Items extends Secure_Controller 'name' => $this->input->post('name'), 'description' => $this->input->post('description'), 'category' => $this->input->post('category'), + 'item_type' => $this->input->post('item_type'), + 'stock_type' => $this->input->post('stock_type'), 'supplier_id' => $this->input->post('supplier_id') == '' ? NULL : $this->input->post('supplier_id'), 'item_number' => $this->input->post('item_number') == '' ? NULL : $this->input->post('item_number'), 'cost_price' => parse_decimals($this->input->post('cost_price')), @@ -408,45 +412,45 @@ 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) - { - $updated_quantity = parse_decimals($this->input->post('quantity_' . $location['location_id'])); - $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, - 'trans_user' => $employee_id, - 'trans_location' => $location['location_id'], - '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 quantity + $stock_locations = $this->Stock_location->get_undeleted_all()->result_array(); + foreach($stock_locations as $location) + { + $updated_quantity = parse_decimals($this->input->post('quantity_' . $location['location_id'])); + $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, + 'trans_user' => $employee_id, + 'trans_location' => $location['location_id'], + 'trans_comment' => $this->lang->line('items_manually_editing_of_quantity'), + 'trans_inventory' => $updated_quantity - $item_quantity->quantity + ); + + $success &= $this->Inventory->insert($inv_data); + } + } if($success && $upload_success) - { - $message = $this->xss_clean($this->lang->line('items_successful_' . ($new_item ? 'adding' : 'updating')) . ' ' . $item_data['name']); + { + $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' => 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)); - } + echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => $item_id)); + } } else//failure { @@ -461,7 +465,23 @@ class Items extends Secure_Controller $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. + */ + public function check_kit_exists() + { + if ($this->input->post('item_number') === -1) + { + $exists = $this->Item_kit->item_kit_exists_for_name($this->input->post('name')); + } + else + { + $exists = false; + } + echo !$exists ? 'true' : 'false'; + } + private function _handle_image_upload() { /* Let files be uploaded with their original name */ @@ -491,7 +511,7 @@ class Items extends Secure_Controller { $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; $cur_item_info = $this->Item->get_info($item_id); - $location_id = $this->input->post('stock_location'); + $location_id = $this->input->post('stock_location'); $inv_data = array( 'trans_date' => date('Y-m-d H:i:s'), 'trans_items' => $item_id, @@ -604,52 +624,52 @@ class Items extends Secure_Controller $this->load->view('items/form_excel_import', NULL); } - public function do_excel_import() - { - if($_FILES['file_path']['error'] != UPLOAD_ERR_OK) - { - echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_failed'))); - } - else + public function do_excel_import() + { + if($_FILES['file_path']['error'] != UPLOAD_ERR_OK) { - if(($handle = fopen($_FILES['file_path']['tmp_name'], 'r')) !== FALSE) - { - // Skip the first row as it's the table description - fgetcsv($handle); - $i = 1; + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_failed'))); + } + else + { + if(($handle = fopen($_FILES['file_path']['tmp_name'], 'r')) !== FALSE) + { + // Skip the first row as it's the table description + fgetcsv($handle); + $i = 1; $failCodes = array(); - while(($data = fgetcsv($handle)) !== FALSE) - { + while(($data = fgetcsv($handle)) !== FALSE) + { // XSS file data sanity check $data = $this->xss_clean($data); /* haven't touched this so old templates will work, or so I guess... */ if(sizeof($data) >= 23) { - $item_data = array( - 'name' => $data[1], - 'description' => $data[11], - 'category' => $data[2], - 'cost_price' => $data[4], - 'unit_price' => $data[5], - 'reorder_level' => $data[10], - 'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : NULL, - 'allow_alt_description' => $data[12] != '' ? '1' : '0', - 'is_serialized' => $data[13] != '' ? '1' : '0', - 'custom1' => $data[14], - 'custom2' => $data[15], - 'custom3' => $data[16], - 'custom4' => $data[17], - 'custom5' => $data[18], - 'custom6' => $data[19], - 'custom7' => $data[20], - 'custom8' => $data[21], - 'custom9' => $data[22], - 'custom10' => $data[23] - ); - + $item_data = array( + 'name' => $data[1], + 'description' => $data[11], + 'category' => $data[2], + 'cost_price' => $data[4], + 'unit_price' => $data[5], + 'reorder_level' => $data[10], + 'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : NULL, + 'allow_alt_description' => $data[12] != '' ? '1' : '0', + 'is_serialized' => $data[13] != '' ? '1' : '0', + 'custom1' => $data[14], + 'custom2' => $data[15], + 'custom3' => $data[16], + 'custom4' => $data[17], + 'custom5' => $data[18], + 'custom6' => $data[19], + 'custom7' => $data[20], + 'custom8' => $data[21], + 'custom9' => $data[22], + 'custom10' => $data[23] + ); + /* we could do something like this, however, the effectiveness of this is rather limited, since for now, you have to upload files manually into that directory, so you really can do whatever you want, this probably @@ -660,90 +680,90 @@ class Items extends Secure_Controller $pic_file=''; }*/ $item_data['pic_filename']=$pic_file; - - $item_number = $data[0]; - $invalidated = FALSE; - if($item_number != '') - { - $item_data['item_number'] = $item_number; - $invalidated = $this->Item->item_number_exists($item_number); - } + + $item_number = $data[0]; + $invalidated = FALSE; + if($item_number != '') + { + $item_data['item_number'] = $item_number; + $invalidated = $this->Item->item_number_exists($item_number); + } } else { $invalidated = TRUE; } - if(!$invalidated && $this->Item->save($item_data)) - { - $items_taxes_data = NULL; - //tax 1 - if(is_numeric($data[7]) && $data[6] != '') - { - $items_taxes_data[] = array('name' => $data[6], 'percent' => $data[7] ); - } + if(!$invalidated && $this->Item->save($item_data)) + { + $items_taxes_data = NULL; + //tax 1 + if(is_numeric($data[7]) && $data[6] != '') + { + $items_taxes_data[] = array('name' => $data[6], 'percent' => $data[7] ); + } - //tax 2 - if(is_numeric($data[9]) && $data[8] != '') - { - $items_taxes_data[] = array('name' => $data[8], 'percent' => $data[9] ); - } + //tax 2 + if(is_numeric($data[9]) && $data[8] != '') + { + $items_taxes_data[] = array('name' => $data[8], 'percent' => $data[9] ); + } - // save tax values - if(count($items_taxes_data) > 0) - { - $this->Item_taxes->save($items_taxes_data, $item_data['item_id']); - } + // save tax values + if(count($items_taxes_data) > 0) + { + $this->Item_taxes->save($items_taxes_data, $item_data['item_id']); + } - // quantities & inventory Info - $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; - $emp_info = $this->Employee->get_info($employee_id); - $comment ='Qty CSV Imported'; + // quantities & inventory Info + $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; + $emp_info = $this->Employee->get_info($employee_id); + $comment ='Qty CSV Imported'; - $cols = count($data); + $cols = count($data); - // array to store information if location got a quantity - $allowed_locations = $this->Stock_location->get_allowed_locations(); - for ($col = 24; $col < $cols; $col = $col + 2) - { - $location_id = $data[$col]; - if(array_key_exists($location_id, $allowed_locations)) - { - $item_quantity_data = array( - 'item_id' => $item_data['item_id'], - 'location_id' => $location_id, - 'quantity' => $data[$col + 1], - ); - $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $location_id); + // array to store information if location got a quantity + $allowed_locations = $this->Stock_location->get_allowed_locations(); + for ($col = 24; $col < $cols; $col = $col + 2) + { + $location_id = $data[$col]; + if(array_key_exists($location_id, $allowed_locations)) + { + $item_quantity_data = array( + 'item_id' => $item_data['item_id'], + 'location_id' => $location_id, + 'quantity' => $data[$col + 1], + ); + $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $location_id); - $excel_data = array( - 'trans_items' => $item_data['item_id'], - 'trans_user' => $employee_id, - 'trans_comment' => $comment, - 'trans_location' => $data[$col], - 'trans_inventory' => $data[$col + 1] - ); + $excel_data = array( + 'trans_items' => $item_data['item_id'], + 'trans_user' => $employee_id, + 'trans_comment' => $comment, + 'trans_location' => $data[$col], + 'trans_inventory' => $data[$col + 1] + ); - $this->Inventory->insert($excel_data); - unset($allowed_locations[$location_id]); - } - } + $this->Inventory->insert($excel_data); + unset($allowed_locations[$location_id]); + } + } - /* - * now iterate through the array and check for which location_id no entry into item_quantities was made yet - * those get an entry with quantity as 0. - * unfortunately a bit duplicate code from above... - */ - foreach($allowed_locations as $location_id => $location_name) - { - $item_quantity_data = array( - 'item_id' => $item_data['item_id'], - 'location_id' => $location_id, - 'quantity' => 0, - ); - $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $data[$col]); + /* + * now iterate through the array and check for which location_id no entry into item_quantities was made yet + * those get an entry with quantity as 0. + * unfortunately a bit duplicate code from above... + */ + foreach($allowed_locations as $location_id => $location_name) + { + $item_quantity_data = array( + 'item_id' => $item_data['item_id'], + 'location_id' => $location_id, + 'quantity' => 0, + ); + $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $data[$col]); - $excel_data = array( + $excel_data = array( 'trans_items' => $item_data['item_id'], 'trans_user' => $employee_id, 'trans_comment' => $comment, @@ -751,16 +771,16 @@ class Items extends Secure_Controller 'trans_inventory' => 0 ); - $this->Inventory->insert($excel_data); - } - } - else //insert or update item failure - { - $failCodes[] = $i; - } + $this->Inventory->insert($excel_data); + } + } + else //insert or update item failure + { + $failCodes[] = $i; + } ++$i; - } + } if(count($failCodes) > 0) { @@ -775,9 +795,9 @@ class Items extends Secure_Controller } else { - echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_nodata_wrongformat'))); + echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_nodata_wrongformat'))); } - } + } } } ?> diff --git a/application/controllers/Reports.php b/application/controllers/Reports.php index 14199554e..38a006c66 100644 --- a/application/controllers/Reports.php +++ b/application/controllers/Reports.php @@ -369,21 +369,21 @@ class Reports extends Secure_Controller $stock_locations = $data = $this->xss_clean($this->Stock_location->get_allowed_locations('sales')); $stock_locations['all'] = $this->lang->line('reports_all'); $data['stock_locations'] = array_reverse($stock_locations, TRUE); - $data['mode'] = 'sale'; + $data['mode'] = 'sale'; $this->load->view('reports/date_input', $data); } - public function date_input_recv() - { - $data = array(); + public function date_input_recv() + { + $data = array(); $stock_locations = $data = $this->xss_clean($this->Stock_location->get_allowed_locations('receivings')); $stock_locations['all'] = $this->lang->line('reports_all'); $data['stock_locations'] = array_reverse($stock_locations, TRUE); - $data['mode'] = 'receiving'; + $data['mode'] = 'receiving'; - $this->load->view('reports/date_input', $data); - } + $this->load->view('reports/date_input', $data); + } //Graphical summary sales report public function graphical_summary_sales($start_date, $end_date, $sale_type, $location_id = 'all') @@ -893,7 +893,7 @@ class Reports extends Secure_Controller $this->load->view('reports/tabular_details', $data); } - public function get_detailed_sales_row($sale_id) + public function get_detailed_sales_row($sale_id) { $inputs = array('sale_id' => $sale_id); @@ -931,10 +931,11 @@ class Reports extends Secure_Controller $this->load->model('reports/Detailed_sales'); $model = $this->Detailed_sales; - + $model->create($inputs); $headers = $this->xss_clean($model->getDataColumns()); + $report_data = $model->getData($inputs); $summary_data = array(); @@ -1041,6 +1042,7 @@ class Reports extends Secure_Controller 'employee_name' => $row['employee_name'], 'supplier_name' => $row['supplier_name'], 'total' => to_currency($row['total']), + 'profit' => to_currency($row['profit']), 'payment_type' => $row['payment_type'], 'reference' => $row['reference'], 'comment' => $row['comment'], diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index 8c0650524..f221bc802 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -176,7 +176,7 @@ class Sales extends Secure_Controller public function set_email_receipt() { - $this->sale_lib->set_email_receipt($this->input->post('email_receipt')); + $this->sale_lib->set_email_receipt($this->input->post('email_receipt')); } // Multiple Payments @@ -248,7 +248,7 @@ class Sales extends Secure_Controller public function add() { $data = array(); - + $discount = 0; // check if any discount is assigned to the selected customer @@ -280,10 +280,42 @@ class Sales extends Secure_Controller } elseif($this->Item_kit->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt)) { - if(!$this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location, $discount)) + + // Add kit item to order if one is assigned + $pieces = explode(' ', $item_id_or_number_or_item_kit_or_receipt); + $item_kit_id = $pieces[1]; + $item_kit_info = $this->Item_kit->get_info($item_kit_id); + $kit_item_id = $item_kit_info->kit_item_id; + $price_option = $item_kit_info->price_option; + $stock_type = $item_kit_info->stock_type; + $kit_print_option = $item_kit_info->print_option; // 0-all, 1-priced, 2-kit-only + + if ($kit_item_id !== '' && $kit_item_id != 0) + { + if ($item_kit_info->kit_discount_percent != 0 && $item_kit_info->kit_discount_percent > $discount) + { + $discount = $item_kit_info->kit_discount_percent; + } + + $price = null; + $print_option = 0; // Always include in list of items on invoice + + if(!$this->sale_lib->add_item($kit_item_id, $quantity, $item_location, $discount, $price, null, null, null, $print_option)) + { + $data['error'] = $this->lang->line('sales_unable_to_add_item'); + } + else + { + $data['warning'] = $this->sale_lib->out_of_stock($item_id_or_number_or_item_kit_or_receipt, $item_location); + } + } + + // Add item kit items to order + if(!$this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt, $item_location, $discount, $price_option, $kit_print_option)) { $data['error'] = $this->lang->line('sales_unable_to_add_item'); } + } else { @@ -388,7 +420,8 @@ class Sales extends Secure_Controller $data['invoice_number'] = $invoice_number; $data['sale_id_num'] = $this->Sale->save($data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $data['payments']); $data['sale_id'] = 'POS ' . $data['sale_id_num']; - + + $data = $this->xss_clean($data); if($data['sale_id_num'] == -1) @@ -403,7 +436,10 @@ class Sales extends Secure_Controller $data['cur_giftcard_value'] = $this->sale_lib->get_giftcard_remainder(); $data['print_after_sale'] = $this->sale_lib->is_print_after_sale(); $data['email_receipt'] = $this->sale_lib->get_email_receipt(); - + + // Reload (sorted) and filter the cart line items for printing purposes + $data['cart'] = $this->get_filtered($this->sale_lib->get_cart_reordered($data['sale_id_num'])); + if($this->sale_lib->is_invoice_number_enabled()) { $this->load->view('sales/invoice', $data); @@ -845,5 +881,23 @@ class Sales extends Secure_Controller echo !$exists ? 'true' : 'false'; } + + public function get_filtered($cart) + { + $filteredCart = array(); + foreach($cart as $id => $item) + { + if ($item['print_option'] == '0') // always include + { + $filteredCart[$id] = $item; + } + elseif ($item['print_option'] == '1' && $item['price'] != 0) // include only if the price is not zero + { + $filteredCart[$id] = $item; + } + // print_option 2 is never included + }; + return $filteredCart; + } } ?> diff --git a/application/language/en/config_lang.php b/application/language/en/config_lang.php index 3a43cdeff..d25c4e438 100644 --- a/application/language/en/config_lang.php +++ b/application/language/en/config_lang.php @@ -104,6 +104,7 @@ $lang["config_language"] = "Language"; $lang["config_left"] = "Left"; $lang["config_license"] = "License"; $lang["config_license_configuration"] = "License Statement"; +$lang["config_line_sequence"] = "Line Sequence"; $lang["config_lines_per_page"] = "Lines Per Page"; $lang["config_lines_per_page_number"] = ""; $lang["config_lines_per_page_required"] = "The lines per page is a required field"; diff --git a/application/language/en/item_kits_lang.php b/application/language/en/item_kits_lang.php index 353c0b7c2..122ff38ce 100644 --- a/application/language/en/item_kits_lang.php +++ b/application/language/en/item_kits_lang.php @@ -1,21 +1,31 @@ CI =& get_instance(); } + public function get_line_sequence_options() + { + return array( + '0' => $this->CI->lang->line('sales_entry'), + '1' => $this->CI->lang->line('sales_group_by_type'), + '2' => $this->CI->lang->line('sales_group_by_category') + ); + } + public function get_cart() { if(!$this->CI->session->userdata('sales_cart')) @@ -34,7 +43,7 @@ class Sale_lib // avoid returning a NULL that results in a 0 in the comment if nothing is set/available $comment = $this->CI->session->userdata('sales_comment'); - return empty($comment) ? '' : $comment; + return empty($comment) ? '' : $comment; } public function set_comment($comment) @@ -177,7 +186,7 @@ class Sale_lib $subtotal = 0; foreach($this->get_payments() as $payments) { - $subtotal = bcadd($payments['payment_amount'], $subtotal); + $subtotal = bcadd($payments['payment_amount'], $subtotal); } return $subtotal; @@ -192,7 +201,7 @@ class Sale_lib $precision = $this->CI->config->item('currency_decimals'); $rounded_due = bccomp(round($amount_due, $precision, PHP_ROUND_HALF_EVEN), 0, $precision); // take care of rounding error introduced by round tripping payment amount to the browser - return $rounded_due == 0 ? 0 : $amount_due; + return $rounded_due == 0 ? 0 : $amount_due; } public function get_customer() @@ -255,52 +264,52 @@ class Sale_lib $this->CI->session->unset_userdata('sales_mode'); } - public function get_sale_location() - { - if(!$this->CI->session->userdata('sales_location')) - { - $this->set_sale_location($this->CI->Stock_location->get_default_location_id()); - } - - return $this->CI->session->userdata('sales_location'); - } - - public function set_sale_location($location) - { - $this->CI->session->set_userdata('sales_location', $location); - } - - public function clear_sale_location() - { - $this->CI->session->unset_userdata('sales_location'); - } - - public function set_giftcard_remainder($value) - { - $this->CI->session->set_userdata('sales_giftcard_remainder', $value); - } - - public function get_giftcard_remainder() - { - return $this->CI->session->userdata('sales_giftcard_remainder'); - } - - public function clear_giftcard_remainder() - { - $this->CI->session->unset_userdata('sales_giftcard_remainder'); - } - - public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $include_deleted = FALSE) + public function get_sale_location() { + if(!$this->CI->session->userdata('sales_location')) + { + $this->set_sale_location($this->CI->Stock_location->get_default_location_id()); + } + + return $this->CI->session->userdata('sales_location'); + } + + public function set_sale_location($location) + { + $this->CI->session->set_userdata('sales_location', $location); + } + + public function clear_sale_location() + { + $this->CI->session->unset_userdata('sales_location'); + } + + public function set_giftcard_remainder($value) + { + $this->CI->session->set_userdata('sales_giftcard_remainder', $value); + } + + public function get_giftcard_remainder() + { + return $this->CI->session->userdata('sales_giftcard_remainder'); + } + + public function clear_giftcard_remainder() + { + $this->CI->session->unset_userdata('sales_giftcard_remainder'); + } + + public function add_item(&$item_id, $quantity = 1, $item_location, $discount = 0, $price = NULL, $description = NULL, $serialnumber = NULL, $include_deleted = FALSE, $print_option = '0') + { + $item_info = $this->CI->Item->get_info_by_id_or_number($item_id); //make sure item exists - if(empty($item_info)) - { + if (empty($item_info)) { $item_id = -1; - return FALSE; + return FALSE; } - + $item_id = $item_info->item_id; // Serialization and Description @@ -308,74 +317,83 @@ class Sale_lib //Get all items in the cart so far... $items = $this->get_cart(); - //We need to loop through all items in the cart. - //If the item is already there, get it's key($updatekey). - //We also need to get the next key that we are going to use in case we need to add the - //item to the cart. Since items can be deleted, we can't use a count. we use the highest key + 1. + //We need to loop through all items in the cart. + //If the item is already there, get it's key($updatekey). + //We also need to get the next key that we are going to use in case we need to add the + //item to the cart. Since items can be deleted, we can't use a count. we use the highest key + 1. - $maxkey = 0; //Highest key so far - $itemalreadyinsale = FALSE; //We did not find the item yet. + $maxkey = 0; //Highest key so far + $itemalreadyinsale = FALSE; //We did not find the item yet. $insertkey = 0; //Key to use for new entry. $updatekey = 0; //Key to use to update(quantity) foreach($items as $item) { - //We primed the loop so maxkey is 0 the first time. - //Also, we have stored the key in the element itself so we can compare. + //We primed the loop so maxkey is 0 the first time. + //Also, we have stored the key in the element itself so we can compare. - if($maxkey <= $item['line']) - { + if ($maxkey <= $item['line']) { $maxkey = $item['line']; } - if($item['item_id'] == $item_id && $item['item_location'] == $item_location) - { + if ($item['item_id'] == $item_id && $item['item_location'] == $item_location) { $itemalreadyinsale = TRUE; $updatekey = $item['line']; - if(!$item_info->is_serialized) - { - $quantity = bcadd($quantity, $items[$updatekey]['quantity']); - } + if(!$item_info->is_serialized) + { + $quantity = bcadd($quantity, $items[$updatekey]['quantity']); + } } } - $insertkey = $maxkey+1; + $insertkey = $maxkey + 1; //array/cart records are identified by $insertkey and item_id is just another field. - $price = $price != NULL ? $price : $item_info->unit_price; + + if (is_null($price)) + { + $price = $item_info->unit_price; + } + elseif ($price == 0) + { + $price = 0.00; + $discount = 0.00; + } + $total = $this->get_item_total($quantity, $price, $discount); - $discounted_total = $this->get_item_total($quantity, $price, $discount, TRUE); + $discounted_total = $this->get_item_total($quantity, $price, $discount, TRUE); //Item already exists and is not serialized, add to quantity if(!$itemalreadyinsale || $item_info->is_serialized) { - $item = array($insertkey => array( - 'item_id' => $item_id, - 'item_location' => $item_location, - 'stock_name' => $this->CI->Stock_location->get_location_name($item_location), - 'line' => $insertkey, - 'name' => $item_info->name, - 'item_number' => $item_info->item_number, - 'description' => $description != NULL ? $description : $item_info->description, - 'serialnumber' => $serialnumber != NULL ? $serialnumber : '', - 'allow_alt_description' => $item_info->allow_alt_description, - 'is_serialized' => $item_info->is_serialized, - 'quantity' => $quantity, - 'discount' => $discount, - 'in_stock' => $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity, - 'price' => $price, - 'total' => $total, - 'discounted_total' => $discounted_total, - ) - ); + $item = array($insertkey => array( + 'item_id' => $item_id, + 'item_location' => $item_location, + 'stock_name' => $this->CI->Stock_location->get_location_name($item_location), + 'line' => $insertkey, + 'name' => $item_info->name, + 'item_number' => $item_info->item_number, + 'description' => $description != NULL ? $description : $item_info->description, + 'serialnumber' => $serialnumber != NULL ? $serialnumber : '', + 'allow_alt_description' => $item_info->allow_alt_description, + 'is_serialized' => $item_info->is_serialized, + 'quantity' => $quantity, + 'discount' => $discount, + 'in_stock' => $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity, + 'price' => $price, + 'total' => $total, + 'discounted_total' => $discounted_total, + 'print_option' => $print_option + ) + ); //add to existing array $items += $item; } - else - { - $line = &$items[$updatekey]; - $line['quantity'] = $quantity; - $line['total'] = $total; - $line['discounted_total'] = $discounted_total; - } + else + { + $line = &$items[$updatekey]; + $line['quantity'] = $quantity; + $line['total'] = $total; + $line['discounted_total'] = $discounted_total; + } $this->set_cart($items); @@ -387,16 +405,20 @@ class Sale_lib //make sure item exists if($item_id != -1) { - $item_quantity = $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity; - $quantity_added = $this->get_quantity_already_added($item_id, $item_location); + $item_info = $this->CI->Item->get_info_by_id_or_number($item_id); - if($item_quantity - $quantity_added < 0) - { - return $this->CI->lang->line('sales_quantity_less_than_zero'); - } - elseif($item_quantity - $quantity_added < $this->CI->Item->get_info_by_id_or_number($item_id)->reorder_level) - { - return $this->CI->lang->line('sales_quantity_less_than_reorder_level'); + if ($item_info->stock_type == '0') { + $item_quantity = $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity; + $quantity_added = $this->get_quantity_already_added($item_id, $item_location); + + if($item_quantity - $quantity_added < 0) + { + return $this->CI->lang->line('sales_quantity_less_than_zero'); + } + elseif($item_quantity - $quantity_added < $item_info->reorder_level) + { + return $this->CI->lang->line('sales_quantity_less_than_reorder_level'); + } } } @@ -468,24 +490,58 @@ class Sale_lib $this->empty_cart(); $this->remove_customer(); - foreach($this->CI->Sale->get_sale_items($sale_id)->result() as $row) + foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, TRUE); + $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); } $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); } - public function add_item_kit($external_item_kit_id, $item_location, $discount) + public function add_item_kit($external_item_kit_id, $item_location, $discount, $price_option, $kit_print_option) { + //KIT # $pieces = explode(' ', $external_item_kit_id); $item_kit_id = $pieces[1]; $result = TRUE; - + foreach($this->CI->Item_kit_items->get_info($item_kit_id) as $item_kit_item) { - $result &= $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount); + if ($price_option == '0') // all + { + $price = null; + } + elseif ($price_option == '1') // item kit only + { + $price = 0; + } + elseif ($price_option == '2') // item kit plus stock items (assuming materials) + { + if ($item_kit_item['stock_type'] == 0) // stock item + { + $price = null; + } + else + { + $price = 0; + } + } + + if ($kit_print_option == '0') // all + { + $print_option = '0'; // print always + } + elseif ($kit_print_option == '1') // priced + { + $print_option = '1'; // print if price not zero + } + elseif ($kit_print_option == '2') // kit only if price is not zero + { + $print_option = '2'; // Do not include in list + } + + $result &= $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, $price, null, null, null, $print_option); } return $result; @@ -496,9 +552,9 @@ class Sale_lib $this->empty_cart(); $this->remove_customer(); - foreach($this->CI->Sale->get_sale_items($sale_id)->result() as $row) + foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, TRUE); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber, TRUE, $row->print_option); } foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row) @@ -509,6 +565,18 @@ class Sale_lib $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); $this->set_employee($this->CI->Sale->get_employee($sale_id)->person_id); } + + public function get_cart_reordered($sale_id) + { + $this->empty_cart(); + foreach($this->CI->Sale->get_sale_items_ordered($sale_id)->result() as $row) + { + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, + $row->description, $row->serialnumber, TRUE, $row->print_option); + } + + return $this->CI->session->userdata('sales_cart'); + } public function copy_entire_suspended_sale($sale_id) { @@ -517,12 +585,15 @@ class Sale_lib foreach($this->CI->Sale_suspended->get_sale_items($sale_id)->result() as $row) { - $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, $row->description, $row->serialnumber); + $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount_percent, $row->item_unit_price, + $row->description, $row->serialnumber, TRUE, $row->print_option); } + foreach($this->CI->Sale_suspended->get_sale_payments($sale_id)->result() as $row) { $this->add_payment($row->payment_type, $row->payment_amount); } + $suspended_sale_info = $this->CI->Sale_suspended->get_info($sale_id)->row(); $this->set_customer($suspended_sale_info->person_id); $this->set_comment($suspended_sale_info->comment); @@ -704,7 +775,6 @@ class Sale_lib return $total; } - } ?> diff --git a/application/models/Item.php b/application/models/Item.php index 5faaf6c65..7e96f104e 100644 --- a/application/models/Item.php +++ b/application/models/Item.php @@ -60,13 +60,59 @@ class Item extends CI_Model */ public function search($search, $filters, $rows = 0, $limit_from = 0, $sort = 'items.name', $order = 'asc') { - $this->db->from('items'); - $this->db->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left'); - $this->db->join('inventory', 'inventory.trans_items = items.item_id'); + $this->db->select('MAX(items.name) as name'); + $this->db->select('MAX(items.category) as category'); + $this->db->select('MAX(items.supplier_id) as supplier_id'); + $this->db->select('MAX(items.item_number) as item_number'); + $this->db->select('MAX(items.description) as description'); + $this->db->select('MAX(items.cost_price) as cost_price'); + $this->db->select('MAX(items.unit_price) as unit_price'); + $this->db->select('MAX(items.reorder_level) as reorder_level'); + $this->db->select('MAX(items.receiving_quantity) as receiving_quantity'); + $this->db->select('items.item_id as item_id'); + $this->db->select('MAX(items.pic_id) as pic_id'); + $this->db->select('MAX(items.allow_alt_description) as allow_alt_description'); + $this->db->select('MAX(items.is_serialized) as is_serialized'); + $this->db->select('MAX(items.deleted) as deleted'); + $this->db->select('MAX(items.custom1) as custom1'); + $this->db->select('MAX(items.custom2) as custom2'); + $this->db->select('MAX(items.custom3) as custom3'); + $this->db->select('MAX(items.custom4) as custom4'); + $this->db->select('MAX(items.custom5) as custom5'); + $this->db->select('MAX(items.custom6) as custom6'); + $this->db->select('MAX(items.custom7) as custom7'); + $this->db->select('MAX(items.custom8) as custom8'); + $this->db->select('MAX(items.custom9) as custom9'); + $this->db->select('MAX(items.custom10) as custom10'); + + $this->db->select('MAX(suppliers.person_id) as person_id'); + $this->db->select('MAX(suppliers.company_name) as company_name'); + $this->db->select('MAX(suppliers.agency_name) as agency_name'); + $this->db->select('MAX(suppliers.account_number) as account_number'); + $this->db->select('MAX(suppliers.deleted) as deleted'); + + $this->db->select('MAX(inventory.trans_id) as trans_id'); + $this->db->select('MAX(inventory.trans_items) as trans_items'); + $this->db->select('MAX(inventory.trans_user) as trans_user'); + $this->db->select('MAX(inventory.trans_date) as trans_date'); + $this->db->select('MAX(inventory.trans_comment) as trans_comment'); + $this->db->select('MAX(inventory.trans_location) as trans_location'); + $this->db->select('MAX(inventory.trans_inventory) as trans_inventory'); if($filters['stock_location_id'] > -1) { - $this->db->join('item_quantities', 'item_quantities.item_id = items.item_id'); + $this->db->select('MAX(item_quantities.item_id) as qty_item_id'); + $this->db->select('MAX(item_quantities.location_id) as location_id'); + $this->db->select('MAX(item_quantities.quantity) as quantity'); + } + + $this->db->from('items as items'); + $this->db->join('suppliers as suppliers', 'suppliers.person_id = items.supplier_id', 'left'); + $this->db->join('inventory as inventory', 'inventory.trans_items = items.item_id'); + + if($filters['stock_location_id'] > -1) + { + $this->db->join('item_quantities as item_quantities', 'item_quantities.item_id = items.item_id'); $this->db->where('location_id', $filters['stock_location_id']); } @@ -129,18 +175,18 @@ class Item extends CI_Model // avoid duplicated entries with same name because of inventory reporting multiple changes on the same item in the same date range $this->db->group_by('items.item_id'); - + // order by name of item $this->db->order_by($sort, $order); - if($rows > 0) - { + if($rows > 0) + { $this->db->limit($rows, $limit_from); } return $this->db->get(); } - + /* Returns all the items */ @@ -199,7 +245,7 @@ class Item extends CI_Model return $item_obj; } } - + /* Gets information about a particular item by item id or number */ @@ -207,17 +253,17 @@ class Item extends CI_Model { $this->db->from('items'); - if (ctype_digit($item_id)) - { - $this->db->group_start(); - $this->db->where('item_id', (int) $item_id); - $this->db->or_where('items.item_number', $item_id); - $this->db->group_end(); - } - else - { - $this->db->where('item_number', $item_id); - } + if (ctype_digit($item_id)) + { + $this->db->group_start(); + $this->db->where('item_id', (int) $item_id); + $this->db->or_where('items.item_number', $item_id); + $this->db->group_end(); + } + else + { + $this->db->where('item_number', $item_id); + } $this->db->where('items.deleted', 0); @@ -243,7 +289,7 @@ class Item extends CI_Model { $this->db->where('items.deleted', $deleted); } - + $query = $this->db->get(); if($query->num_rows() == 1) @@ -284,7 +330,7 @@ class Item extends CI_Model return FALSE; } - + $this->db->where('item_id', $item_id); return $this->db->update('items', $item_data); @@ -312,14 +358,14 @@ class Item extends CI_Model $this->Item_quantity->reset_quantity($item_id); $this->db->where('item_id', $item_id); $success = $this->db->update('items', array('deleted'=>1)); - + $this->db->trans_complete(); - + $success &= $this->db->trans_status(); return $success; } - + /* Undeletes one item */ @@ -342,13 +388,13 @@ class Item extends CI_Model $this->Item_quantity->reset_quantity_list($item_ids); $this->db->where_in('item_id', $item_ids); $success = $this->db->update('items', array('deleted'=>1)); - + $this->db->trans_complete(); - + $success &= $this->db->trans_status(); return $success; - } + } public function get_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25) { @@ -357,6 +403,7 @@ class Item extends CI_Model $this->db->select('item_id, name'); $this->db->from('items'); $this->db->where('deleted', $filters['is_deleted']); + $this->db->where("item_type = '0'"); // standard, exclude kit items since kits will be picked up later $this->db->like('name', $search); $this->db->order_by('name', 'asc'); foreach($this->db->get()->result() as $row) @@ -465,7 +512,7 @@ class Item extends CI_Model return $suggestions; } - + public function get_location_suggestions($search) { $suggestions = array(); @@ -479,7 +526,7 @@ class Item extends CI_Model { $suggestions[] = array('label' => $row->location); } - + return $suggestions; } @@ -497,7 +544,7 @@ class Item extends CI_Model $row_array = (array) $row; $suggestions[] = array('label' => $row_array['custom'.$field_no]); } - + return $suggestions; } @@ -547,4 +594,4 @@ class Item extends CI_Model return $this->save($data, $item_id); } } -?> \ No newline at end of file +?> diff --git a/application/models/Item_kit.php b/application/models/Item_kit.php index 91a673781..ba07e7dd4 100644 --- a/application/models/Item_kit.php +++ b/application/models/Item_kit.php @@ -46,7 +46,41 @@ class Item_kit extends CI_Model */ public function get_info($item_kit_id) { - $this->db->from('item_kits'); + $this->db->select(' + item_kit_id, + item_kits.name as name, + items.name as item_name, + item_kits.description, + items.description as item_description, + item_kits.item_id as kit_item_id, + kit_discount_percent, + price_option, + print_option, + category, + supplier_id, + item_number, + cost_price, + unit_price, + reorder_level, + receiving_quantity, + pic_id, + allow_alt_description, + is_serialized, + deleted, + custom1, + custom2, + custom3, + custom4, + custom5, + custom6, + custom7, + custom8, + custom9, + custom10, + item_type'); + + $this->db->from('item_kits'); + $this->db->join('items', 'item_kits.item_id = items.item_id', 'left'); $this->db->where('item_kit_id', $item_kit_id); $query = $this->db->get(); @@ -120,7 +154,7 @@ class Item_kit extends CI_Model $this->db->where_in('item_kit_id', $item_kit_ids); return $this->db->delete('item_kits'); - } + } public function get_search_suggestions($search, $limit = 25) { diff --git a/application/models/Item_kit_items.php b/application/models/Item_kit_items.php index ab4e0b3fa..293b78b22 100644 --- a/application/models/Item_kit_items.php +++ b/application/models/Item_kit_items.php @@ -6,31 +6,49 @@ class Item_kit_items extends CI_Model */ public function get_info($item_kit_id) { - $this->db->from('item_kit_items'); + $this->db->select('item_kit_id, item_kit_items.item_id, quantity, kit_sequence, unit_price, item_type, stock_type'); + $this->db->from('item_kit_items as item_kit_items'); + $this->db->join('items as items', 'item_kit_items.item_id = items.item_id'); $this->db->where('item_kit_id', $item_kit_id); - + $this->db->order_by('kit_sequence', 'asc'); + + //return an array of item kit items for an item + return $this->db->get()->result_array(); + } + + /* + Gets item kit items for a particular item kit + */ + public function get_info_for_sale($item_kit_id) + { + $this->db->from('item_kit_items'); + $this->db->where('item_kit_id', $item_kit_id); + + $this->db->order_by('kit_sequence', 'desc'); + //return an array of item kit items for an item return $this->db->get()->result_array(); } - /* Inserts or updates an item kit's items */ public function save(&$item_kit_items_data, $item_kit_id) { $success = TRUE; - + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); $this->delete($item_kit_id); - - foreach($item_kit_items_data as $row) - { - $row['item_kit_id'] = $item_kit_id; - $success &= $this->db->insert('item_kit_items', $row); + + if ($item_kit_items_data != NULL) { + foreach ($item_kit_items_data as $row) { + $row['item_kit_id'] = $item_kit_id; + $success &= $this->db->insert('item_kit_items', $row); + } } - + $this->db->trans_complete(); $success &= $this->db->trans_status(); diff --git a/application/models/Receiving.php b/application/models/Receiving.php index 417fb721f..20ba13aa4 100644 --- a/application/models/Receiving.php +++ b/application/models/Receiving.php @@ -2,7 +2,7 @@ class Receiving extends CI_Model { public function get_info($receiving_id) - { + { $this->db->from('receivings'); $this->db->join('people', 'people.person_id = receivings.supplier_id', 'LEFT'); $this->db->join('suppliers', 'suppliers.person_id = receivings.supplier_id', 'LEFT'); @@ -30,7 +30,7 @@ class Receiving extends CI_Model { return $this->exists($pieces[1]); } - else + else { return $this->get_receiving_by_reference($receipt_receiving_id)->num_rows() > 0; } @@ -46,7 +46,7 @@ class Receiving extends CI_Model return ($this->db->get()->num_rows() == 1); } - + public function update($receiving_data, $receiving_id) { $this->db->where('receiving_id', $receiving_id); @@ -106,8 +106,8 @@ class Receiving extends CI_Model //Update stock quantity $item_quantity = $this->Item_quantity->get_item_quantity($item['item_id'], $item['item_location']); - $this->Item_quantity->save(array('quantity' => $item_quantity->quantity + $items_received, 'item_id' => $item['item_id'], - 'location_id' => $item['item_location']), $item['item_id'], $item['item_location']); + $this->Item_quantity->save(array('quantity' => $item_quantity->quantity + $items_received, 'item_id' => $item['item_id'], + 'location_id' => $item['item_location']), $item['item_id'], $item['item_location']); $recv_remarks = 'RECV ' . $receiving_id; $inv_data = array( @@ -125,7 +125,7 @@ class Receiving extends CI_Model } $this->db->trans_complete(); - + if($this->db->trans_status() === FALSE) { return -1; @@ -133,7 +133,7 @@ class Receiving extends CI_Model return $receiving_id; } - + public function delete_list($receiving_ids, $employee_id, $update_inventory = TRUE) { $success = TRUE; @@ -153,7 +153,7 @@ class Receiving extends CI_Model return $success; } - + public function delete($receiving_id, $employee_id, $update_inventory = TRUE) { // start a transaction to assure data integrity @@ -240,33 +240,33 @@ class Receiving extends CI_Model { $where = 'WHERE receivings_items.receiving_id = ' . $this->db->escape($inputs['receiving_id']); } - - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('receivings_items_temp') . + + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('receivings_items_temp') . ' (INDEX(receiving_date), INDEX(receiving_time), INDEX(receiving_id)) ( SELECT - DATE(receiving_time) AS receiving_date, - receiving_time, + MAX(DATE(receiving_time)) AS receiving_date, + MAX(receiving_time) AS receiving_time, receivings_items.receiving_id, - comment, - item_location, - reference, - payment_type, - employee_id, + MAX(comment) AS comment, + MAX(item_location) AS item_location, + MAX(reference) AS reference, + MAX(payment_type) AS payment_type, + MAX(employee_id) AS employee_id, items.item_id, - receivings.supplier_id, - quantity_purchased, - receivings_items.receiving_quantity, - item_cost_price, - item_unit_price, - discount_percent, + MAX(receivings.supplier_id) AS supplier_id, + MAX(quantity_purchased) AS quantity_purchased, + MAX(receivings_items.receiving_quantity) AS receiving_quantity, + MAX(item_cost_price) AS item_cost_price, + MAX(item_unit_price) AS item_unit_price, + MAX(discount_percent) AS discount_percent, receivings_items.line, - serialnumber, - receivings_items.description, - (item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) AS subtotal, - (item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) AS total, - (item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) - (item_cost_price * quantity_purchased) AS profit, - (item_cost_price * quantity_purchased) AS cost + MAX(serialnumber) AS serialnumber, + MAX(receivings_items.description) AS description, + MAX(item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) AS subtotal, + MAX(item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) AS total, + MAX((item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent / 100) - (item_cost_price * quantity_purchased)) AS profit, + MAX(item_cost_price * quantity_purchased) AS cost FROM ' . $this->db->dbprefix('receivings_items') . ' AS receivings_items INNER JOIN ' . $this->db->dbprefix('receivings') . ' AS receivings ON receivings_items.receiving_id = receivings.receiving_id diff --git a/application/models/Sale.php b/application/models/Sale.php index de27c1854..d4150521d 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -5,7 +5,7 @@ class Sale extends CI_Model { // NOTE: temporary tables are created to speed up searches due to the fact that are ortogonal to the main query // create a temporary table to contain all the payments per sale item - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . '( SELECT payments.sale_id AS sale_id, IFNULL(SUM(payments.payment_amount), 0) AS sale_payment_amount, @@ -19,7 +19,7 @@ class Sale extends CI_Model ); // create a temporary table to contain all the sum of taxes per sale item - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') . '( SELECT sales_items_taxes.sale_id AS sale_id, sales_items_taxes.item_id AS item_id, @@ -51,23 +51,23 @@ class Sale extends CI_Model $this->db->select(' sales.sale_id AS sale_id, - DATE(sales.sale_time) AS sale_date, - sales.sale_time AS sale_time, - sales.comment AS comment, - sales.invoice_number AS invoice_number, - sales.employee_id AS employee_id, - sales.customer_id AS customer_id, - CONCAT(customer_p.first_name, " ", customer_p.last_name) AS customer_name, - customer_p.first_name AS first_name, - customer_p.last_name AS last_name, - customer_p.email AS email, - customer_p.comments AS comments, + MAX(DATE(sales.sale_time)) AS sale_date, + MAX(sales.sale_time) AS sale_time, + MAX(sales.comment) AS comment, + MAX(sales.invoice_number) AS invoice_number, + MAX(sales.employee_id) AS employee_id, + MAX(sales.customer_id) AS customer_id, + MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name, + MAX(customer_p.first_name) AS first_name, + MAX(customer_p.last_name) AS last_name, + MAX(customer_p.email) AS email, + MAX(customer_p.comments) AS comments, ' . " IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals)) AS amount_due, - payments.sale_payment_amount AS amount_tendered, - (payments.sale_payment_amount - IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals))) AS change_due, + MAX(payments.sale_payment_amount) AS amount_tendered, + (MAX(payments.sale_payment_amount) - IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals))) AS change_due, " . ' - payments.payment_type AS payment_type + MAX(payments.payment_type) AS payment_type '); $this->db->from('sales_items AS sales_items'); @@ -109,7 +109,7 @@ class Sale extends CI_Model } // NOTE: temporary tables are created to speed up searches due to the fact that are ortogonal to the main query // create a temporary table to contain all the payments per sale item - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . ' (PRIMARY KEY(sale_id), INDEX(sale_id)) ( SELECT payments.sale_id AS sale_id, @@ -124,7 +124,7 @@ class Sale extends CI_Model ); // create a temporary table to contain all the sum of taxes per sale item - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') . ' (INDEX(sale_id), INDEX(item_id)) ( SELECT sales_items_taxes.sale_id AS sale_id, @@ -159,12 +159,12 @@ class Sale extends CI_Model $this->db->select(' sales.sale_id AS sale_id, - DATE(sales.sale_time) AS sale_date, - sales.sale_time AS sale_time, - sales.invoice_number AS invoice_number, + MAX(DATE(sales.sale_time)) AS sale_date, + MAX(sales.sale_time) AS sale_time, + MAX(sales.invoice_number) AS invoice_number, SUM(sales_items.quantity_purchased) AS items_purchased, - CONCAT(customer_p.first_name, " ", customer_p.last_name) AS customer_name, - customer.company_name AS company_name, + MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name, + MAX(customer.company_name) AS company_name, ' . " ROUND($sale_subtotal, $decimals) AS subtotal, IFNULL(ROUND($sale_tax, $decimals), 0) AS tax, @@ -172,10 +172,10 @@ class Sale extends CI_Model ROUND($sale_cost, $decimals) AS cost, ROUND($sale_total - IFNULL($sale_tax, 0) - $sale_cost, $decimals) AS profit, IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals)) AS amount_due, - payments.sale_payment_amount AS amount_tendered, - (payments.sale_payment_amount - IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals))) AS change_due, + MAX(payments.sale_payment_amount) AS amount_tendered, + (MAX(payments.sale_payment_amount) - IFNULL(ROUND($sale_total, $decimals), ROUND($sale_subtotal, $decimals))) AS change_due, " . ' - payments.payment_type AS payment_type + MAX(payments.payment_type) AS payment_type '); $this->db->from('sales_items AS sales_items'); @@ -202,7 +202,7 @@ class Sale extends CI_Model $this->db->where('sales.sale_id', $pieces[1]); } else - { + { $this->db->group_start(); // customer last name $this->db->like('customer_p.last_name', $search); @@ -222,13 +222,13 @@ class Sale extends CI_Model } if($filters['sale_type'] == 'sales') - { - $this->db->where('sales_items.quantity_purchased > 0'); - } - elseif($filters['sale_type'] == 'returns') - { - $this->db->where('sales_items.quantity_purchased < 0'); - } + { + $this->db->where('sales_items.quantity_purchased > 0'); + } + elseif($filters['sale_type'] == 'returns') + { + $this->db->where('sales_items.quantity_purchased < 0'); + } if($filters['only_invoices'] != FALSE) { @@ -310,7 +310,7 @@ class Sale extends CI_Model { $this->db->where('invoice_number IS NOT NULL'); } - + if($filters['only_cash'] != FALSE) { $this->db->like('payment_type', $this->lang->line('sales_cash'), 'after'); @@ -401,7 +401,7 @@ class Sale extends CI_Model return $this->db->get(); } - public function get_invoice_number_for_year($year = '', $start_from = 0) + public function get_invoice_number_for_year($year = '', $start_from = 0) { $year = $year == '' ? date('Y') : $year; $this->db->select('COUNT( 1 ) AS invoice_number_year'); @@ -412,7 +412,7 @@ class Sale extends CI_Model return ($start_from + $result['invoice_number_year']); } - + public function is_valid_receipt(&$receipt_sale_id) { if(!empty($receipt_sale_id)) @@ -457,7 +457,7 @@ class Sale extends CI_Model { //Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - + // first delete all payments $this->db->delete('sales_payments', array('sale_id' => $sale_id)); @@ -472,12 +472,12 @@ class Sale extends CI_Model $success = $this->db->insert('sales_payments', $sales_payments_data); } - + $this->db->trans_complete(); - + $success &= $this->db->trans_status(); } - + return $success; } @@ -534,23 +534,28 @@ class Sale extends CI_Model 'discount_percent' => $item['discount'], 'item_cost_price' => $cur_item_info->cost_price, 'item_unit_price' => $item['price'], - 'item_location' => $item['item_location'] + 'item_location' => $item['item_location'], + 'print_option' => $item['print_option'] ); $this->db->insert('sales_items', $sales_items_data); - // Update stock quantity - $item_quantity = $this->Item_quantity->get_item_quantity($item['item_id'], $item['item_location']); - $this->Item_quantity->save(array('quantity' => $item_quantity->quantity - $item['quantity'], - 'item_id' => $item['item_id'], - 'location_id' => $item['item_location']), $item['item_id'], $item['item_location']); + if ($cur_item_info->stock_type === '0') + { + // Update stock quantity if item type is not non-stock + $item_quantity = $this->Item_quantity->get_item_quantity($item['item_id'], $item['item_location']); + $this->Item_quantity->save(array('quantity' => $item_quantity->quantity - $item['quantity'], + 'item_id' => $item['item_id'], + 'location_id' => $item['item_location']), $item['item_id'], $item['item_location']); + } // if an items was deleted but later returned it's restored with this rule + if($item['quantity'] < 0) { $this->Item->undelete($item['item_id']); } - + // Inventory Count Details $sale_remarks = 'POS '.$sale_id; $inv_data = array( @@ -564,8 +569,8 @@ class Sale extends CI_Model $this->Inventory->insert($inv_data); $customer = $this->Customer->get_info($customer_id); - if($customer_id == -1 || $customer->taxable) - { + if($customer_id == -1 || $customer->taxable) + { foreach($this->Item_taxes->get_info($item['item_id']) as $row) { $this->db->insert('sales_items_taxes', array( @@ -580,16 +585,16 @@ class Sale extends CI_Model } $this->db->trans_complete(); - + if($this->db->trans_status() === FALSE) { return -1; } - + return $sale_id; } - public function delete_list($sale_ids, $employee_id, $update_inventory = TRUE) + public function delete_list($sale_ids, $employee_id, $update_inventory = TRUE) { $result = TRUE; @@ -601,7 +606,7 @@ class Sale extends CI_Model return $result; } - public function delete($sale_id, $employee_id, $update_inventory = TRUE) + public function delete($sale_id, $employee_id, $update_inventory = TRUE) { // start a transaction to assure data integrity $this->db->trans_start(); @@ -618,20 +623,24 @@ class Sale extends CI_Model $items = $this->get_sale_items($sale_id)->result_array(); foreach($items as $item) { - // create query to update inventory tracking - $inv_data = array( - 'trans_date' => date('Y-m-d H:i:s'), - 'trans_items' => $item['item_id'], - 'trans_user' => $employee_id, - 'trans_comment' => 'Deleting sale ' . $sale_id, - 'trans_location' => $item['item_location'], - 'trans_inventory' => $item['quantity_purchased'] - ); - // update inventory - $this->Inventory->insert($inv_data); + $cur_item_info = $this->Item->get_info($item['item_id']); - // update quantities - $this->Item_quantity->change_quantity($item['item_id'], $item['item_location'], $item['quantity_purchased']); + if ($cur_item_info->stock_type === '0') { + // create query to update inventory tracking + $inv_data = array( + 'trans_date' => date('Y-m-d H:i:s'), + 'trans_items' => $item['item_id'], + 'trans_user' => $employee_id, + 'trans_comment' => 'Deleting sale ' . $sale_id, + 'trans_location' => $item['item_location'], + 'trans_inventory' => $item['quantity_purchased'] + ); + // update inventory + $this->Inventory->insert($inv_data); + + // update quantities + $this->Item_quantity->change_quantity($item['item_id'], $item['item_location'], $item['quantity_purchased']); + } } } @@ -642,7 +651,7 @@ class Sale extends CI_Model // execute transaction $this->db->trans_complete(); - + return $this->db->trans_status(); } @@ -654,6 +663,58 @@ class Sale extends CI_Model return $this->db->get(); } + /* + * Used by the invoice and receipt programs + */ + public function get_sale_items_ordered($sale_id) + { + $this->db->select(' + sale_id, + sales_items.item_id, + sales_items.description, + serialnumber, + line, + quantity_purchased, + item_cost_price, + item_unit_price, + discount_percent, + item_location, + print_option, + items.name as name, + category, + item_type'); + $this->db->from('sales_items as sales_items'); + $this->db->join('items as items', 'sales_items.item_id = items.item_id'); + $this->db->where('sale_id', $sale_id); + + // Entry sequence (this will render kits in the expected sequence) + if($this->config->item('line_sequence') == '0') + { + $this->db->order_by('line', 'asc'); + } + // Group by Stock Type (nonstock first - type 1, stock next - type 0) + elseif($this->config->item('line_sequence') == '1') + { + $this->db->order_by('stock_type', 'desc'); + $this->db->order_by('sales_items.description', 'asc'); + $this->db->order_by('items.name', 'asc'); + } + // Group by Item Category + elseif($this->config->item('line_sequence') == '2') + { + $this->db->order_by('category', 'asc'); + $this->db->order_by('sales_items.description', 'asc'); + $this->db->order_by('items.name', 'asc'); + } + // Group by entry sequence in descending sequence (the Standard) + else + { + $this->db->order_by('line', 'desc'); + } + + return $this->db->get(); + } + public function get_sale_payments($sale_id) { $this->db->from('sales_payments'); @@ -665,7 +726,7 @@ class Sale extends CI_Model public function get_payment_options($giftcard = TRUE) { $payments = array(); - + if($this->config->item('payment_options_order') == 'debitcreditcash') { $payments[$this->lang->line('sales_debit')] = $this->lang->line('sales_debit'); @@ -719,7 +780,7 @@ class Sale extends CI_Model { $this->db->where('sale_id !=', $sale_id); } - + return ($this->db->get()->num_rows() == 1); } @@ -729,7 +790,7 @@ class Sale extends CI_Model { return 0; } - + $this->db->from('giftcards'); $this->db->where('giftcard_number', $giftcardNumber); @@ -773,7 +834,7 @@ class Sale extends CI_Model } // create a temporary table to contain all the payment types and amount - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_payments_temp') . ' (PRIMARY KEY(sale_id), INDEX(sale_id)) ( SELECT payments.sale_id AS sale_id, @@ -789,38 +850,38 @@ class Sale extends CI_Model )' ); - $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_temp') . + $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_temp') . ' (INDEX(sale_date), INDEX(sale_time), INDEX(sale_id)) ( SELECT - DATE(sales.sale_time) AS sale_date, - sales.sale_time, + MAX(DATE(sales.sale_time)) AS sale_date, + MAX(sales.sale_time) AS sale_time, sales.sale_id, - sales.comment, - sales.invoice_number, - sales.customer_id, - CONCAT(customer_p.first_name, " ", customer_p.last_name) AS customer_name, - customer_p.first_name AS customer_first_name, - customer_p.last_name AS customer_last_name, - customer_p.email AS customer_email, - customer_p.comments AS customer_comments, - customer.company_name AS customer_company_name, - sales.employee_id, - CONCAT(employee.first_name, " ", employee.last_name) AS employee_name, + MAX(sales.comment) AS comment, + MAX(sales.invoice_number) AS invoice_number, + MAX(sales.customer_id) AS customer_id, + MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name, + MAX(customer_p.first_name) AS customer_first_name, + MAX(customer_p.last_name) AS customer_last_name, + MAX(customer_p.email) AS customer_email, + MAX(customer_p.comments) AS customer_comments, + MAX(customer.company_name) AS customer_company_name, + MAX(sales.employee_id) AS employee_id, + MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name, items.item_id, - items.name, - items.category, - items.supplier_id, - sales_items.quantity_purchased, - sales_items.item_cost_price, - sales_items.item_unit_price, - sales_items.discount_percent, + MAX(items.name) AS name, + MAX(items.category) AS category, + MAX(items.supplier_id) AS supplier_id, + MAX(sales_items.quantity_purchased) AS quantity_purchased, + MAX(sales_items.item_cost_price) AS item_cost_price, + MAX(sales_items.item_unit_price) AS item_unit_price, + MAX(sales_items.discount_percent) AS discount_percent, sales_items.line, - sales_items.serialnumber, - sales_items.item_location, - sales_items.description, - payments.payment_type, - payments.sale_payment_amount, + MAX(sales_items.serialnumber) AS serialnumber, + MAX(sales_items.item_location) AS item_location, + MAX(sales_items.description) AS description, + MAX(payments.payment_type) AS payment_type, + MAX(payments.sale_payment_amount) AS sale_payment_amount, IFNULL(SUM(sales_items_taxes.percent), 0) AS item_tax_percent, ' . " ROUND($sale_subtotal, $decimals) AS subtotal, diff --git a/application/models/reports/Detailed_receivings.php b/application/models/reports/Detailed_receivings.php index 956d7c73a..aba669d80 100644 --- a/application/models/reports/Detailed_receivings.php +++ b/application/models/reports/Detailed_receivings.php @@ -14,7 +14,7 @@ class Detailed_receivings extends Report //Create our temp tables to work with the data in our report $this->Receiving->create_temp_table($inputs); } - + public function getDataColumns() { $columns = array( @@ -26,8 +26,8 @@ class Detailed_receivings extends Report array('supplier_name' => $this->lang->line('reports_supplied_by')), array('total' => $this->lang->line('reports_total'), 'sorter' => 'number_sorter'), array('payment_type' => $this->lang->line('reports_payment_type')), - array('reference' => $this->lang->line('receivings_reference')), - array('comment' => $this->lang->line('reports_comments'))), + array('comment' => $this->lang->line('reports_comments')), + array('reference' => $this->lang->line('receivings_reference'))), 'details' => array( $this->lang->line('reports_item_number'), $this->lang->line('reports_name'), @@ -39,22 +39,42 @@ class Detailed_receivings extends Report return $columns; } - + public function getDataByReceivingId($receiving_id) { - $this->db->select('receiving_id, receiving_date, SUM(quantity_purchased) AS items_purchased, CONCAT(employee.first_name, " ", employee.last_name) AS employee_name, supplier.company_name AS supplier_name, SUM(subtotal) AS subtotal, SUM(total) AS total, SUM(profit) AS profit, payment_type, comment, reference'); + $this->db->select('receiving_id, + MAX(receiving_date) as receiving_date, + SUM(quantity_purchased) AS items_purchased, + MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name, + MAX(supplier.company_name) AS supplier_name, + SUM(subtotal) AS subtotal, + SUM(total) AS total, + SUM(profit) AS profit, + MAX(payment_type) as payment_type, + MAX(comment) as comment, + MAX(reference) as reference'); $this->db->from('receivings_items_temp'); $this->db->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id'); $this->db->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left'); $this->db->where('receiving_id', $receiving_id); + $this->db->group_by('receiving_id'); return $this->db->get()->row_array(); } - + public function getData(array $inputs) { - $this->db->select('receiving_id, receiving_date, SUM(quantity_purchased) AS items_purchased, CONCAT(employee.first_name," ",employee.last_name) AS employee_name, supplier.company_name AS supplier_name, SUM(total) AS total, SUM(profit) AS profit, payment_type, comment, reference'); - $this->db->from('receivings_items_temp'); + $this->db->select('receiving_id, + MAX(receiving_date) as receiving_date, + SUM(quantity_purchased) AS items_purchased, + MAX(CONCAT(employee.first_name," ",employee.last_name)) AS employee_name, + MAX(supplier.company_name) AS supplier_name, + SUM(total) AS total, + SUM(profit) AS profit, + MAX(payment_type) AS payment_type, + MAX(comment) AS comment, + MAX(reference) AS reference'); + $this->db->from('receivings_items_temp AS receivings_items_temp'); $this->db->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id'); $this->db->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left'); @@ -74,13 +94,13 @@ class Detailed_receivings extends Report { $this->db->having('items_purchased = 0'); } - $this->db->group_by('receiving_id'); - $this->db->order_by('receiving_date'); + $this->db->group_by('receiving_id', 'receiving_date'); + $this->db->order_by('receiving_id'); $data = array(); $data['summary'] = $this->db->get()->result_array(); $data['details'] = array(); - + foreach($data['summary'] as $key=>$value) { $this->db->select('name, item_number, category, quantity_purchased, serialnumber,total, discount_percent, item_location, receivings_items_temp.receiving_quantity'); @@ -89,10 +109,10 @@ class Detailed_receivings extends Report $this->db->where('receiving_id = '.$value['receiving_id']); $data['details'][$key] = $this->db->get()->result_array(); } - + return $data; } - + public function getSummaryData(array $inputs) { $this->db->select('SUM(total) AS total'); diff --git a/application/models/reports/Detailed_sales.php b/application/models/reports/Detailed_sales.php index a060fa111..540e87eda 100644 --- a/application/models/reports/Detailed_sales.php +++ b/application/models/reports/Detailed_sales.php @@ -25,8 +25,8 @@ class Detailed_sales extends Report array('employee_name' => $this->lang->line('reports_sold_by')), array('customer_name' => $this->lang->line('reports_sold_to')), array('subtotal' => $this->lang->line('reports_subtotal'), 'sorter' => 'number_sorter'), - array('total' => $this->lang->line('reports_total'), 'sorter' => 'number_sorter'), array('tax' => $this->lang->line('reports_tax'), 'sorter' => 'number_sorter'), + array('total' => $this->lang->line('reports_total'), 'sorter' => 'number_sorter'), array('cost' => $this->lang->line('reports_cost'), 'sorter' => 'number_sorter'), array('profit' => $this->lang->line('reports_profit'), 'sorter' => 'number_sorter'), array('payment_type' => $this->lang->line('sales_amount_tendered')), @@ -43,7 +43,7 @@ class Detailed_sales extends Report $this->lang->line('reports_cost'), $this->lang->line('reports_profit'), $this->lang->line('reports_discount')) - ); + ); } public function getDataBySaleId($sale_id) @@ -57,7 +57,18 @@ class Detailed_sales extends Report public function getData(array $inputs) { - $this->db->select('sale_id, sale_date, SUM(quantity_purchased) AS items_purchased, employee_name, customer_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, payment_type, comment'); + $this->db->select('sale_id, + MAX(sale_date) AS sale_date, + SUM(quantity_purchased) AS items_purchased, + MAX(employee_name) AS employee_name, + MAX(customer_name) AS customer_name, + SUM(subtotal) AS subtotal, + SUM(tax) AS tax, + SUM(total) AS total, + SUM(cost) AS cost, + SUM(profit) AS profit, + MAX(payment_type) AS payment_type, + MAX(comment) AS comment'); $this->db->from('sales_items_temp'); if($inputs['location_id'] != 'all') @@ -75,7 +86,7 @@ class Detailed_sales extends Report } $this->db->group_by('sale_id'); - $this->db->order_by('sale_date'); + $this->db->order_by('MAX(sale_date)'); $data = array(); $data['summary'] = $this->db->get()->result_array(); @@ -99,7 +110,7 @@ class Detailed_sales extends Report if($inputs['location_id'] != 'all') { - $this->db->where('item_location', $inputs['location_id']); + $this->db->where('item_location', $inputs['location_id']); } if($inputs['sale_type'] == 'sales') diff --git a/application/models/reports/Inventory_low.php b/application/models/reports/Inventory_low.php index 943aef993..e2b23f0f6 100644 --- a/application/models/reports/Inventory_low.php +++ b/application/models/reports/Inventory_low.php @@ -27,7 +27,7 @@ class Inventory_low extends Report $this->db->join('stock_locations', 'item_quantities.location_id = stock_locations.location_id'); $this->db->where('items.deleted', 0); $this->db->where('stock_locations.deleted', 0); - $this->db->where('item_quantities.quantity <= items.reorder_level'); + $this->db->where('items.stock_type', 0); $this->db->order_by('items.name'); return $this->db->get()->result_array(); diff --git a/application/models/reports/Inventory_summary.php b/application/models/reports/Inventory_summary.php index 443290f9c..b2ed5b582 100644 --- a/application/models/reports/Inventory_summary.php +++ b/application/models/reports/Inventory_summary.php @@ -28,6 +28,7 @@ class Inventory_summary extends Report $this->db->join('item_quantities AS item_quantities', 'items.item_id = item_quantities.item_id'); $this->db->join('stock_locations AS stock_locations', 'item_quantities.location_id = stock_locations.location_id'); $this->db->where('items.deleted', 0); + $this->db->where('items.stock_type', 0); $this->db->where('stock_locations.deleted', 0); // should be corresponding to values Inventory_summary::getItemCountDropdownArray() returns... diff --git a/application/models/reports/Specific_customer.php b/application/models/reports/Specific_customer.php index d698a96be..7ab99546a 100644 --- a/application/models/reports/Specific_customer.php +++ b/application/models/reports/Specific_customer.php @@ -8,13 +8,13 @@ class Specific_customer extends Report { parent::__construct(); } - + public function create(array $inputs) { //Create our temp tables to work with the data in our report $this->Sale->create_temp_table($inputs); } - + public function getDataColumns() { return array( @@ -44,10 +44,10 @@ class Specific_customer extends Report $this->lang->line('reports_discount')) ); } - + public function getData(array $inputs) { - $this->db->select('sale_id, sale_date, SUM(quantity_purchased) AS items_purchased, employee_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, payment_type, comment'); + $this->db->select('sale_id, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, MAX(employee_name) AS employee_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, MAX(payment_type) AS payment_type, MAX(comment) AS comment'); $this->db->from('sales_items_temp'); $this->db->where('customer_id', $inputs['customer_id']); @@ -61,12 +61,12 @@ class Specific_customer extends Report } $this->db->group_by('sale_id'); - $this->db->order_by('sale_date'); + $this->db->order_by('MAX(sale_date)'); $data = array(); $data['summary'] = $this->db->get()->result_array(); $data['details'] = array(); - + foreach($data['summary'] as $key=>$value) { $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); @@ -77,7 +77,7 @@ class Specific_customer extends Report return $data; } - + public function getSummaryData(array $inputs) { $this->db->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit'); diff --git a/application/models/reports/Specific_discount.php b/application/models/reports/Specific_discount.php index 2ae0cfc11..609e7b7ce 100755 --- a/application/models/reports/Specific_discount.php +++ b/application/models/reports/Specific_discount.php @@ -8,13 +8,13 @@ class Specific_discount extends Report { parent::__construct(); } - + public function create(array $inputs) { //Create our temp tables to work with the data in our report $this->Sale->create_temp_table($inputs); } - + public function getDataColumns() { return array( @@ -40,12 +40,12 @@ class Specific_discount extends Report $this->lang->line('reports_tax'), $this->lang->line('reports_profit'), $this->lang->line('reports_discount')) - ); + ); } - + public function getData(array $inputs) { - $this->db->select('sale_id, sale_date, SUM(quantity_purchased) AS items_purchased, customer_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, payment_type, comment'); + $this->db->select('sale_id, MAX(sale_date) AS sales_date, SUM(quantity_purchased) AS items_purchased, MAX(customer_name) AS customer_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, MAX(payment_type) AS payment_type, MAX(comment) AS comment'); $this->db->from('sales_items_temp'); $this->db->where('discount_percent >=', $inputs['discount']); @@ -59,12 +59,12 @@ class Specific_discount extends Report } $this->db->group_by('sale_id'); - $this->db->order_by('sale_date'); + $this->db->order_by('MAX(sale_date)'); $data = array(); $data['summary'] = $this->db->get()->result_array(); $data['details'] = array(); - + foreach($data['summary'] as $key=>$value) { $this->db->select('name, serialnumber, category, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); @@ -75,13 +75,13 @@ class Specific_discount extends Report return $data; } - + public function getSummaryData(array $inputs) { $this->db->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit'); $this->db->from('sales_items_temp'); $this->db->where('discount_percent >=', $inputs['discount']); - + if ($inputs['sale_type'] == 'sales') { $this->db->where('quantity_purchased > 0'); diff --git a/application/models/reports/Specific_employee.php b/application/models/reports/Specific_employee.php index c924d54a5..e36f7ae6d 100644 --- a/application/models/reports/Specific_employee.php +++ b/application/models/reports/Specific_employee.php @@ -8,13 +8,13 @@ class Specific_employee extends Report { parent::__construct(); } - + public function create(array $inputs) { //Create our temp tables to work with the data in our report $this->Sale->create_temp_table($inputs); } - + public function getDataColumns() { return array( @@ -42,31 +42,31 @@ class Specific_employee extends Report $this->lang->line('reports_cost'), $this->lang->line('reports_profit'), $this->lang->line('reports_discount')) - ); + ); } - + public function getData(array $inputs) { - $this->db->select('sale_id, sale_date, SUM(quantity_purchased) AS items_purchased, customer_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, payment_type, comment'); + $this->db->select('sale_id, MAX(sale_date) AS sale_date, SUM(quantity_purchased) AS items_purchased, MAX(customer_name) AS customer_name, SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit, MAX(payment_type) AS payment_type, MAX(comment) AS comment'); $this->db->from('sales_items_temp'); $this->db->where('employee_id', $inputs['employee_id']); - + if ($inputs['sale_type'] == 'sales') - { - $this->db->where('quantity_purchased > 0'); - } - elseif ($inputs['sale_type'] == 'returns') - { - $this->db->where('quantity_purchased < 0'); - } - + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('sale_id'); - $this->db->order_by('sale_date'); + $this->db->order_by('MAX(sale_date)'); $data = array(); $data['summary'] = $this->db->get()->result_array(); $data['details'] = array(); - + foreach($data['summary'] as $key=>$value) { $this->db->select('name, category, serialnumber, description, quantity_purchased, subtotal, tax, total, cost, profit, discount_percent'); @@ -74,10 +74,10 @@ class Specific_employee extends Report $this->db->where('sale_id', $value['sale_id']); $data['details'][$key] = $this->db->get()->result_array(); } - + return $data; } - + public function getSummaryData(array $inputs) { $this->db->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit'); diff --git a/application/models/reports/Summary_discounts.php b/application/models/reports/Summary_discounts.php index 338fec5b7..80a279e8b 100644 --- a/application/models/reports/Summary_discounts.php +++ b/application/models/reports/Summary_discounts.php @@ -8,7 +8,7 @@ class Summary_discounts extends Summary_report { parent::__construct(); } - + protected function _get_data_columns() { return array( @@ -18,18 +18,18 @@ class Summary_discounts extends Summary_report public function getData(array $inputs) { - $this->db->select('CONCAT(sales_items.discount_percent, "%") AS discount_percent, count(*) AS count'); + $this->db->select('MAX(CONCAT(sales_items.discount_percent, "%")) AS discount_percent, count(*) AS count'); $this->db->from('sales_items AS sales_items'); $this->db->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner'); $this->db->where('discount_percent > 0'); $this->_where($inputs); - + $this->db->group_by('sales_items.discount_percent'); $this->db->order_by('sales_items.discount_percent'); - return $this->db->get()->result_array(); + return $this->db->get()->result_array(); } } ?> diff --git a/application/models/reports/Summary_employees.php b/application/models/reports/Summary_employees.php index 2e3997a1b..2824911ec 100644 --- a/application/models/reports/Summary_employees.php +++ b/application/models/reports/Summary_employees.php @@ -8,7 +8,7 @@ class Summary_employees extends Summary_report { parent::__construct(); } - + protected function _get_data_columns() { return array( @@ -26,7 +26,7 @@ class Summary_employees extends Summary_report parent::_select($inputs); $this->db->select(' - CONCAT(employee_p.first_name, " ", employee_p.last_name) AS employee, + MAX(CONCAT(employee_p.first_name, " ", employee_p.last_name)) AS employee, SUM(sales_items.quantity_purchased) AS quantity_purchased '); } diff --git a/application/models/reports/Summary_items.php b/application/models/reports/Summary_items.php index 30a57039f..515e0f636 100644 --- a/application/models/reports/Summary_items.php +++ b/application/models/reports/Summary_items.php @@ -26,7 +26,7 @@ class Summary_items extends Summary_report parent::_select($inputs); $this->db->select(' - items.name AS name, + MAX(items.name) AS name, SUM(sales_items.quantity_purchased) AS quantity_purchased '); } @@ -41,7 +41,7 @@ class Summary_items extends Summary_report protected function _group_order() { $this->db->group_by('items.item_id'); - $this->db->order_by('items.name'); + $this->db->order_by('name'); } } ?> diff --git a/application/models/reports/Summary_sales.php b/application/models/reports/Summary_sales.php index 692df096d..2c174fa76 100644 --- a/application/models/reports/Summary_sales.php +++ b/application/models/reports/Summary_sales.php @@ -26,11 +26,11 @@ class Summary_sales extends Summary_report parent::_select($inputs); $this->db->select(' - DATE(sales.sale_time) AS sale_date, + DATE(sales.sale_time) AS sale_date, SUM(sales_items.quantity_purchased) AS quantity_purchased '); } - + protected function _group_order() { $this->db->group_by('sale_date'); diff --git a/application/models/reports/Summary_suppliers.php b/application/models/reports/Summary_suppliers.php index 97b478c51..0aad9c808 100644 --- a/application/models/reports/Summary_suppliers.php +++ b/application/models/reports/Summary_suppliers.php @@ -26,7 +26,7 @@ class Summary_suppliers extends Summary_report parent::_select($inputs); $this->db->select(' - CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")") AS supplier, + MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")")) AS supplier, SUM(sales_items.quantity_purchased) AS quantity_purchased '); } @@ -35,15 +35,15 @@ class Summary_suppliers extends Summary_report { parent::_from(); - $this->db->join('items AS items', 'sales_items.item_id = items.item_id', 'inner'); - $this->db->join('suppliers AS supplier_c', 'supplier_c.person_id = items.supplier_id'); - $this->db->join('people AS supplier_p', 'supplier_c.person_id = supplier_p.person_id'); + $this->db->join('items AS items', 'sales_items.item_id = items.item_id'); + $this->db->join('suppliers AS supplier_c', 'items.supplier_id = supplier_c.person_id '); + $this->db->join('people AS supplier_p', 'items.supplier_id = supplier_p.person_id'); } protected function _group_order() { $this->db->group_by('items.supplier_id'); - $this->db->order_by('supplier_p.last_name'); + $this->db->order_by('MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")"))'); } } ?> diff --git a/application/views/configs/invoice_config.php b/application/views/configs/invoice_config.php index 51caac39e..adf8b09dd 100644 --- a/application/views/configs/invoice_config.php +++ b/application/views/configs/invoice_config.php @@ -59,6 +59,13 @@ +
+ lang->line('config_line_sequence'), 'line_sequence', array('class' => 'control-label col-xs-2')); ?> +
+ config->item('line_sequence'), array('class' => 'form-control input-sm')); ?> +
+
+ 'submit_form', 'id' => 'submit_form', diff --git a/application/views/item_kits/form.php b/application/views/item_kits/form.php index e4179592b..dba610952 100644 --- a/application/views/item_kits/form.php +++ b/application/views/item_kits/form.php @@ -16,6 +16,109 @@ +
+ lang->line('item_kits_find_kit_item'), 'item_name', array('class'=>'control-label col-xs-3')); ?> +
+
+ 'item_name', + 'id'=>'item_name', + 'class'=>'form-control input-sm', + 'size'=>'50', + 'value'=>$selected_kit_item) + ); ?> + + +
+
+
+ +
+ lang->line('item_kits_discount_percent'), 'kit_discount_percent', array('class' => 'control-label col-xs-3')); ?> +
+
+ 'kit_discount_percent', + 'size'=>'5', + 'maxlength'=>'5', + 'id'=>'kit_discount_percent', + 'class'=>'form-control input-sm', + 'value'=>$item_kit_info->kit_discount_percent) + );?> + % +
+
+
+ +
+ lang->line('item_kits_price_option'), 'price_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> +
+ + + + +
+
+ +
+ lang->line('item_kits_print_option'), 'print_option', !empty($basic_version) ? array('class'=>'required control-label col-xs-3') : array('class'=>'control-label col-xs-3')); ?> +
+ + + + +
+
+ +
lang->line('item_kits_description'), 'description', array('class'=>'control-label col-xs-3')); ?>
@@ -43,7 +146,8 @@ lang->line('common_delete'); ?> - lang->line('item_kits_item'); ?> + lang->line('item_kits_sequence'); ?> + lang->line('item_kits_item'); ?> lang->line('item_kits_quantity'); ?> @@ -54,8 +158,9 @@ ?> + ' name=item_kit_seq[] value=''/> - ' name=item_kit_item[] value=''/> + ' name=item_kit_qty[] value=''/> +