Added foreign/alias item codes and sales kits support.
authorJanusz Dobrowolski <janusz@frontaccounting.eu>
Mon, 24 Nov 2008 20:16:01 +0000 (20:16 +0000)
committerJanusz Dobrowolski <janusz@frontaccounting.eu>
Mon, 24 Nov 2008 20:16:01 +0000 (20:16 +0000)
13 files changed:
CHANGELOG.txt
applications/inventory.php
includes/ui/ui_lists.inc
inventory/includes/db/items_category_db.inc
inventory/includes/db/items_codes_db.inc [new file with mode: 0644]
inventory/includes/db/items_db.inc
inventory/includes/inventory_db.inc
inventory/manage/item_codes.php [new file with mode: 0644]
inventory/manage/items.php
inventory/manage/sales_kits.php [new file with mode: 0644]
inventory/prices.php
sales/includes/sales_db.inc
sales/includes/ui/sales_order_ui.inc

index 3c3fb00e948bec781ec160cabaa14bd52759615f..60ab21c47610b6001b693d9b783cfb42d9ff38a5 100644 (file)
@@ -19,6 +19,38 @@ Legend:
 ! -> Note
 $ -> Affected files
 
+24-Nov-2008 Janusz Dobrowolski
++ Added alias/foreign item codes and sales kits support.
+$ /applications/inventory.php
+  /includes/ui/ui_lists.inc
+  /inventory/prices.php
+  /inventory/includes/inventory_db.inc
+  /inventory/includes/db/items_category_db.inc
+  /inventory/includes/db/items_db.inc
+  /inventory/manage/items.php
+  /inventory/includes/db/items_codes_db.inc (new)
+  /inventory/manage/item_codes.php (new)
+  /inventory/manage/sales_kits.php (new)
+  /sales/includes/sales_db.inc
+  /sales/includes/ui/sales_order_ui.inc
+! Added decimals to get_item_edit_info() return (sql usage optimization).
+$ /includes/db/inventory_db.inc
+  /inventory/includes/item_adjustments_ui.inc
+  /inventory/includes/stock_transfers_ui.inc
+  /manufacturing/includes/work_order_issue_ui.inc
+  /purchasing/includes/ui/po_ui.inc
+  /sales/includes/ui/sales_credit_ui.inc
+! Added postlabel update in amount_cells_ex() and derivative helpers, fixed qty_cell $dec handling
+$ /includes/ui/ui_input.inc
+# Fixed _vd() debug function for use also in ajax mode.
+$ /includes/ui/ui_view.inc
+! Changed foreign column name to avoid mysql syntax problems, added category.
+$ /sql/alter2.1.sql
+  /sql/alter2.1.php
+# Fixed unconsistent units of measure.
+$ /sql/en_US-demo.sql
+  /sql/en_US-new.sql
+
 24-Nov-2008 Joe Hunt
 ! Preparing for graphic Links
 $ config.php
index 05180e78699f1b4a05a868d08c3e53935ff76b92..a268c60d86ab3fff70b3844ad7c464e83dee9760 100644 (file)
@@ -19,6 +19,8 @@
 
                        $this->add_module(_("Maintenance"));
                        $this->add_lapp_function(2, _("&Items"),"inventory/manage/items.php?");
+                       $this->add_lapp_function(2, _("&Foreign Item Codes"),"inventory/manage/item_codes.php?");
+                       $this->add_lapp_function(2, _("Sales &Kits"),"inventory/manage/sales_kits.php?");
                        $this->add_lapp_function(2, _("Item &Categories"),"inventory/manage/item_categories.php?");
                        $this->add_lapp_function(2, _("Inventory &Locations"),"inventory/manage/locations.php?");
                        $this->add_rapp_function(2, _("Inventory &Movement Types"),"inventory/manage/movement_types.php?");
index 9c8534731fe768ba09780afb8fa404bb7ddf966a..e2fc6a10cb91505a1cf5012bc2c91cb4303eaa41 100644 (file)
@@ -652,6 +652,73 @@ function stock_items_list_row($label, $name, $selected_id=null, $all_option=fals
        return $str;
 }
 */
+//---------------------------------------------------------------------------------------------------
+//
+// Select item via foreign code.
+//
+function sales_items_list($name, $selected_id=null, $all_option=false, 
+       $submit_on_change=false, $type='', $opts=array())
+{
+       global $all_items;
+       // all sales codes
+       $sql = "SELECT i.item_code, i.description, c.description, count(*)>1 as kit
+                       FROM
+                       ".TB_PREF."item_codes i
+                       LEFT JOIN
+                       ".TB_PREF."stock_category c
+                       ON i.category_id=c.category_id";
+
+       if ($type == 'local')   { // exclude foreign codes
+               $sql .= " WHERE NOT i.is_foreign"; 
+       } elseif ($type == 'kits') { // sales kits
+               $sql .= " WHERE NOT i.is_foreign 
+                       AND NOT i.item_code=i.stock_id";
+       }
+                               
+       $sql .= " GROUP BY i.item_code";
+
+       return combo_input($name, $selected_id, $sql, 'i.item_code', 'c.description',
+       array_merge(
+         array(
+               'format' => '_format_stock_items',
+               'spec_option' => $all_option===true ?  _("All Items") : $all_option,
+               'spec_id' => $all_items,
+               'search_box' => true,
+               'search' => array("i.item_code", "c.description","s.description"),
+               'search_submit' => get_company_pref('no_item_list')!=0,
+               'size'=>15,
+               'select_submit'=> $submit_on_change,
+               'order' => 'i.item_code'
+         ), $opts) );
+}
+
+function sales_items_list_cells($label, $name, $selected_id=null, $all_option=false, $submit_on_change=false)
+{
+       if ($label != null)
+               echo "<td>$label</td>\n";
+       $str = sales_items_list($name, $selected_id, $all_option, $submit_on_change,
+               '', array('cells'=>true));
+       return $str;
+}
+
+function sales_kits_list($name, $selected_id=null, $all_option=false, $submit_on_change=false)
+{
+       $str = sales_items_list($name, $selected_id, $all_option, $submit_on_change,
+               'kits', array('cells'=>false));
+       return $str;
+}
+
+function sales_local_items_list_row($label, $name, $selected_id=null, $all_option=false, $submit_on_change=false)
+{
+       echo "<tr>";
+       if ($label != null)
+               echo "<td>$label</td>\n";
+       echo "<td>";
+       $str = sales_items_list($name, $selected_id, $all_option, $submit_on_change,
+               'local', array('cells'=>false));
+       echo "</td></tr>";
+       return $str;
+}
 //------------------------------------------------------------------------------------
 
 function base_stock_items_list($where, $name, $selected_id=null,
index 8883b5f2fdd13299904b37864e4d9d4bc084d1c5..87819e0dabb50bc8c5309f2fc82203fb55259692 100644 (file)
@@ -44,5 +44,4 @@ function get_category_name($id)
        return $row[0];
 }
 
-
 ?>
\ No newline at end of file
diff --git a/inventory/includes/db/items_codes_db.inc b/inventory/includes/db/items_codes_db.inc
new file mode 100644 (file)
index 0000000..a5946c6
--- /dev/null
@@ -0,0 +1,152 @@
+<?php
+/*
+       item_codes table is used to store both multiply foreign codes and 
+       sale kits definition.
+*/
+function update_item_code($id, $item_code, $stock_id, $description, $category, $qty, $foreign=0)
+{
+       $sql = "UPDATE ".TB_PREF."item_codes SET
+               item_code = ".db_escape($item_code).",
+               stock_id = ".db_escape($stock_id).",
+               description = ".db_escape($description).",
+               category_id = $category,
+               quantity = ".db_escape($qty).",
+               is_foreign = ".db_escape($foreign)."
+               WHERE ";
+                       
+       if ($id == -1) // update with unknown $id i.e. from items table editor
+               "item_code = ".db_escape($item_code)
+               ." AND stock_id = ".db_escape($stock_id);
+       else
+               $sql .= "id = $id";
+
+       db_query($sql,"an item code could not be updated");
+}
+
+function add_item_code($item_code, $stock_id, $description, $category, $qty, $foreign=0)
+{
+       $sql = "INSERT INTO ".TB_PREF."item_codes
+                       (item_code, stock_id, description, category_id, quantity, is_foreign) 
+                       VALUES( ".db_escape($item_code).",".db_escape($stock_id).",
+                       ".db_escape($description).",$category,".db_escape($qty).",".$foreign.")";
+
+       db_query($sql,"an item code could not be added");
+}
+
+function delete_item_code($id)
+{
+       $sql="DELETE FROM ".TB_PREF."item_codes WHERE id=$id";
+       db_query($sql,"an item code could not be deleted");
+}
+
+function get_item_code($id)
+{
+       $sql="SELECT * FROM ".TB_PREF."item_codes WHERE id='$id'";
+
+       $result = db_query($sql,"item code could not be retrieved");
+
+       return db_fetch($result);
+}
+
+function get_all_item_codes($stock_id, $foreign=1)
+{
+       $sql="SELECT i.*, c.description as cat_name FROM "
+               .TB_PREF."item_codes as i,"
+               .TB_PREF."stock_category as c
+               WHERE stock_id='$stock_id'
+               AND i.category_id=c.category_id
+               AND i.is_foreign=$foreign";
+
+       $result = db_query($sql,"all item codes could not be retrieved");
+
+       return $result;
+}
+
+function delete_item_kit($item_code)
+{
+       $sql="DELETE FROM ".TB_PREF."item_codes WHERE item_code='$item_code'";
+       db_query($sql,"an item kit could not be deleted");
+}
+
+function get_item_kit($item_code)
+{
+       $sql="SELECT DISTINCT kit.*, item.units, comp.description as comp_name 
+               FROM "
+               .TB_PREF."item_codes kit,"
+               .TB_PREF."item_codes comp
+               LEFT JOIN "
+               .TB_PREF."stock_master item
+               ON 
+                       item.stock_id=comp.item_code
+               WHERE
+                       kit.stock_id=comp.item_code
+                       AND kit.item_code='$item_code'";
+
+       $result = db_query($sql,"item kit could not be retrieved");
+
+       return $result;
+}
+
+function get_item_code_dflts($stock_id)
+{
+       $sql = "SELECT units, decimals, description, category_id
+               FROM ".TB_PREF."stock_master,".TB_PREF."item_units
+               WHERE stock_id='$stock_id'";
+
+       $result = db_query($sql,"item code defaults could not be retrieved");
+       return db_fetch($result);
+}
+//
+//     Check if kit contains given item, optionally recursive.
+//
+function check_item_in_kit($old_id, $kit_code, $item_code, $recurse=false)
+{
+       $result = get_item_kit($kit_code);
+       if ($result != 0)
+       {
+               while ($myrow = db_fetch($result))
+               {
+                       if ($myrow['id'] == $old_id) 
+                               continue;
+                               
+                       if ($myrow['stock_id'] == $item_code)
+                       {
+                               return 1;
+                       }
+
+                       if ($recurse && $myrow['item_code'] != $myrow['stock_id']
+                               && check_item_in_kit($old_id, $item_code, $myrow['stock_id'], true))
+                       {
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+function get_kit_props($kit_code)
+{
+       $sql = "SELECT description, category_id FROM ".TB_PREF."item_codes "
+               . " WHERE item_code='$kit_code'";
+       $res = db_query($sql, "kit name query failed");
+       return db_fetch($res);
+}
+
+function update_kit_props($kit_code, $name, $category)
+{
+       $sql = "UPDATE ".TB_PREF."item_codes SET description="
+               . db_escape($name).",category_id=".db_escape($category)         
+               . " WHERE item_code='$kit_code'";
+       db_query($sql, "kit name update failed");
+}
+
+function get_where_used($item_code)
+{
+       $sql = "SELECT item_code, description FROM "
+               .TB_PREF."item_codes "
+               . " WHERE stock_id='$item_code'
+                       AND item_
+                       code!='$item_code'";
+       return db_query($sql, "where used query failed");
+}
+?>
\ No newline at end of file
index f9f60a47b37e9d7617203712767edc908d7230c1..7a6bd4ff48bf8d15c2451467fd71a73169353f76 100644 (file)
@@ -18,6 +18,8 @@ function update_item($stock_id, $description, $long_description, $category_id, $
                WHERE stock_id='$stock_id'";
 
        db_query($sql, "The item could not be updated");
+
+       update_item_code(-1, $stock_id, $stock_id, $description, 1, 0);
 }
 
 function add_item($stock_id, $description, $long_description, $category_id, $tax_type_id, $units, $mb_flag,
@@ -38,6 +40,8 @@ function add_item($stock_id, $description, $long_description, $category_id, $tax
                SELECT ".TB_PREF."locations.loc_code, '$stock_id' FROM ".TB_PREF."locations";
 
        db_query($sql, "The item locstock could not be added");
+
+       add_item_code($stock_id, $stock_id, $description, 1, 0);
 }
 
 function delete_item($stock_id)
@@ -60,6 +64,8 @@ function delete_item($stock_id)
        /*and cascade delete the bill of material if any */
        $sql = "DELETE FROM ".TB_PREF."bom WHERE parent='$stock_id'";
        db_query($sql, "could not delete stock item bom");
+
+       delete_item_kit($stock_id);
 }
 
 function get_item($stock_id)
index 1faf253f96165858080ba571c34a5b4aff0e33e2..803742937915fd981606d814e604f462646905a5 100644 (file)
@@ -7,6 +7,7 @@ include_once($path_to_root . "/includes/manufacturing.inc");
 include_once($path_to_root . "/inventory/includes/db/items_category_db.inc");
 include_once($path_to_root . "/inventory/includes/db/items_trans_db.inc");
 include_once($path_to_root . "/inventory/includes/db/items_prices_db.inc");
+include_once($path_to_root . "/inventory/includes/db/items_codes_db.inc");
 include_once($path_to_root . "/inventory/includes/db/items_db.inc");
 include_once($path_to_root . "/inventory/includes/db/items_locations_db.inc");
 include_once($path_to_root . "/inventory/includes/db/movement_types_db.inc");
diff --git a/inventory/manage/item_codes.php b/inventory/manage/item_codes.php
new file mode 100644 (file)
index 0000000..2e4b727
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+$page_security = 11;
+$path_to_root="../..";
+include_once($path_to_root . "/includes/session.inc");
+
+page(_("Foreign Item Codes"));
+
+include_once($path_to_root . "/includes/date_functions.inc");
+include_once($path_to_root . "/includes/ui.inc");
+include_once($path_to_root . "/includes/manufacturing.inc");
+include_once($path_to_root . "/includes/data_checks.inc");
+
+check_db_has_purchasable_items(_("There are no inventory items defined in the system."));
+
+simple_page_mode(true);
+//--------------------------------------------------------------------------------------------------
+
+if ($Mode=='ADD_ITEM' || $Mode=='UPDATE_ITEM')
+{
+
+       $input_error = 0;
+       if ($_POST['stock_id'] == "" || !isset($_POST['stock_id']))
+       {
+       $input_error = 1;
+       display_error( _("There is no item selected."));
+               set_focus('stock_id');
+       }
+       elseif (!check_num('quantity', 0))
+       {
+       $input_error = 1;
+       display_error( _("The price entered was not numeric."));
+               set_focus('quantity');
+       }
+       elseif ($_POST['description'] == '')
+       {
+       $input_error = 1;
+       display_error( _("Item code description cannot be empty."));
+               set_focus('description');
+       }
+       elseif($selected_id == -1)
+       {
+               $kit = get_item_kit($_POST['item_code']);
+       if (db_num_rows($kit)) {
+                       $input_error = 1;
+               display_error( _("This item code is already assigned to stock item or sale kit."));
+                       set_focus('item_code');
+               }
+       }
+       
+       if ($input_error == 0)
+       {
+       if ($Mode == 'ADD_ITEM') 
+               {
+                       add_item_code($_POST['item_code'], $_POST['stock_id'],
+                               $_POST['description'], $_POST['category_id'], $_POST['quantity'], 1); 
+
+               display_notification(_("New item code has been added."));
+               } else
+               {
+                       update_item_code($selected_id, $_POST['item_code'], $_POST['stock_id'],
+                               $_POST['description'], $_POST['category_id'], $_POST['quantity'], 1); 
+
+               display_notification(_("Item code has been updated."));
+               }
+               $Mode = 'RESET';
+       }
+}
+
+//--------------------------------------------------------------------------------------------------
+
+if ($Mode == 'Delete')
+{
+       delete_item_code($selected_id);
+       
+       display_notification(_("The purchasing data item has been sucessfully deleted."));
+       $Mode = 'RESET';
+}
+
+if ($Mode == 'RESET')
+{
+       $selected_id = -1;
+       unset($_POST);
+}
+
+if (list_updated('stock_id')) 
+       $Ajax->activate('_page_body');
+
+//--------------------------------------------------------------------------------------------------
+
+start_form(false, true);
+
+if (!isset($_POST['stock_id']))
+       $_POST['stock_id'] = get_global_stock_item();
+
+echo "<center>" . _("Item:"). "&nbsp;";
+stock_purchasable_items_list('stock_id', $_POST['stock_id'], false, true);
+
+echo "<hr></center>";
+
+set_global_stock_item($_POST['stock_id']);
+
+$result = get_item_code_dflts($_POST['stock_id']);
+$dec = $result['decimals'];
+$units = $result['units'];
+$dflt_desc = $result['description'];
+$dflt_cat = $result['category_id'];
+
+$result = get_all_item_codes($_POST['stock_id']);
+div_start('code_table');
+       start_table("$table_style width=60%");
+
+       $th = array(_("EAN/UPC Code"), _("Quantity"), _("Units"), 
+               _("Description"),_("Category"), "", "");
+
+        table_header($th);
+
+        $k = $j = 0; //row colour counter
+
+        while ($myrow = db_fetch($result))
+        {
+                       alt_table_row_color($k);
+
+            label_cell($myrow["item_code"]);
+            qty_cell($myrow["quantity"], $dec);
+            label_cell($units);
+            label_cell($myrow["description"]);
+            label_cell($myrow["cat_name"]);
+                       edit_button_cell("Edit".$myrow['id'], _("Edit"));
+                       edit_button_cell("Delete".$myrow['id'], _("Delete"));
+            end_row();
+
+            $j++;
+            If ($j == 12)
+            {
+               $j = 1;
+                       table_header($th);
+            } //end of page full new headings
+        } //end of while loop
+
+       end_table();
+div_end();
+
+//-----------------------------------------------------------------------------------------------
+
+if ($Mode =='Edit')
+{
+       $myrow = get_item_code($selected_id);
+       $_POST['item_code'] = $myrow["item_code"];
+    $_POST['quantity'] = $myrow["quantity"];
+    $_POST['description'] = $myrow["description"];
+    $_POST['category_id'] = $myrow["category_id"];
+}
+ else {
+    $_POST['quantity'] = 1;
+    $_POST['description'] = $dflt_desc;
+    $_POST['category_id'] = $dflt_cat;
+}
+
+echo "<br>";
+hidden('selected_id', $selected_id);
+start_table($table_style2);
+
+hidden('code_id', $selected_id);
+
+text_row(_("UPC/EAN code:"), 'item_code', null, 20, 21);
+qty_row(_("Quantity:"), 'quantity', null, '', $units, $dec);
+text_row(_("Description:"), 'description', null, 50, 200);
+stock_categories_list_row(_("Category:"), 'category_id', null);
+
+end_table(1);
+
+submit_add_or_update_center($selected_id == -1, '', true);
+
+end_form();
+end_page();
+
+?>
index 99091defdf6dcf9ee32be7255be0a889c10422fc..b9b679d40368fbe490b8e3f95b392fc80567ffd4 100644 (file)
@@ -123,7 +123,13 @@ if (isset($_POST['addupdate']))
                set_focus('NewStockID');
 
        }
-
+       elseif ($new_item && db_num_rows(get_item_kit($_POST['NewStockID'])))
+       {
+                       $input_error = 1;
+               display_error( _("This item code is already assigned to stock item or sale kit."));
+                       set_focus('NewStockID');
+       }
+       
        if ($input_error != 1)
        {
 
@@ -195,7 +201,22 @@ function can_delete($stock_id)
                display_error(_('Cannot delete this item because there are existing purchase order items for it.'));
                return false;
        }
-
+       $kits = get_where_used($stock_id);
+       $num_kits = db_num_rows($kits);
+       if ($num_kits) {
+               $msg = _("This item cannot be deleted because some code aliases 
+                       or foreign codes was entered for it, or there are kits defined 
+                       using this item as component")
+                       .':<br>';
+
+               while($num_kits--) {
+                       $kit = db_fetch($kits);
+                       $msg .= "'".$kit[0]."'";
+                       if ($num_kits) $msg .= ',';
+               }
+               display_error($msg);
+               return false;
+       }
        return true;
 }
 
diff --git a/inventory/manage/sales_kits.php b/inventory/manage/sales_kits.php
new file mode 100644 (file)
index 0000000..245656c
--- /dev/null
@@ -0,0 +1,241 @@
+<?php
+
+$page_security = 11;
+$path_to_root="../..";
+include_once($path_to_root . "/includes/session.inc");
+
+page(_("Sales Kits & Alias Codes"));
+
+include_once($path_to_root . "/includes/date_functions.inc");
+include_once($path_to_root . "/includes/ui.inc");
+include_once($path_to_root . "/includes/data_checks.inc");
+
+include_once($path_to_root . "/includes/manufacturing.inc");
+
+check_db_has_stock_items(_("There are no items defined in the system."));
+
+simple_page_mode(true);
+/*
+if (isset($_GET['item_code']))
+{
+       $_POST['item_code'] = $_GET['item_code'];
+       $selected_kit =  $_GET['item_code'];
+}
+*/
+//--------------------------------------------------------------------------------------------------
+function display_kit_items($selected_kit)
+{
+       global $table_style;
+
+       $result = get_item_kit($selected_kit);
+div_start('bom');
+       start_table("$table_style width=60%");
+       $th = array(_("Stock Item"), _("Description"), _("Quantity"), _("Units"),
+               '','');
+       table_header($th);
+
+       $k = 0;
+       while ($myrow = db_fetch($result))
+       {
+
+               alt_table_row_color($k);
+
+               label_cell($myrow["stock_id"]);
+               label_cell($myrow["comp_name"]);
+        qty_cell($myrow["quantity"], false, 
+                       $myrow["units"] == '' ? 0 : get_qty_dec($myrow["comp_name"]));
+        label_cell($myrow["units"] == '' ? _('kit') : $myrow["units"]);
+               edit_button_cell("Edit".$myrow['id'], _("Edit"));
+               edit_button_cell("Delete".$myrow['id'], _("Delete"));
+        end_row();
+
+       } //END WHILE LIST LOOP
+       end_table();
+div_end();
+}
+
+//--------------------------------------------------------------------------------------------------
+
+function update_component($kit_code, $selected_item)
+{
+       global $Mode, $Ajax, $selected_kit;
+       
+       if (!check_num('quantity', 0))
+       {
+               display_error(_("The quantity entered must be numeric and greater than zero."));
+               set_focus('quantity');
+               return;
+       }
+       elseif ($_POST['description'] == '')
+       {
+       display_error( _("Item code description cannot be empty."));
+               set_focus('description');
+               return;
+       }
+       elseif ($selected_item == -1)   // adding new item or new alias/kit
+       {
+               if (get_post('item_code') == '') { // New kit/alias definition
+                       $kit = get_item_kit($_POST['item_code']);
+               if (db_num_rows($kit)) {
+                               $input_error = 1;
+                       display_error( _("This item code is already assigned to stock item or sale kit."));
+                               set_focus('kit_code');
+                               return;
+                       }
+                       if (get_post('kit_code') == '') {
+                       display_error( _("Kit/alias code cannot be empty."));
+                               set_focus('kit_code');
+                               return;
+                       }
+               }
+       }
+
+       if (check_item_in_kit($selected_item, $kit_code, $_POST['component'], true)) {
+               display_error(_("The selected component contains directly or on any lower level the kit under edition. Recursive kits are not allowed."));
+               set_focus('component');
+               return;
+       }
+
+               /*Now check to see that the component is not already in the kit */
+       if (check_item_in_kit($selected_item, $kit_code, $_POST['component'])) {
+               display_error(_("The selected component is already in this kit. You can modify it's quantity but it cannot appear more than once in the same kit."));
+               set_focus('component');
+               return;
+       }
+       if ($selected_item == -1) { // new item alias/kit
+               if ($_POST['item_code']=='') {
+                       $kit_code = $_POST['kit_code'];
+                       $selected_kit = $_POST['item_code'] = $kit_code;
+                       $msg = _("New alias code has been created.");
+               } 
+                else
+                       $msg =_("New component has been added to selected kit.");
+
+               add_item_code( $kit_code, get_post('component'), get_post('description'),
+                        get_post('category'), input_num('quantity'), 0);
+               display_notification($msg);
+
+       } else {
+               $props = get_kit_props($_POST['item_code']);
+               update_item_code($selected_item, $kit_code, get_post('component'),
+                       $props['description'], $props['category_id'], input_num('quantity'), 0);
+               display_notification(_("Component of selected kit has been updated."));
+       }
+       $Mode = 'RESET';
+       $Ajax->activate('_page_body');
+}
+
+//--------------------------------------------------------------------------------------------------
+
+if (get_post('update_name')) {
+       update_kit_props(get_post('item_code'), get_post('description'), get_post('category'));
+       display_notification(_('Kit common properties has been updated'));
+       $Ajax->activate('_page_body');
+}
+
+if ($Mode=='ADD_ITEM' || $Mode=='UPDATE_ITEM')
+       update_component($_POST['item_code'], $selected_id);
+
+if ($Mode == 'Delete')
+{
+       // Before removing last component from selected kit check 
+       // if selected kit is not included in any other kit. 
+       // 
+       $other_kits = get_where_used($_POST['item_code']);
+       $num_kits = db_num_rows($other_kits);
+       if ($num_kits) {
+               $msg = _("This item cannot be deleted because it is the last item in the kit used by following kits")
+                       .':<br>';
+
+               while($num_kits--) {
+                       $kit = db_fetch($other_kits);
+                       $msg .= "'".$kit[0]."'";
+                       if ($num_kits) $msg .= ',';
+               }
+               display_error($msg);
+       } else {
+               delete_item_code($selected_id);
+               display_notification(_("The component item has been deleted from this bom"));
+               $Mode = 'RESET';
+       }
+}
+
+if ($Mode == 'RESET')
+{
+       $selected_id = -1;
+       unset($_POST['quantity']);
+       unset($_POST['component']);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+start_form(false, true);
+
+echo "<center>" . _("Select a sale kit:") . "&nbsp;";
+sales_kits_list('item_code', null, _('New kit'), true);
+echo "</center><br>";
+$props = get_kit_props($_POST['item_code']);
+
+if (isset($_POST['_item_code_update'])) {
+       if (get_post('item_code') == '')
+               $_POST['description'] = '';
+       $Ajax->activate('_page_body');
+}
+
+$selected_kit = $_POST['item_code'];
+//----------------------------------------------------------------------------------
+if (get_post('item_code') == '') {
+// New sales kit entry
+       start_table($table_style2);
+       text_row(_("Alias/kit code:"), 'kit_code', null, 20, 21);
+} else
+{ // Kit selected so display bom or edit component
+       $_POST['description'] = $props['description'];
+       $_POST['category'] = $props['category_id'];
+       start_table($table_style2);
+       text_row(_("Description:"), 'description', null, 50, 200);
+       stock_categories_list_row(_("Category:"), 'category', null);
+       submit_row('update_name', _("Update"), false, 'align=center colspan=2', _('Update kit/alias name'), true);
+       end_row();
+       end_table(1);
+       display_kit_items($selected_kit);
+       echo '<br>';
+       start_table($table_style2);
+}
+
+       if ($Mode == 'Edit') {
+               $myrow = get_item_code($selected_id);
+               $_POST['component'] = $myrow["stock_id"];
+               $_POST['quantity'] = number_format2($myrow["quantity"], get_qty_dec($myrow["stock_id"]));
+       }
+       hidden("selected_id", $selected_id);
+       
+       sales_local_items_list_row(_("Component:"),'component', null, false, true);
+
+//     if (get_post('description') == '')
+//             $_POST['description'] = get_kit_name($_POST['component']);
+       if (get_post('item_code') == '') { // new kit/alias
+               $_POST['description'] = $props['description'];
+               $_POST['category'] = $props['category_id'];
+               text_row(_("Description:"), 'description', null, 50, 200);
+               stock_categories_list_row(_("Category:"), 'category', null);
+       }
+       $res = get_item_edit_info(get_post('component'));
+       $dec =  $res["decimals"] == '' ? 0 : $res["decimals"];
+       $units = $res["units"] == '' ? _('kits') : $res["units"];
+       if (list_updated('component')) 
+       {
+               $_POST['quantity'] = number_format2(1, $dec);
+               $Ajax->activate('quantity');
+               $Ajax->activate('category');
+       }
+       qty_row(_("Quantity:"), 'quantity', null, '', $units, $dec);
+
+       end_table(1);
+       submit_add_or_update_center($selected_id == -1, '', true);
+       end_form();
+//----------------------------------------------------------------------------------
+
+end_page();
+
+?>
index 4da07b47f900a3c31808592b761536f4c541671d..10366fa39871fb62ee60e753fd539c6edebfd915 100644 (file)
@@ -45,7 +45,7 @@ if (!isset($_POST['stock_id']))
        $_POST['stock_id'] = get_global_stock_item();
 
 echo "<center>" . _("Item:"). "&nbsp;";
-stock_items_list('stock_id', $_POST['stock_id'], false, true);
+sales_items_list('stock_id', $_POST['stock_id'], false, true);
 echo "<hr></center>";
 
 set_global_stock_item($_POST['stock_id']);
@@ -110,7 +110,7 @@ if (list_updated('stock_id') || isset($_POST['_curr_abrev_update']) ) {
        // after change of stock, currency or salestype selector
        // display default calculated price for new settings. 
        // If we have this price already in db it is overwritten later.
-       $_POST['price'] = price_format(get_price(get_post('stock_id'), 
+       $_POST['price'] = price_format(get_kit_price(get_post('stock_id'), 
                get_post('curr_abrev'), get_post('sales_type_id')));
        $Ajax->activate('price_details');
 }
index f653c24a6b038ebf995601f50e7884d8a3575208..8c74c9bfbe597194168cea6667c6725552f67c3d 100644 (file)
@@ -59,11 +59,11 @@ function get_price ($stock_id, $currency, $sales_type_id, $factor=null, $date=nu
                $factor = $myrow['factor'];
        }
            
-       $sql = "SELECT ".TB_PREF."prices.price
+       $sql = "SELECT price
                FROM ".TB_PREF."prices
-               WHERE ".TB_PREF."prices.stock_id = '" . $stock_id . "' "
-               ." AND ".TB_PREF."prices.sales_type_id = " . $sales_type_id
-               ." AND ".TB_PREF."prices.curr_abrev = '$currency'";
+               WHERE stock_id = '" . $stock_id . "' "
+               ." AND sales_type_id = " . $sales_type_id
+               ." AND curr_abrev = '$currency'";
 
        $msg = "There was a problem retrieving the pricing information for the part $stock_id for customer";
        $result = db_query($sql, $msg);
@@ -73,21 +73,20 @@ function get_price ($stock_id, $currency, $sales_type_id, $factor=null, $date=nu
                $myrow = db_fetch_row($result);
                return $myrow[0];
        }
-       if ($factor == 0) return 0; // auto price calculations off
+       if ($factor == 0) return false; // auto price calculations off
 
        $base_id = get_base_sales_type();
         $home_curr = get_company_currency();
 
     // get all prices which we can use to guess the price.
     // alternative is make up to 2 additional sql queries
-       $sql = "SELECT ".TB_PREF."prices.price,".TB_PREF."prices.curr_abrev,
-               ".TB_PREF."prices.sales_type_id
+       $sql = "SELECT price, curr_abrev, sales_type_id
                FROM ".TB_PREF."prices
-               WHERE ".TB_PREF."prices.stock_id = '" . $stock_id . "' "
-               ." AND (".TB_PREF."prices.sales_type_id = " . $sales_type_id
-               ." OR ".TB_PREF."prices.sales_type_id = " . $base_id.")"
-               ." AND (".TB_PREF."prices.curr_abrev = '$currency'"
-               ." OR ".TB_PREF."prices.curr_abrev = '$home_curr')";
+               WHERE stock_id = '" . $stock_id . "' "
+               ." AND (sales_type_id = " . $sales_type_id
+               ." OR sales_type_id = " . $base_id.")"
+               ." AND (curr_abrev = '$currency'"
+               ." OR curr_abrev = '$home_curr')";
 
        $result = db_query($sql, $msg);
 
@@ -99,7 +98,7 @@ function get_price ($stock_id, $currency, $sales_type_id, $factor=null, $date=nu
        
        $rate = round(get_exchange_rate_from_home_currency($currency, $date),
            user_exrate_dec());
-       $price = 0.00;
+       $price = false;
        
        if (isset($prices[$sales_type_id][$home_curr])) 
        {
@@ -107,14 +106,49 @@ function get_price ($stock_id, $currency, $sales_type_id, $factor=null, $date=nu
        }
        if (isset($prices[$base_id][$currency])) 
        {
-           $price =$prices[$base_id][$currency] * $factor;
+           $price = $prices[$base_id][$currency] * $factor;
        }
        if (isset($prices[$base_id][$home_curr])) 
        {
-           $price =$prices[$base_id][$home_curr] * $factor / $rate;
+           $price = $prices[$base_id][$home_curr] * $factor / $rate;
        }
        
-       return round($price, user_price_dec());
+       return $price === false ? false : round($price, user_price_dec());
+}
+//----------------------------------------------------------------------------------------
+//
+//     Get price for given item or kit.
+//  When $std==true price is calculated as a sum of all included stock items,
+//     otherwise all prices set for kits and items are accepted.
+//
+function get_kit_price($item_code, $currency, $sales_type_id, $factor=null, 
+       $date=null, $std = false)
+{
+       $kit_price = 0.00;
+       if (!$std) {
+               $kit_price = get_price( $item_code, $currency, $sales_type_id, 
+                       $factor, $date);
+
+               if ($kit_price !== false) {
+                       return $kit_price;
+               }
+       }       
+       // no price for kit found, get total value of all items
+       $kit = get_item_kit($item_code);
+       
+       while($item = db_fetch($kit)) {
+               if ($item['item_code'] != $item['stock_id']) {
+                       // foreign/kit code
+                       $kit_price += $item['quantity'] * get_kit_price( $item['stock_id'], 
+                               $currency, $sales_type_id, $factor, $date, $std);
+
+               } else {
+                       // stock item
+                       $kit_price += $item['quantity'] * get_price( $item['stock_id'], 
+                               $currency, $sales_type_id, $factor, $date);
+               }
+       }
+       return $kit_price;
 }
 
 //-----------------------------------------------------------------------------
@@ -270,7 +304,8 @@ function read_sales_trans($doc_type, $trans_no, &$cart)
                $result = get_customer_trans_details($doc_type,$trans_no);
                if (db_num_rows($result) > 0) {
                        for($line_no=0; $myrow = db_fetch($result); $line_no++) {
-                               $cart->add_to_cart($line_no,$myrow["stock_id"],$myrow["quantity"],
+                               $cart->line_items[$line_no] = new line_details(
+                                       $myrow["stock_id"],$myrow["quantity"],
                                        $myrow["unit_price"], $myrow["discount_percent"],
                                        $myrow["qty_done"], $myrow["standard_cost"],
                                        $myrow["StockDescription"],$myrow["id"], $myrow["debtor_trans_no"]);
index 26894710857927006a3dd6c1a1cacaa1257c1f58..56926b42a451e930747ec2d204ef29df8978849d 100644 (file)
@@ -15,19 +15,58 @@ include_once($path_to_root . "/includes/manufacturing.inc");
 //--------------------------------------------------------------------------------
 function add_to_order(&$order, $new_item, $new_item_qty, $price, $discount)
 {
+       // calculate item price to sum of kit element prices factor for 
+       // value distribution over all exploded kit items
+        $std_price = get_kit_price($new_item, $order->customer_currency, 
+               $order->sales_type,     $order->price_factor, get_post('OrderDate'), true);
 
-       foreach ($order->line_items AS $order_item)
-       {
-               if (strcasecmp($order_item->stock_id, $new_item) == 0)
+       if ($std_price == 0)
+               $price_factor = 0;
+       else
+               $price_factor = $price/$std_price;
+
+       $kit = get_item_kit($new_item);
+       $item_num = db_num_rows($kit);
+
+       while($item = db_fetch($kit)) {
+               $std_price = get_kit_price($item['stock_id'], $order->customer_currency, 
+                       $order->sales_type,     $order->price_factor, get_post('OrderDate'), true);
+
+               // rounding differences are included in last price item in kit
+               $item_num--;
+               if ($item_num) {
+                       $price -= $item['quantity']*$std_price*$price_factor;
+                       $item_price = $std_price*$price_factor;
+               } else {
+                       if ($item['quantity']) 
+                               $price = $price/$item['quantity'];
+                       $item_price = $price;
+               }
+               $item_price = round($item_price, user_price_dec());
+
+        if (!$item['is_foreign'] && $item['item_code'] != $item['stock_id'])
+        {      // this is sales kit - recurse 
+               add_to_order($order, $item['stock_id'], $new_item_qty*$item['quantity'],
+                       $item_price, $discount, $std_price);
+        }
+        else
+        {      // stock item record eventually with foreign code
+
+               // check duplicate stock item
+               foreach ($order->line_items as $order_item)
                {
-                       display_notification(_("For Part :") . $new_item . " " . _("This item is already on this order. You have been warned."));
-                       break;
+                       if (strcasecmp($order_item->stock_id, $item['stock_id']) == 0)
+                       {
+                               display_notification(_("For Part :").$item['stock_id']. " " 
+                                       . _("This item is already on this order. You have been warned."));
+                               break;
+                       }
                }
+               $order->add_to_cart (count($order->line_items), $item['stock_id'], 
+                       $new_item_qty*$item['quantity'], $item_price, $discount);
+        }
        }
-
-       $order->add_to_cart (count($order->line_items),$new_item, $new_item_qty, $price, $discount);
 }
-
 //---------------------------------------------------------------------------------
 
 function get_customer_details_to_order(&$order, $customer_id, $branch_id)
@@ -382,7 +421,7 @@ function display_order_header(&$order, $editable, $date_text, $display_tax_group
        if ($change_prices != 0) {
                foreach ($order->line_items as $line_no=>$item) {
                        $line = &$order->line_items[$line_no];
-                       $line->price = get_price($line->stock_id, $order->customer_currency,
+                       $line->price = get_kit_price($line->stock_id, $order->customer_currency,
                                $order->sales_type, $order->price_factor, get_post('OrderDate'));
                //              $line->discount_percent = $order->default_discount;
                }
@@ -401,7 +440,7 @@ function sales_order_item_controls(&$order, &$rowcounter, $line_no=-1)
        alt_table_row_color($rowcounter);
 
        $id = find_submit('Edit');
-       if ($line_no!=-1 && $line_no == $id)
+       if ($line_no!=-1 && $line_no == $id) // edit old line
        {
                $_POST['stock_id'] = $order->line_items[$id]->stock_id;
                $dec = get_qty_dec($_POST['stock_id']);
@@ -414,9 +453,9 @@ function sales_order_item_controls(&$order, &$rowcounter, $line_no=-1)
                label_cell($order->line_items[$line_no]->item_description, "nowrap");
            $Ajax->activate('items_table');
        }
-       else
+       else    // prepare new line
        {
-               stock_items_list_cells(null,'stock_id', null, false, true);
+               sales_items_list_cells(null,'stock_id', null, false, true);
                if (list_updated('stock_id')) {
                            $Ajax->activate('price');
                            $Ajax->activate('units');
@@ -426,15 +465,14 @@ function sales_order_item_controls(&$order, &$rowcounter, $line_no=-1)
 
                $item_info = get_item_edit_info($_POST['stock_id']);
                $units = $item_info["units"];
-               $dec = get_qty_dec($_POST['stock_id']);
+               $dec = $item_info['decimals'];
                $_POST['qty'] = number_format2(1, $dec);
-
-               $_POST['price'] = price_format(get_price ($_POST['stock_id'],
+               $price = get_kit_price($_POST['stock_id'],
                        $order->customer_currency, $order->sales_type,
-                       $order->price_factor, get_post('OrderDate')));
+                       $order->price_factor, get_post('OrderDate'));
+               $_POST['price'] = price_format($price);
                // default to the customer's discount %
                $_POST['Disc'] = percent_format($order->default_discount * 100);
-
        }
 
        qty_cells(null, 'qty', $_POST['qty'], null, null, $dec);