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 @@ +
+ lang->line('config_multi_pack_enabled'), 'multi_pack_enabled', array('class' => 'control-label col-xs-2')); ?> +
+ 'multi_pack_enabled', + 'id' => 'multi_pack_enabled', + 'value' => 'multi_pack_enabled', + 'checked' => $this->config->item('multi_pack_enabled'))); ?> +
+
+
lang->line('config_custom1'), 'config_custom1', array('class' => 'control-label col-xs-2')); ?>
diff --git a/application/views/items/form.php b/application/views/items/form.php index a78aca067..f89c7ca55 100644 --- a/application/views/items/form.php +++ b/application/views/items/form.php @@ -93,7 +93,8 @@ ); ?> lang->line('items_kit'); ?> config->item('derive_sale_quantity') == '1') { + if($this->config->item('derive_sale_quantity') == '1') + { ?>
+ config->item('multi_pack_enabled') == '1') + { + ?> +
+ lang->line('items_qty_per_pack'), 'qty_per_pack', array('class'=>'control-label col-xs-3')); ?> +
+ 'qty_per_pack', + 'id'=>'qty_per_pack', + 'class'=>'form-control input-sm', + 'value'=>isset($item_info->item_id) ? to_quantity_decimals($item_info->qty_per_pack) : to_quantity_decimals(0)) + );?> +
+
+
+ lang->line('items_pack_name'), 'name', array('class'=>'control-label col-xs-3')); ?> +
+ 'pack_name', + 'id'=>'pack_name', + 'class'=>'form-control input-sm', + 'value'=>$item_info->pack_name) + );?> +
+
+
+ lang->line('items_low_sell_item'), 'low_sell_item_name', array('class'=>'control-label col-xs-3')); ?> +
+
+ 'low_sell_item_name', + 'id'=>'low_sell_item_name', + 'class'=>'form-control input-sm', + 'size'=>'50', + 'value'=>$selected_low_sell_item) + ); ?> + +
+
+
+ +
lang->line('items_is_deleted'), 'is_deleted', array('class'=>'control-label col-xs-3')); ?>
@@ -381,6 +427,22 @@ $(document).ready(function() stay_open = false; }); + var fill_value = function(event, ui) { + event.preventDefault(); + $("input[name='low_sell_item_id']").val(ui.item.value); + $("input[name='low_sell_item_name']").val(ui.item.label); + }; + + $("#low_sell_item_name").autocomplete({ + source: '', + minChars: 0, + delay: 15, + cacheLength: 1, + appendTo: '.modal-content', + select: fill_value, + focus: fill_value + }); + var no_op = function(event, data, formatted){}; $('#category').autocomplete({ source: "", diff --git a/application/views/receivings/receipt.php b/application/views/receivings/receipt.php index 378fa7594..0d3d4bfde 100644 --- a/application/views/receivings/receipt.php +++ b/application/views/receivings/receipt.php @@ -82,7 +82,7 @@    x -
+
diff --git a/application/views/receivings/receiving.php b/application/views/receivings/receiving.php index fd9395bce..ae131f6bf 100644 --- a/application/views/receivings/receiving.php +++ b/application/views/receivings/receiving.php @@ -103,10 +103,10 @@ if (isset($success)) lang->line('common_delete'); ?> - lang->line('receivings_item_name'); ?> + lang->line('receivings_item_name'); ?> lang->line('receivings_cost'); ?> lang->line('receivings_quantity'); ?> - + lang->line('receivings_ship_pack'); ?> lang->line('receivings_discount'); ?> lang->line('receivings_total'); ?> lang->line('receivings_update'); ?> @@ -157,21 +157,8 @@ if (isset($success)) ?> 'quantity', 'class'=>'form-control input-sm', 'value'=>to_quantity_decimals($item['quantity']))); ?> - 1) - { - ?> - - - - - + 'form-control input-sm'));?> + lang->line('sales_no_description'); + echo "".$this->lang->line('sales_no_description').""; echo form_hidden('description',''); } } @@ -351,42 +338,41 @@ if (isset($success))
'comment', 'id'=>'comment', 'class'=>'form-control input-sm', 'value'=>$comment, 'rows'=>'4'));?> - - - - - - - - +
+
lang->line('receivings_print_after_sale'); ?> - 'recv_print_after_sale', 'id'=>'recv_print_after_sale', 'class'=>'checkbox', 'value'=>1, 'checked'=>$print_after_sale)); ?> -
- + - - - - - - - - - - -
lang->line('receivings_reference');?>lang->line('receivings_print_after_sale'); ?> - 'recv_reference', 'id'=>'recv_reference', 'class'=>'form-control input-sm', 'value'=>$reference, 'size'=>5));?> + 'recv_print_after_sale', 'id'=>'recv_print_after_sale', 'class'=>'checkbox', 'value'=>1, 'checked'=>$print_after_sale)); ?>
lang->line('sales_payment'); ?> - 'payment_types', 'class'=>'selectpicker show-menu-arrow', 'data-style'=>'btn-default btn-sm', 'data-width'=>'auto')); ?> -
lang->line('sales_amount_tendered'); ?> - 'amount_tendered', 'value'=>'', 'class'=>'form-control input-sm', 'size'=>'5')); ?> -
+ + + lang->line('receivings_reference');?> + + 'recv_reference', 'id'=>'recv_reference', 'class'=>'form-control input-sm', 'value'=>$reference, 'size'=>5));?> + + + + + lang->line('sales_payment'); ?> + + 'payment_types', 'class'=>'selectpicker show-menu-arrow', 'data-style'=>'btn-default btn-sm', 'data-width'=>'auto')); ?> + + + + lang->line('sales_amount_tendered'); ?> + + 'amount_tendered', 'value'=>'', 'class'=>'form-control input-sm', 'size'=>'5')); ?> + + + +
 lang->line('receivings_cancel_receiving') ?>
@@ -517,7 +503,7 @@ $(document).ready(function() } } - $('[name="price"],[name="quantity"],[name="discount"],[name="description"],[name="serialnumber"]').change(function() { + $('[name="price"],[name="quantity"],[name="receiving_quantity"],[name="discount"],[name="description"],[name="serialnumber"]').change(function() { $(this).parents("tr").prevAll("form:first").submit() }); diff --git a/application/views/sales/register.php b/application/views/sales/register.php index 7cde592a1..26852456a 100644 --- a/application/views/sales/register.php +++ b/application/views/sales/register.php @@ -133,6 +133,7 @@ if(isset($success)) foreach(array_reverse($cart, TRUE) as $line=>$item) { ?> + 'form-horizontal', 'id'=>'cart_'.$line)); ?> diff --git a/database/tables.sql b/database/tables.sql index 51bff19c3..6a63bfbbc 100644 --- a/database/tables.sql +++ b/database/tables.sql @@ -118,7 +118,8 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('suggestions_second_column', ''), ('suggestions_third_column', ''), ('allow_duplicate_barcodes', '0'), -('quote_default_comments', 'This is a default quote comment'); +('quote_default_comments', 'This is a default quote comment'), +('multi_pack_enabled', '0'); -- -------------------------------------------------------- @@ -243,6 +244,9 @@ CREATE TABLE `ospos_items` ( `stock_type` TINYINT(2) NOT NULL DEFAULT 0, `item_type` TINYINT(2) NOT NULL DEFAULT 0, `tax_category_id` int(10) NOT NULL DEFAULT 1, + `qty_per_pack` decimal(15,3) NOT NULL DEFAULT 1, + `pack_name` varchar(8) DEFAULT '', + `low_sell_item_id` int(10) DEFAULT 0, `deleted` int(1) NOT NULL DEFAULT '0', `custom1` VARCHAR(255) DEFAULT NULL, `custom2` VARCHAR(255) DEFAULT NULL,