diff --git a/application/controllers/Config.php b/application/controllers/Config.php
index a16458559..9c08478be 100644
--- a/application/controllers/Config.php
+++ b/application/controllers/Config.php
@@ -299,6 +299,7 @@ class Config extends Secure_Controller
'suggestions_third_column' => $this->input->post('suggestions_third_column'),
'giftcard_number' => $this->input->post('giftcard_number'),
'derive_sale_quantity' => $this->input->post('derive_sale_quantity') != NULL,
+ 'multi_pack_enabled' => $this->input->post('multi_pack_enabled') != NULL,
'custom1_name' => $this->input->post('custom1_name'),
'custom2_name' => $this->input->post('custom2_name'),
'custom3_name' => $this->input->post('custom3_name'),
diff --git a/application/controllers/Items.php b/application/controllers/Items.php
index 2e6d2a3a8..6a5395fb8 100644
--- a/application/controllers/Items.php
+++ b/application/controllers/Items.php
@@ -128,6 +128,15 @@ class Items extends Secure_Controller
echo json_encode($suggestions);
}
+
+ public function suggest_low_sell()
+ {
+ $suggestions = $this->xss_clean($this->Item->get_low_sell_suggestions($this->input->post_get('name')));
+
+ echo json_encode($suggestions);
+ }
+
+
public function suggest_kits()
{
$suggestions = $this->xss_clean($this->Item->get_kit_search_suggestions($this->input->post_get('term'),
@@ -181,9 +190,13 @@ class Items extends Secure_Controller
public function view($item_id = -1)
{
+ if($item_id == -1)
+ {
+ $data = array();
+ }
+
// allow_temp_items is set in the index function of items.php or sales.php
$data['allow_temp_item'] = $this->session->userdata('allow_temp_items');
-
$data['item_tax_info'] = $this->xss_clean($this->Item_taxes->get_info($item_id));
$data['default_tax_1_rate'] = '';
$data['default_tax_2_rate'] = '';
@@ -224,6 +237,8 @@ class Items extends Secure_Controller
$item_info->item_type = ITEM; // standard
$item_info->stock_type = HAS_STOCK;
$item_info->tax_category_id = 1; // Standard
+ $item_info->qty_per_pack = 1;
+ $item_info->pack_name = $this->lang->line('items_default_pack_name');
}
$data['item_info'] = $item_info;
@@ -279,6 +294,18 @@ class Items extends Secure_Controller
$data['stock_locations'] = $location_array;
}
+ $data['selected_low_sell_item_id'] = $item_info->low_sell_item_id;
+
+ if($item_id != -1 && $item_info->item_id != $item_info->low_sell_item_id)
+ {
+ $low_sell_item_info = $this->Item->get_info($item_info->low_sell_item_id);
+ $data['selected_low_sell_item'] = implode(NAME_SEPARATOR, array($low_sell_item_info->name, $low_sell_item_info->pack_name));
+ }
+ else
+ {
+ $data['selected_low_sell_item'] = '';
+ }
+
$this->load->view('items/form', $data);
}
@@ -397,6 +424,8 @@ class Items extends Secure_Controller
{
$receiving_quantity = '1';
}
+ $default_pack_name = $this->lang->line('items_default_pack_name');
+
//Save item data
$item_data = array(
'name' => $this->input->post('name'),
@@ -412,6 +441,9 @@ class Items extends Secure_Controller
'receiving_quantity' => $receiving_quantity,
'allow_alt_description' => $this->input->post('allow_alt_description') != NULL,
'is_serialized' => $this->input->post('is_serialized') != NULL,
+ 'qty_per_pack' => $this->input->post('qty_per_pack') == NULL ? 1 : $this->input->post('qty_per_pack'),
+ 'pack_name' => $this->input->post('pack_name') == NULL ? $default_pack_name : $this->input->post('pack_name'),
+ 'low_sell_item_id' => $this->input->post('low_sell_item_id') == NULL ? -1 : $this->input->post('low_sell_item_id'),
'deleted' => $this->input->post('is_deleted') != NULL,
'custom1' => $this->input->post('custom1') == NULL ? '' : $this->input->post('custom1'),
'custom2' => $this->input->post('custom2') == NULL ? '' : $this->input->post('custom2'),
diff --git a/application/controllers/Receivings.php b/application/controllers/Receivings.php
index 5e4f0a1c2..8972b85ec 100644
--- a/application/controllers/Receivings.php
+++ b/application/controllers/Receivings.php
@@ -124,10 +124,11 @@ class Receivings extends Secure_Controller
$quantity = parse_decimals($this->input->post('quantity'));
$discount = parse_decimals($this->input->post('discount'));
$item_location = $this->input->post('location');
+ $receiving_quantity = $this->input->post('receiving_quantity');
if($this->form_validation->run() != FALSE)
{
- $this->receiving_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $price);
+ $this->receiving_lib->edit_item($item_id, $description, $serialnumber, $quantity, $discount, $price, $receiving_quantity);
}
else
{
diff --git a/application/controllers/Reports.php b/application/controllers/Reports.php
index 8d05d4c88..82b4b9eff 100644
--- a/application/controllers/Reports.php
+++ b/application/controllers/Reports.php
@@ -1420,6 +1420,7 @@ class Reports extends Secure_Controller
'item_name' => $row['name'],
'item_number' => $row['item_number'],
'quantity' => to_quantity_decimals($row['quantity']),
+ 'low_sell_quantity' => to_quantity_decimals($row['low_sell_quantity']),
'reorder_level' => to_quantity_decimals($row['reorder_level']),
'location_name' => $row['location_name'],
'cost_price' => to_currency($row['cost_price']),
diff --git a/application/helpers/tabular_helper.php b/application/helpers/tabular_helper.php
index 9e1101983..f37befc91 100644
--- a/application/helpers/tabular_helper.php
+++ b/application/helpers/tabular_helper.php
@@ -374,6 +374,11 @@ function get_item_data_row($item)
}
}
+ if ($CI->config->item('multi_pack_enabled') == '1')
+ {
+ $item->name .= NAME_SEPARATOR . $item->pack_name;
+ }
+
return array (
'items.item_id' => $item->item_id,
'item_number' => $item->item_number,
diff --git a/application/language/en-GB/config_lang.php b/application/language/en-GB/config_lang.php
index f581ce4e1..91c35af9f 100644
--- a/application/language/en-GB/config_lang.php
+++ b/application/language/en-GB/config_lang.php
@@ -181,6 +181,7 @@ $lang["config_msg_src"] = "SMS-API Sender ID";
$lang["config_msg_src_required"] = "SMS-API Sender ID is a required field";
$lang["config_msg_uid"] = "SMS-API Username";
$lang["config_msg_uid_required"] = "SMS-API Username is a required field";
+$lang["config_multi_pack_enabled"] = "Multiple Packages per Item";
$lang["config_none"] = "none";
$lang["config_notify_alignment"] = "Notification Popup Position";
$lang["config_number_format"] = "Number Format";
diff --git a/application/language/en-GB/items_lang.php b/application/language/en-GB/items_lang.php
index f993612c0..8cdb10235 100644
--- a/application/language/en-GB/items_lang.php
+++ b/application/language/en-GB/items_lang.php
@@ -24,6 +24,7 @@ $lang["items_cost_price_number"] = "Cost Price must be a number";
$lang["items_cost_price_required"] = "Cost Price is a required field";
$lang["items_count"] = "Update Inventory";
$lang["items_current_quantity"] = "Current Quantity";
+$lang["items_default_pack_name"] = "Each";
$lang["items_description"] = "Description";
$lang["items_details_count"] = "Inventory count details";
$lang["items_do_nothing"] = "Do nothing";
@@ -55,6 +56,7 @@ $lang["items_item_number_duplicate"] = "Item Number is already present in the da
$lang["items_kit"] = "Kit";
$lang["items_location"] = "Location";
$lang["items_low_inventory_items"] = "Out Of Stock Items";
+$lang["items_low_sell_item"] = "Low sell item";
$lang["items_manually_editing_of_quantity"] = "Manual Edit of Quantity";
$lang["items_name"] = "Item Name";
$lang["items_name_required"] = "Item Name is a required field";
@@ -67,6 +69,8 @@ $lang["items_nonstock"] = "Non-stocked";
$lang["items_number_information"] = "Item Number";
$lang["items_number_required"] = "Barcode is a required field";
$lang["items_one_or_multiple"] = "item(s)";
+$lang["items_pack_name"] = "Pack Name";
+$lang["items_qty_per_pack"] = "Quantity per pack";
$lang["items_quantity"] = "Quantity";
$lang["items_quantity_number"] = "Quantity must be a number";
$lang["items_quantity_required"] = "Quantity is a required field";
diff --git a/application/language/en-GB/receivings_lang.php b/application/language/en-GB/receivings_lang.php
index a44ed6565..6237237da 100644
--- a/application/language/en-GB/receivings_lang.php
+++ b/application/language/en-GB/receivings_lang.php
@@ -35,6 +35,7 @@ $lang["receivings_register"] = "Items Receiving";
$lang["receivings_requisition"] = "Requisition";
$lang["receivings_return"] = "Return";
$lang["receivings_select_supplier"] = "Select Supplier (Optional)";
+$lang["receivings_ship_pack"] = "Ship Pack";
$lang["receivings_start_typing_supplier_name"] = "Start Typing Supplier's name...";
$lang["receivings_stock"] = "Stock";
$lang["receivings_stock_destination"] = "Stock Destination";
diff --git a/application/language/en-GB/reports_lang.php b/application/language/en-GB/reports_lang.php
index 6f8148b31..cadad4315 100644
--- a/application/language/en-GB/reports_lang.php
+++ b/application/language/en-GB/reports_lang.php
@@ -63,6 +63,7 @@ $lang["reports_items_received"] = "Items Received";
$lang["reports_items_summary_report"] = "Items Summary Report";
$lang["reports_low_inventory"] = "";
$lang["reports_low_inventory_report"] = "";
+$lang["reports_low_sell_quantity"] = "Low Sell Qty";
$lang["reports_more_than_zero"] = "More than zero";
$lang["reports_name"] = "Name";
$lang["reports_no_reports_to_display"] = "No Items to display";
@@ -114,6 +115,7 @@ $lang["reports_taxes"] = "Taxes";
$lang["reports_taxes_summary_report"] = "Taxes Summary Report";
$lang["reports_total"] = "Total";
$lang["reports_total_inventory_value"] = "Total Inventory Value";
+$lang["reports_total_low_sell_quantity"] = "Total Low Sell Quantity";
$lang["reports_total_quantity"] = "Total Quantity";
$lang["reports_total_retail"] = "Total Inv. Retail Value";
$lang["reports_type"] = "Type";
diff --git a/application/language/en-GB/sales_lang.php b/application/language/en-GB/sales_lang.php
index a106e54da..2802e1dcf 100644
--- a/application/language/en-GB/sales_lang.php
+++ b/application/language/en-GB/sales_lang.php
@@ -84,7 +84,7 @@ $lang["sales_must_enter_numeric"] = "Amount Tendered must be a number";
$lang["sales_must_enter_numeric_giftcard"] = "Gift Card Number must be a number";
$lang["sales_new_customer"] = "New Customer";
$lang["sales_new_item"] = "New Item";
-$lang["sales_no_description"] = "None";
+$lang["sales_no_description"] = "No description";
$lang["sales_no_filter"] = "All";
$lang["sales_no_items_in_cart"] = "There are no Items in the cart";
$lang["sales_no_sales_to_display"] = "No Sales to display";
diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php
index 00bf2e81b..a1ac16e7b 100644
--- a/application/language/en-US/config_lang.php
+++ b/application/language/en-US/config_lang.php
@@ -181,6 +181,7 @@ $lang["config_msg_src"] = "SMS-API Sender ID";
$lang["config_msg_src_required"] = "SMS-API Sender ID is a required field";
$lang["config_msg_uid"] = "SMS-API Username";
$lang["config_msg_uid_required"] = "SMS-API Username is a required field";
+$lang["config_multi_pack_enabled"] = "Multiple Packages per Item";
$lang["config_none"] = "none";
$lang["config_notify_alignment"] = "Notification Popup Position";
$lang["config_number_format"] = "Number Format";
diff --git a/application/language/en-US/items_lang.php b/application/language/en-US/items_lang.php
index bf8527123..d44e7d7ed 100644
--- a/application/language/en-US/items_lang.php
+++ b/application/language/en-US/items_lang.php
@@ -24,6 +24,7 @@ $lang["items_cost_price_number"] = "Wholesale Price must be a number.";
$lang["items_cost_price_required"] = "Wholesale Price is a required field.";
$lang["items_count"] = "Update Inventory";
$lang["items_current_quantity"] = "Current Quantity";
+$lang["items_default_pack_name"] = "Each";
$lang["items_description"] = "Description";
$lang["items_details_count"] = "Inventory Count Details";
$lang["items_do_nothing"] = "Do Nothing";
@@ -55,6 +56,7 @@ $lang["items_item_number_duplicate"] = "Item Number is already present in the da
$lang["items_kit"] = "Kit";
$lang["items_location"] = "Location";
$lang["items_low_inventory_items"] = "Out Of Stock Items";
+$lang["items_low_sell_item"] = "Low sell item";
$lang["items_manually_editing_of_quantity"] = "Manual Edit of Quantity";
$lang["items_name"] = "Item Name";
$lang["items_name_required"] = "Item Name is a required field.";
@@ -67,6 +69,8 @@ $lang["items_nonstock"] = "Non-stocked";
$lang["items_number_information"] = "Item Number";
$lang["items_number_required"] = "Barcode is a required field.";
$lang["items_one_or_multiple"] = "item(s)";
+$lang["items_pack_name"] = "Pack Name";
+$lang["items_qty_per_pack"] = "Quantity per pack";
$lang["items_quantity"] = "Quantity";
$lang["items_quantity_number"] = "Quantity must be a number.";
$lang["items_quantity_required"] = "Quantity is a required field.";
diff --git a/application/language/en-US/receivings_lang.php b/application/language/en-US/receivings_lang.php
index d56372f33..0f4138555 100644
--- a/application/language/en-US/receivings_lang.php
+++ b/application/language/en-US/receivings_lang.php
@@ -35,6 +35,7 @@ $lang["receivings_register"] = "Items Receiving";
$lang["receivings_requisition"] = "Requisition";
$lang["receivings_return"] = "Return";
$lang["receivings_select_supplier"] = "Select Supplier (Optional)";
+$lang["receivings_ship_pack"] = "Ship Pack";
$lang["receivings_start_typing_supplier_name"] = "Start Typing Supplier's name...";
$lang["receivings_stock"] = "Stock";
$lang["receivings_stock_destination"] = "Stock Destination";
diff --git a/application/language/en-US/reports_lang.php b/application/language/en-US/reports_lang.php
index e73037774..4563efcb4 100644
--- a/application/language/en-US/reports_lang.php
+++ b/application/language/en-US/reports_lang.php
@@ -63,6 +63,7 @@ $lang["reports_items_received"] = "Items Received";
$lang["reports_items_summary_report"] = "Items Summary Report";
$lang["reports_low_inventory"] = "";
$lang["reports_low_inventory_report"] = "";
+$lang["reports_low_sell_quantity"] = "Low Sell Qty";
$lang["reports_more_than_zero"] = "More than zero";
$lang["reports_name"] = "Name";
$lang["reports_no_reports_to_display"] = "No Items to display.";
@@ -114,6 +115,7 @@ $lang["reports_taxes"] = "Taxes";
$lang["reports_taxes_summary_report"] = "Taxes Summary Report";
$lang["reports_total"] = "Total";
$lang["reports_total_inventory_value"] = "Total Inventory Value";
+$lang["reports_total_low_sell_quantity"] = "Total Low Sell Quantity";
$lang["reports_total_quantity"] = "Total Quantity";
$lang["reports_total_retail"] = "Total Inv. Retail Value";
$lang["reports_type"] = "Type";
diff --git a/application/language/en-US/sales_lang.php b/application/language/en-US/sales_lang.php
index dbb549a52..7b1efb4df 100644
--- a/application/language/en-US/sales_lang.php
+++ b/application/language/en-US/sales_lang.php
@@ -84,7 +84,7 @@ $lang["sales_must_enter_numeric"] = "Amount Tendered must be a number.";
$lang["sales_must_enter_numeric_giftcard"] = "Gift Card Number must be a number.";
$lang["sales_new_customer"] = "New Customer";
$lang["sales_new_item"] = "New Item";
-$lang["sales_no_description"] = "None";
+$lang["sales_no_description"] = "No description";
$lang["sales_no_filter"] = "All";
$lang["sales_no_items_in_cart"] = "There are no Items in the cart.";
$lang["sales_no_sales_to_display"] = "No Sales to display.";
diff --git a/application/libraries/Receiving_lib.php b/application/libraries/Receiving_lib.php
index 894474bc9..4c01e9bbc 100644
--- a/application/libraries/Receiving_lib.php
+++ b/application/libraries/Receiving_lib.php
@@ -209,6 +209,23 @@ class Receiving_lib
$item_info = $this->CI->Item->get_info($item_id,$item_location);
//array records are identified by $insertkey and item_id is just another field.
$price = $price != NULL ? $price : $item_info->cost_price;
+
+ if($this->CI->config->item('multi_pack_enabled') == '1')
+ {
+ $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
+ }
+
+ if ($item_info->receiving_quantity == 0 || $item_info->receiving_quantity == 1)
+ {
+ $receiving_quantity_choices = array(1 => 'x1');
+ }
+ else
+ {
+ $receiving_quantity_choices = array(
+ to_quantity_decimals($item_info->receiving_quantity) => 'x' . to_quantity_decimals($item_info->receiving_quantity),
+ 1 => 'x1');
+ }
+
$item = array($insertkey => array(
'item_id' => $item_id,
'item_location' => $item_location,
@@ -223,8 +240,9 @@ class Receiving_lib
'discount' => $discount,
'in_stock' => $this->CI->Item_quantity->get_item_quantity($item_id, $item_location)->quantity,
'price' => $price,
- 'receiving_quantity' => $receiving_quantity!=NULL ? $receiving_quantity : $item_info->receiving_quantity,
- 'total' => $this->get_item_total($quantity, $price, $discount, $receiving_quantity)
+ 'receiving_quantity' => $item_info->receiving_quantity,
+ 'receiving_quantity_choices' => $receiving_quantity_choices,
+ 'total' => $this->get_item_total($quantity, $price, $discount, $item_info->receiving_quantity)
)
);
@@ -232,7 +250,7 @@ class Receiving_lib
if($itemalreadyinsale)
{
$items[$updatekey]['quantity'] += $quantity;
- $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount);
+ $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount, $items[$updatekey]['receiving_quantity']);
}
else
{
@@ -245,7 +263,7 @@ class Receiving_lib
return TRUE;
}
- public function edit_item($line, $description, $serialnumber, $quantity, $discount, $price)
+ public function edit_item($line, $description, $serialnumber, $quantity, $discount, $price, $receiving_quantity)
{
$items = $this->get_cart();
if(isset($items[$line]))
@@ -254,9 +272,10 @@ class Receiving_lib
$line['description'] = $description;
$line['serialnumber'] = $serialnumber;
$line['quantity'] = $quantity;
+ $line['receiving_quantity'] = $receiving_quantity;
$line['discount'] = $discount;
$line['price'] = $price;
- $line['total'] = $this->get_item_total($quantity, $price, $discount);
+ $line['total'] = $this->get_item_total($quantity, $price, $discount, $receiving_quantity);
$this->set_cart($items);
}
@@ -330,9 +349,10 @@ class Receiving_lib
$this->clear_reference();
}
- public function get_item_total($quantity, $price, $discount_percentage)
+ public function get_item_total($quantity, $price, $discount_percentage, $receiving_quantity)
{
- $total = bcmul($quantity, $price);
+ $extended_quantity = bcmul($quantity, $receiving_quantity);
+ $total = bcmul($extended_quantity, $price);
$discount_fraction = bcdiv($discount_percentage, 100);
$discount_amount = bcmul($total, $discount_fraction);
@@ -344,7 +364,7 @@ class Receiving_lib
$total = 0;
foreach($this->get_cart() as $item)
{
- $total = bcadd($total, $this->get_item_total(($item['quantity']* $item['receiving_quantity']), $item['price'], $item['discount']));
+ $total = bcadd($total, $this->get_item_total(($item['quantity']), $item['price'], $item['discount'], $item['receiving_quantity']));
}
return $total;
diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php
index 7dfb3fed9..35d033c0c 100644
--- a/application/libraries/Sale_lib.php
+++ b/application/libraries/Sale_lib.php
@@ -827,7 +827,14 @@ class Sale_lib
$total = $this->get_item_total($quantity, $price, $discount);
$discounted_total = $this->get_item_total($quantity, $price, $discount, TRUE);
- //Item already exists and is not serialized, add to quantity
+
+ if($this->CI->config->item('multi_pack_enabled') == '1')
+ {
+ $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
+ }
+
+
+ //Item already exists and is not serialized, add to quantity
if(!$itemalreadyinsale || $item_info->is_serialized)
{
$item = array($insertkey => array(
diff --git a/application/migrations/20180610100000_upgrade_to_3_3_0.php b/application/migrations/20180610100000_upgrade_to_3_3_0.php
new file mode 100644
index 000000000..fda74aa77
--- /dev/null
+++ b/application/migrations/20180610100000_upgrade_to_3_3_0.php
@@ -0,0 +1,20 @@
+
diff --git a/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql b/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql
new file mode 100644
index 000000000..0cc3bd68d
--- /dev/null
+++ b/application/migrations/sqlscripts/3.2.1_to_3.3.0.sql
@@ -0,0 +1,15 @@
+--
+-- Add support for Multi-Package Items
+--
+
+INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
+('multi_pack_enabled', '0');
+
+ALTER TABLE `ospos_items`
+ ADD COLUMN `qty_per_pack` decimal(15,3) NOT NULL DEFAULT 1,
+ ADD COLUMN `pack_name` varchar(8) DEFAULT 'Each',
+ ADD COLUMN `low_sell_item_id` int(10) DEFAULT 0;
+
+UPDATE `ospos_items`
+ SET `low_sell_item_id` = `item_id`
+ WHERE `low_sell_item_id` = 0;
diff --git a/application/models/Item.php b/application/models/Item.php
index fcb28c670..758ba2e86 100644
--- a/application/models/Item.php
+++ b/application/models/Item.php
@@ -23,6 +23,8 @@ define('PRICE_OPTION_ALL', 0);
define('PRICE_OPTION_KIT', 1);
define('PRICE_OPTION_KIT_STOCK', 2);
+define('NAME_SEPARATOR', ' | ');
+
/**
* Item class
@@ -109,64 +111,65 @@ class Item extends CI_Model
// get_found_rows case
if($count_only == TRUE)
{
- $this->db->select('COUNT(DISTINCT items.item_id) as count');
+ $this->db->select('COUNT(DISTINCT items.item_id) AS count');
}
else
{
- $this->db->select('items.item_id as 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('MAX(items.pic_filename) as pic_filename');
- $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('items.item_id AS 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('MAX(items.pic_filename) AS pic_filename');
+ $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.pack_name) AS pack_name');
+ $this->db->select('MAX(items.deleted) AS deleted');
+ $this->db->select('MAX(items.custom1) AS custom1');
+ $this->db->select('MAX(items.custom2) AS custom2');
+ $this->db->select('MAX(items.custom3) AS custom3');
+ $this->db->select('MAX(items.custom4) AS custom4');
+ $this->db->select('MAX(items.custom5) AS custom5');
+ $this->db->select('MAX(items.custom6) AS custom6');
+ $this->db->select('MAX(items.custom7) AS custom7');
+ $this->db->select('MAX(items.custom8) AS custom8');
+ $this->db->select('MAX(items.custom9) AS custom9');
+ $this->db->select('MAX(items.custom10) AS custom10');
- $this->db->select('MAX(suppliers.person_id) as person_id');
- $this->db->select('MAX(suppliers.company_name) as company_name');
- $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(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');
+ $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->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->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');
+ $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->join('item_quantities AS item_quantities', 'item_quantities.item_id = items.item_id');
$this->db->where('location_id', $filters['stock_location_id']);
}
@@ -398,6 +401,11 @@ class Item extends CI_Model
if($this->db->insert('items', $item_data))
{
$item_data['item_id'] = $this->db->insert_id();
+ if($item_data['low_sell_item_id'] == -1)
+ {
+ $this->db->where('item_id', $item_data['item_id']);
+ $this->db->update('items', array('low_sell_item_id'=>$item_data['item_id']));
+ }
return TRUE;
}
return FALSE;
@@ -477,7 +485,7 @@ class Item extends CI_Model
function get_search_suggestion_format($seed = NULL)
{
$seed .= ',' . $this->config->item('suggestions_first_column');
-
+
if($this->config->item('suggestions_second_column') !== '')
{
$seed .= ',' . $this->config->item('suggestions_second_column');
@@ -487,37 +495,77 @@ class Item extends CI_Model
{
$seed .= ',' . $this->config->item('suggestions_third_column');
}
-
+
return $seed;
}
function get_search_suggestion_label($result_row)
{
+ $label = '';
$label1 = $this->config->item('suggestions_first_column');
$label2 = $this->config->item('suggestions_second_column');
$label3 = $this->config->item('suggestions_third_column');
- $label = $result_row->$label1;
-
- if($label2 !== '')
+ // If multi_pack enabled then if "name" is part of the search suggestions then append pack
+ if($this->config->item('multi_pack_enabled') == '1')
{
- $label .= ' | '. $result_row->$label2;
+ $this->append_label($label, $label1, $result_row);
+ $this->append_label($label, $label2, $result_row);
+ $this->append_label($label, $label3, $result_row);
}
-
- if($label3 !== '')
+ else
{
- $label .= ' | '. $result_row->$label3;
- }
-
+ $label = $result_row->$label1;
+
+ if($label2 !== '')
+ {
+ $label .= NAME_SEPARATOR . $result_row->$label2;
+ }
+
+ if($label3 !== '')
+ {
+ $label .= NAME_SEPARATOR . $result_row->$label3;
+ }
+ }
+
return $label;
- }
+ }
+
+ private function append_label(&$label, $item_field_name, $item_info)
+ {
+ if($item_field_name !== '')
+ {
+ if($label == "")
+ {
+ if($item_field_name == 'name')
+ {
+ $label .= implode(NAME_SEPARATOR, array($item_info->name, $item_info->pack_name));
+ }
+ else
+ {
+ $label .= $item_info->$item_field_name;
+ }
+ }
+ else
+ {
+ if($item_field_name == 'name')
+ {
+ $label .= implode(NAME_SEPARATOR, array("", $item_info->name, $item_info->pack_name));
+ }
+ else
+ {
+ $label .= NAME_SEPARATOR . $item_info->$item_field_name;
+ }
+ }
+ }
+ }
public function get_search_suggestions($search, $filters = array('is_deleted' => FALSE, 'search_custom' => FALSE), $unique = FALSE, $limit = 25)
{
$suggestions = array();
$non_kit = array(ITEM, ITEM_AMOUNT_ENTRY);
- $this->db->select($this->get_search_suggestion_format('item_id, name'));
+ $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -528,7 +576,7 @@ class Item extends CI_Model
$suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
}
- $this->db->select($this->get_search_suggestion_format('item_id, item_number'));
+ $this->db->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -569,7 +617,7 @@ class Item extends CI_Model
}
//Search by description
- $this->db->select($this->get_search_suggestion_format('item_id, name, description'));
+ $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -624,7 +672,7 @@ class Item extends CI_Model
$suggestions = array();
$non_kit = array(ITEM, ITEM_AMOUNT_ENTRY);
- $this->db->select($this->get_search_suggestion_format('item_id, name'));
+ $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -636,7 +684,7 @@ class Item extends CI_Model
$suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
}
- $this->db->select($this->get_search_suggestion_format('item_id, item_number'));
+ $this->db->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -678,7 +726,7 @@ class Item extends CI_Model
}
//Search by description
- $this->db->select($this->get_search_suggestion_format('item_id, name, description'));
+ $this->db->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
$this->db->from('items');
$this->db->where('deleted', $filters['is_deleted']);
$this->db->where_in('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
@@ -834,6 +882,24 @@ class Item extends CI_Model
return $suggestions;
}
+ public function get_low_sell_suggestions($search)
+ {
+ $suggestions = array();
+
+ $this->db->select($this->get_search_suggestion_format('item_id, pack_name'));
+ $this->db->from('items');
+ $this->db->where('deleted', '0');
+ $this->db->where("stock_type = '0'"); // stocked items only
+ $this->db->like('name', $search);
+ $this->db->order_by('name', 'asc');
+ foreach($this->db->get()->result() as $row)
+ {
+ $suggestions[] = array('value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row));
+ }
+
+ return $suggestions;
+ }
+
public function get_category_suggestions($search)
{
$suggestions = array();
@@ -950,5 +1016,31 @@ class Item extends CI_Model
$this->db->update('items', array('description'=>$item_description));
}
+ /**
+ * Determine the item name to use taking into consideration that
+ * for a multipack environment then the item name should have the
+ * pack appended to it
+ */
+ function get_item_name($as_name = NULL)
+ {
+ if($as_name == NULL)
+ {
+ $as_name = '';
+ }
+ else
+ {
+ $as_name = ' AS ' . $as_name;
+ }
+
+ if($this->config->item('multi_pack_enabled') == '1')
+ {
+ $item_name = "concat(items.name,'" . NAME_SEPARATOR . '\', items.pack_name)' . $as_name;
+ }
+ else
+ {
+ $item_name = 'items.name' . $as_name;
+ }
+ return $item_name;
+ }
}
?>
diff --git a/application/models/Sale.php b/application/models/Sale.php
index 9c1cba3ce..a82e9be69 100644
--- a/application/models/Sale.php
+++ b/application/models/Sale.php
@@ -174,7 +174,7 @@ class Sale extends CI_Model
SELECT sales_items_taxes.sale_id AS sale_id,
sales_items_taxes.item_id AS item_id,
sales_items_taxes.line AS line,
- SUM(sales_items_taxes.item_tax_amount) as tax
+ SUM(sales_items_taxes.item_tax_amount) AS tax
FROM ' . $this->db->dbprefix('sales_items_taxes') . ' AS sales_items_taxes
INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales
ON sales.sale_id = sales_items_taxes.sale_id
@@ -188,7 +188,7 @@ class Sale extends CI_Model
// get_found_rows case
if($count_only == TRUE)
{
- $this->db->select('COUNT(DISTINCT sales.sale_id) as count');
+ $this->db->select('COUNT(DISTINCT sales.sale_id) AS count');
}
else
{
@@ -930,12 +930,12 @@ class Sale extends CI_Model
discount_percent,
item_location,
print_option,
- items.name as name,
+ ' . $this->Item->get_item_name('name') . ',
category,
item_type,
stock_type');
- $this->db->from('sales_items as sales_items');
- $this->db->join('items as items', 'sales_items.item_id = items.item_id');
+ $this->db->from('sales_items AS sales_items');
+ $this->db->join('items AS items', 'sales_items.item_id = items.item_id');
$this->db->where('sales_items.sale_id', $sale_id);
// Entry sequence (this will render kits in the expected sequence)
@@ -949,6 +949,7 @@ class Sale extends CI_Model
$this->db->order_by('stock_type', 'desc');
$this->db->order_by('sales_items.description', 'asc');
$this->db->order_by('items.name', 'asc');
+ $this->db->order_by('items.qty_per_pack', 'asc');
}
// Group by Item Category
elseif($this->config->item('line_sequence') == '2')
@@ -956,6 +957,7 @@ class Sale extends CI_Model
$this->db->order_by('category', 'asc');
$this->db->order_by('sales_items.description', 'asc');
$this->db->order_by('items.name', 'asc');
+ $this->db->order_by('items.qty_per_pack', 'asc');
}
// Group by entry sequence in descending sequence (the Standard)
else
@@ -1133,7 +1135,7 @@ class Sale extends CI_Model
SELECT sales_items_taxes.sale_id AS sale_id,
sales_items_taxes.item_id AS item_id,
sales_items_taxes.line AS line,
- SUM(sales_items_taxes.item_tax_amount) as tax
+ SUM(sales_items_taxes.item_tax_amount) AS tax
FROM ' . $this->db->dbprefix('sales_items_taxes') . ' AS sales_items_taxes
INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales
ON sales.sale_id = sales_items_taxes.sale_id
@@ -1181,7 +1183,7 @@ class Sale extends CI_Model
MAX(sales.employee_id) AS employee_id,
MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
items.item_id AS item_id,
- MAX(items.name) AS name,
+ MAX(' . $this->Item->get_item_name() . ') AS name,
MAX(items.item_number) AS item_number,
MAX(items.category) AS category,
MAX(items.supplier_id) AS supplier_id,
diff --git a/application/models/reports/Inventory_low.php b/application/models/reports/Inventory_low.php
index 2cca4519f..35842f700 100644
--- a/application/models/reports/Inventory_low.php
+++ b/application/models/reports/Inventory_low.php
@@ -16,17 +16,20 @@ class Inventory_low extends Report
public function getData(array $inputs)
{
- $this->db->select('items.name, items.item_number, item_quantities.quantity, items.reorder_level, stock_locations.location_name');
- $this->db->from('items');
- $this->db->join('item_quantities', 'items.item_id = item_quantities.item_id');
- $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('items.stock_type', 0);
- $this->db->where('item_quantities.quantity <= items.reorder_level');
- $this->db->order_by('items.name');
+ $query = $this->db->query("SELECT " . $this->Item->get_item_name('name') . ",
+ items.item_number,
+ item_quantities.quantity,
+ items.reorder_level,
+ stock_locations.location_name
+ FROM " . $this->db->dbprefix('items') . " AS items
+ JOIN " . $this->db->dbprefix('item_quantities') . " AS item_quantities ON items.item_id = item_quantities.item_id
+ JOIN " . $this->db->dbprefix('stock_locations') . " AS stock_locations ON item_quantities.location_id = stock_locations.location_id
+ WHERE items.deleted = 0
+ AND items.stock_type = 0
+ AND item_quantities.quantity <= items.reorder_level
+ ORDER BY items.name");
- return $this->db->get()->result_array();
+ return $query->result_array();
}
public function getSummaryData(array $inputs)
diff --git a/application/models/reports/Inventory_summary.php b/application/models/reports/Inventory_summary.php
index 51c4e2004..20215cd68 100644
--- a/application/models/reports/Inventory_summary.php
+++ b/application/models/reports/Inventory_summary.php
@@ -9,6 +9,7 @@ class Inventory_summary extends Report
return array(array('item_name' => $this->lang->line('reports_item_name')),
array('item_number' => $this->lang->line('reports_item_number')),
array('quantity' => $this->lang->line('reports_quantity')),
+ array('low_sell_quantity' => $this->lang->line('reports_low_sell_quantity')),
array('reorder_level' => $this->lang->line('reports_reorder_level')),
array('location_name' => $this->lang->line('reports_stock_location')),
array('cost_price' => $this->lang->line('reports_cost_price'), 'sorter' => 'number_sorter'),
@@ -18,7 +19,7 @@ class Inventory_summary extends Report
public function getData(array $inputs)
{
- $this->db->select('items.name, items.item_number, item_quantities.quantity, items.reorder_level, stock_locations.location_name, items.cost_price, items.unit_price, (items.cost_price * item_quantities.quantity) AS sub_total_value');
+ $this->db->select($this->Item->get_item_name('item_name') . ', items.item_number, item_quantities.quantity, item_quantities.quantity, (item_quantities.quantity * items.qty_per_pack) as low_sell_quantity, items.reorder_level, stock_locations.location_name, items.cost_price, items.unit_price, (items.cost_price * item_quantities.quantity) AS sub_total_value');
$this->db->from('items AS items');
$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');
@@ -42,6 +43,7 @@ class Inventory_summary extends Report
}
$this->db->order_by('items.name');
+ $this->db->order_by('items.qty_per_pack');
return $this->db->get()->result_array();
}
@@ -54,12 +56,13 @@ class Inventory_summary extends Report
*/
public function getSummaryData(array $inputs)
{
- $return = array('total_inventory_value' => 0, 'total_quantity' => 0, 'total_retail' => 0);
+ $return = array('total_inventory_value' => 0, 'total_quantity' => 0, 'total_low_sell_quantity' => 0, 'total_retail' => 0);
foreach($inputs as $input)
{
$return['total_inventory_value'] += $input['sub_total_value'];
$return['total_quantity'] += $input['quantity'];
+ $return['total_low_sell_quantity'] += $input['low_sell_quantity'];
$return['total_retail'] += $input['unit_price'] * $input['quantity'];
}
diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php
index cf910dfaf..0a470281c 100644
--- a/application/views/configs/general_config.php
+++ b/application/views/configs/general_config.php
@@ -160,7 +160,7 @@
'name' => $this->lang->line('items_name'),
'item_number' => $this->lang->line('items_number_information'),
'unit_price' => $this->lang->line('items_unit_price')
- ),
+ ),
$this->config->item('suggestions_third_column'), array('class' => 'form-control input-sm')); ?>
@@ -213,6 +213,17 @@
+
+