Forums / General Questions / Inventory control for fast updating

Inventory control for fast updating

Results 1 to 7 of 7
25 Feb 2016, 14:41
#1
delia avatar

delia

Totally Zenned

Join Date:
May 2006
Posts:
2,383
Plugin Contributions:
5

Inventory control for fast updating

My client has a very old mod that I've never seen before for inventory control. She can update inventory and date available in a full page list of products.

The problem is that due to some server change, the date available field no longer works and throws an error saying invalid field format.

I'm aware of the datetime issues with coding etc but I'm not enough of coder to fix this problem for her without a lot of work and study.

The existing code is

[PHP]// Assuming an MM-DD-YYYY format, convert to YYYY-MM-DD.
// Take note that the datestamp string already includes
// single quotes if need be -- so that the null token can
// be inserted as well.


if($_POST[$nkey] == "now")
$datestamp = "null";
else {
array_shift($date_comp);
$datestamp = "'" . implode('-', array($date_comp[2], $date_comp[0], $date_comp[1])) . "'";
}[/PHP]

the warnings say the format should be mm-dd-yyyy instead. Not seeing how to change this.....
25 Feb 2016, 20:26
#2
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,907
Plugin Contributions:
1

Re: Inventory control for fast updating

What is/how is the array $date_comp generated?

Effectively what is happening is that the first item in the array (if post is not now) is removed from the array (which actually seems somewhat pointless if the individual array elements are then directly referenced, but anyways. The string generated is the 3rd (previously 4th) element - the 1st (previously 2nd) element - and then the 2nd element (previously 3rd) element all captured within a quote to keep as a string. If the result of $datestamp is to be this YYYY-MM-DD (database ready) and the input to this code is an array with at least four elements, 1st(0) : unknown/unimportant, 2nd(1) : MM, 3rd(2) : DD, and 4th(3) : YYYY, then it does that.
26 Feb 2016, 06:37
#3
drbyte avatar

drbyte

Sensei

Join Date:
Jan 2004
Posts:
63,506
Plugin Contributions:
173

Re: Inventory control for fast updating

Also important information is what PHP version is in use now, and what was in use previously?
Any other information you can explain about what "changed on the server" would be useful.
And, as mc12345678 suggested, more info (ie: code) about the $date_comp variable would help.


And, if she's willing to share, perhaps posting the code for the whole mod could be useful for others, or might inspire a new feature.
26 Feb 2016, 12:37
#4
delia avatar

delia

Totally Zenned

Join Date:
May 2006
Posts:
2,383
Plugin Contributions:
5

Re: Inventory control for fast updating

Certainly don't mind sharing!

Her site was being worked on for PCI complicance when she noticed this (geekhost). php version is 5.5.32

[PHP]<?php

/*
* Rapid Inventory Update Module (RIUM) - A module to allow rapid, bulk
* updates to the inventory of the shop.
*
* Author: Alex Balashov <[email protected]>, 2004.
*/

function D($var=NULL)
{ // show $var (debug):
PRIN($var,false);
}
function DD($var=NULL)
{ // show $var and exit (debug & die):
PRIN($var,true,true);
}
function PRIN($variable=NULL,$die=true,$debug=false)
{ // displays $variable contents and stops execution
if(!isset($variable))
$variable = "Not set."; // show all if nothing set:
echo "<pre style='background-color:white;'>";
print_r($variable);
if($debug)
{ // display call stack:
$s = debug_backtrace();
echo "\n\n";
foreach($s as $k=>$v)
echo "Line ".str_pad($v["line"]." ",5,' ',STR_PAD_RIGHT)." ".$v["file"]." ".$v["function"]."()\n";
}
echo "</pre>";
if($die)exit;
}

require('includes/application_top.php');
global $db;
$action = (isset($_GET['action']) ? $_GET['action'] : '');

// If we are processing an update, sanity-check values, and produce an error if something
// is amiss.

if($action == "process") {

foreach(array_keys($_POST) as $qty_var) {

// Process by quantity field. For every quantity field, find corresponding
// date field and run a single update query. This structure is more of a
// database query optimisation than anything.

if(preg_match("/product_qty_(\d+)/", $qty_var, $matches)) {


// Warn if non-numeric values encountered, otherwise process.

if(preg_match("/([^0-9\-]+)/", $POST_[$qty_var])) {

$messageStack->add(sprintf(WARNING_NON_NUMERIC_QUANTITIES, $matches[1]),
'warning');

// Force integerdom anyway in order to avoid SQL errors, injection.

settype($HTTP_POST_VARS[$qty_var], 'integer');
}


$nkey = "product_date_available_" . $matches[1];

if(!preg_match("/([0-9]+)\-([0-9]+)\-([0-9]+)/", $HTTP_POST_VARS[$nkey], $date_comp) &&
($HTTP_POST_VARS[$nkey] != "now"))
{

$messageStack->add(sprintf(WARNING_INVALID_DATE_FORMAT,
$matches[1]),
'warning');

$HTTP_POST_VARS[$nkey] = "now";

}


// Update if the field is not "now".

// Assuming an MM-DD-YYYY format, convert to YYYY-MM-DD.
// Take note that the datestamp string already includes
// single quotes if need be -- so that the null token can
// be inserted as well.


if($_POST[$nkey] == "now")
$datestamp = "null";
else {
array_shift($date_comp);
$datestamp = "'" . implode('-', array($date_comp[2], $date_comp[0], $date_comp[1])) . "'";
}


# Now run the query. Force integers with sprintf() in order to avoid
# SQL injection and otherwise make values what they are expected to be.

$db->Execute("UPDATE products SET "
. "products_quantity = "
. sprintf("%d", $_POST[$qty_var]) . ", "
. "products_date_available = $datestamp "
. "WHERE products_id = " . sprintf("%d", $matches[1]));

}

}

$messageStack->add(SUCCESS_INVENTORY_UPDATE, "success");

}

?>

<html <?php echo HTML_PARAMS; ?>>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET;
?>">
<title><?php echo TITLE; ?></title>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">

</head>

<body marginwidth="0" marginheight="0" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" bgcolor="#FFFFFF">

<!-- header -->
<?php require(DIR_WS_INCLUDES . 'header.php'); ?>
<!-- end of header -->

<!-- body -->
<?php echo zen_draw_form('products_update', 'inventory_stock.php', 'action=process'); ?>


<h1> <?php echo HEADING_TITLE; ?></h1>

<table border=0 cellpadding=0 cellspacing=3>
<tr class="dataTableHeadingRow">
<td class="dataTableHeadingContent"><?php echo HEADING_PRODUCT_CATEGORY; ?></td>
<td class="dataTableHeadingContent"><?php echo HEADING_PRODUCT; ?></td>

</tr>
<tr>
<td valign="top" align="right" colspan="2"><br>
<input type="submit" value="update" />
</td>
</tr>


<?php
// First fetch all categories that have at least one parent.

$categories = array();

// Consolidate the below into a join, so we can alphabetise, among other things.

$result = $db->Execute("SELECT c.categories_id, c.parent_id, cd.categories_name FROM categories AS c, categories_description AS cd WHERE c.parent_id > 0 AND cd.categories_id = c.categories_id ORDER BY cd.categories_name ASC");
// Buffer the categories.

while(!$result->EOF) {



$categories[] = array('categories_id' => $result->fields['categories_id'],
'parent_id' => $result->fields['parent_id'],
'name' => $result->fields['categories_name']);
$result->MoveNext();
}



foreach($categories as $category) {

$categories_products_query = $db->Execute("SELECT products_id FROM products_to_categories WHERE categories_id = " . $category['categories_id']);
$categories_products_query = $db->Execute("SELECT * FROM products_to_categories WHERE categories_id = " . $category['categories_id']);
// d($categories_products_query);
if($categories_products_query->RecordCount()) {


echo "<tr>\n"
. " <td valign=\"top\" class=\"dataTableContent\" width=\"30%\">\n"
. $category['name'] . "\n"
. " </td>\n"
. " <td width=\"70%\">\n<br>\n"
. " <table border=0 cellpadding=1 cellspacing=1 width=\"100%\">";

$products_query = $db->Execute("SELECT p.products_id, pd.products_name, p.products_quantity, DATE_FORMAT(p.products_date_available, '%m-%d-%Y') AS products_date_available "
. "FROM products AS p, products_description AS pd WHERE p.products_id = pd.products_id AND p.products_id = " . $categories_products_query->fields['products_id']);

$products_query = $db->Execute("SELECT p.* "
. "FROM products AS p WHERE p.master_categories_id = " . $categories_products_query->fields['categories_id']);

$products_query = $db->Execute("SELECT p.products_id, pd.products_name, p.products_quantity, DATE_FORMAT(p.products_date_available, '%m-%d-%Y') AS products_date_available "
. "FROM products AS p, products_description AS pd WHERE p.products_id = pd.products_id AND p.master_categories_id = " . $categories_products_query->fields['categories_id']);


// dd($products_query);
//original file has a while statement at this point to run thru the products that belong to each category where I can only get one product per category to show up. So the while statement below is not working.

while(!$products_query->EOF) {

// d($products_query);

//tried to make an array in case one does't exist but doesn't work
//$products[] = array('products_id' => $products_query->fields['products_id'],
// 'products_name' => $products_query->fields['products_name'],
// 'products_quantity' => $products_query->fields['products_quantity'],
// 'product_date_available' => $products_query->fields['product_date_available']);






echo " <tr>\n"
. " <td valign=\"top\" align=\"left\" width=\"50%\" class=\"dataTableContent\">\n"
. $products_query->fields['products_name']
. " </td>\n"
. " <td valign=\"top\" align=\"right\" width=\"20%\" class=\"dataTableContent\">\n"
. zen_draw_input_field('product_qty_' . $products_query->fields['products_id'], $products_query->fields['products_quantity'], 'maxlength=10, size=7', false, $type = 'text', false)
. " </td>\n"
. " <td valign=\"top\" align=\"right\" width=\"30%\" class=\"dataTableContent\">\n"
. zen_draw_input_field('product_date_available_' . $products_query->fields['products_id'],
isset($products_query->fields['products_date_available']) ?
$products_query->fields['products_date_available'] : "now",
'maxlength=15, size=10', false, $type = 'text', false)
. " </td>\n"
. " </tr>\n";

// this marks the end of the movement thru the while statement.
$products_query->MoveNext();




}

echo " </table>\n<br>\n"
. " </td>\n"
. "</tr>\n";

}

}

echo "<tr>\n"
. " <td valign=\"center\" colspan=2>\n"
. zen_draw_separator('pixel_black.gif', '100%', 1)
. " </td>"
. "</tr>\n"
. "<tr>\n"
. " <td valign=\"top\" align=\"right\" colspan=2>\n<br>\n"
. zen_image_submit('button_update.gif', IMAGE_UPDATE)
. " </td>\n"
. "</tr>\n";

?>

</table>
<!-- end body text -->

</form>
<!-- end of body -->

<?php
// Footer.

require(DIR_WS_INCLUDES . 'footer.php');
?>


</body>
</html>

<?php
require(DIR_WS_INCLUDES . 'application_bottom.php');
?>[/PHP]
26 Feb 2016, 14:37
#5
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,907
Plugin Contributions:
1

Re: Inventory control for fast updating

Two things I see could cause the error that you're receiving. Either the date isn't formatted xx-xx-xx specifically with the dashes between numbers or the fact that $HTTP_POST_VARS is used instead of $_POST

It seems that in more recent coding that $HTTP_POST_VARS has been deprecated and that $_POST should be used instead, but one could add a test for that and if it is not present to instead test against $_POST such that "compatibility could be maintained. But... I don't see any reason (yet) to try to maintain that compatibility as at least one source identified that $HTTP_POST_VARS was deprecated back in PHP 4.1.10 or there abouts.
26 Feb 2016, 16:02
#6
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,907
Plugin Contributions:
1

Re: Inventory control for fast updating

Okay, thought I would try it *right* this time, modified the queries a little (highlighted), added some notes, and also saw that the $HTTP_POST_VARS variable was used elsewhere, so might as well update it in full as much as might be seen without testing/executing. :)

<?php

/*
 * Rapid Inventory Update Module (RIUM) - A module to allow rapid, bulk
 * updates to the inventory of the shop.
 *
 * Author: Alex Balashov <[email protected]>, 2004.
 */

function D($var=NULL)
{    // show $var (debug):
    PRIN($var,false);
}
function DD($var=NULL)
{    // show $var and exit (debug & die):
    PRIN($var,true,true);
}
function PRIN($variable=NULL,$die=true,$debug=false)
{    // displays $variable contents and stops execution
    if(!isset($variable))
        $variable = "Not set."; // show all if nothing set:
    echo "<pre style='background-color:white;'>";
    print_r($variable);
    if($debug)
    {    // display call stack:
        $s = debug_backtrace();
        echo "\n\n";
        foreach($s as $k=>$v)
            echo "Line ".str_pad($v["line"]." ",5,' ',STR_PAD_RIGHT)." ".$v["file"]." ".$v["function"]."()\n";
    }
    echo "</pre>";
    if($die)exit;
}

require('includes/application_top.php');
global $db; // <-This is unnecessary;
$action = (isset($_GET['action']) ? $_GET['action'] : '');

// If we are processing an update, sanity-check values, and produce an error if something
// is amiss.

// Would suggest using if(zen_not_null($action)) { before this $action == check and to close it out at the end of the same set of code.

if($action == "process") {

    foreach(array_keys($_POST) as $qty_var) {

        // Process by quantity field.  For every quantity field, find corresponding
        // date field and run a single update query.  This structure is more of a
        // database query optimisation than anything.

        if(preg_match("/product_qty_(\d+)/", $qty_var, $matches)) {


            // Warn if non-numeric values encountered, otherwise process.

            if(preg_match("/([^0-9\-]+)/", $POST_[$qty_var])) {
                
                $messageStack->add(sprintf(WARNING_NON_NUMERIC_QUANTITIES, $matches[1]),
                            'warning');

                // Force integerdom anyway in order to avoid SQL errors, injection.

                settype($_POST[$qty_var], 'integer');
            }


            $nkey = "product_date_available_" . $matches[1];

            if(!preg_match("/([0-9]+)\-([0-9]+)\-([0-9]+)/", $_POST[$nkey], $date_comp) && 
               ($_POST[$nkey] != "now")) 
            {

                $messageStack->add(sprintf(WARNING_INVALID_DATE_FORMAT,
                            $matches[1]),
                                'warning');

                $_POST[$nkey] = "now";
            
            } 


            // Update if the field is not "now".

            // Assuming an MM-DD-YYYY format, convert to YYYY-MM-DD.
            // Take note that the datestamp string already includes 
            // single quotes if need be -- so that the null token can 
            // be inserted as well.


            if($_POST[$nkey] == "now")
                $datestamp = "null";
             else {
                array_shift($date_comp);
                $datestamp = "'" . implode('-', array($date_comp[2], $date_comp[0], $date_comp[1])) . "'";
            }


            # Now run the query.  Force integers with sprintf() in order to avoid
            # SQL injection and otherwise make values what they are expected to be.

            $db->Execute("UPDATE " . TABLE_PRODUCTS . " SET "
                . "products_quantity = " 
                . sprintf("%d", $_POST[$qty_var]) . ", "
                . "products_date_available = $datestamp "
                . "WHERE products_id = " . sprintf("%d", $matches[1]));

        }

    }

    $messageStack->add(SUCCESS_INVENTORY_UPDATE, "success");

}
// Here is where I think I would expect the closing } for zen_not_null($action) closure from above
?>

<html <?php echo HTML_PARAMS; ?>>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET;
?>">
<title><?php echo TITLE; ?></title>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">

</head>

<body marginwidth="0" marginheight="0" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" bgcolor="#FFFFFF">

<!-- header -->
<?php require(DIR_WS_INCLUDES . 'header.php'); ?>
<!-- end of header -->

<!-- body -->
<?php echo zen_draw_form('products_update', 'inventory_stock.php', 'action=process'); ?>


       <h1> <?php echo HEADING_TITLE; ?></h1>
 
       <table border=0 cellpadding=0 cellspacing=3>
         <tr class="dataTableHeadingRow">
           <td class="dataTableHeadingContent"><?php echo HEADING_PRODUCT_CATEGORY; ?></td>
       <td class="dataTableHeadingContent"><?php echo HEADING_PRODUCT; ?></td>
       
         </tr>
         <tr>
           <td valign="top" align="right" colspan="2"><br>
               <input type="submit" value="update" />
           </td>
         </tr>

 
<?php
    // First fetch all categories that have at least one parent.

    $categories = array();

    // Consolidate the below into a join, so we can alphabetise, among other things.

    $result = $db->Execute("SELECT c.categories_id, c.parent_id, cd.categories_name FROM " . TABLE_CATEGORIES . " AS c, " . TABLE_CATEGORIES_DESCRIPTION . " AS cd WHERE c.parent_id > 0 AND cd.categories_id = c.categories_id ORDER BY cd.categories_name ASC"); 
    // Buffer the categories. 

    while(!$result->EOF) { 

        

        $categories[] = array('categories_id' => $result->fields['categories_id'], 
                      'parent_id' => $result->fields['parent_id'], 
                      'name' => $result->fields['categories_name']); 
        $result->MoveNext(); 
    }

    

    foreach($categories as $category) {

        $categories_products_query = $db->Execute("SELECT products_id FROM " . TABLE_PRODUCTS_TO_CATEGORIES . " WHERE categories_id = " . $category['categories_id']);
        $categories_products_query = $db->Execute("SELECT * FROM " . TABLE_PRODUCTS_TO_CATEGORIES . " WHERE categories_id = " . $category['categories_id']);
// d($categories_products_query);
        if($categories_products_query->RecordCount()) {

// Would suggest converting the below to have the html outside of the echo statement(s) and only be echoing the php applicable information.


            echo "<tr>\n"
            .    "  <td valign=\"top\" class=\"dataTableContent\" width=\"30%\">\n"
            .    $category['name'] . "\n"
            .    "  </td>\n"
            .    "  <td width=\"70%\">\n<br>\n"
            .    "    <table border=0 cellpadding=1 cellspacing=1 width=\"100%\">";

$products_query = $db->Execute("SELECT p.products_id, pd.products_name, p.products_quantity, DATE_FORMAT(p.products_date_available, '%m-%d-%Y') AS products_date_available "
                            .      "FROM " . TABLE_PRODUCTS . " AS p, " . TABLE_PRODUCTS_DESCRIPTION . " AS pd WHERE p.products_id = pd.products_id AND p.products_id = " . $categories_products_query->fields['products_id']);

$products_query = $db->Execute("SELECT p.* "
                            .      "FROM " . TABLE_PRODUCTS . " AS p WHERE p.master_categories_id = " . $categories_products_query->fields['categories_id']);

$products_query = $db->Execute("SELECT p.products_id, pd.products_name, p.products_quantity, DATE_FORMAT(p.products_date_available, '%m-%d-%Y') AS products_date_available "
                            .      "FROM " . TABLE_PRODUCTS . " AS p, " . TABLE_PRODUCTS_DESCRIPTION . " AS pd WHERE p.products_id = pd.products_id AND p.master_categories_id = " . $categories_products_query->fields['categories_id']  . " AND pd.language_id = " . (int) $_SESSION['languages_id']); // Thinking the lack of the languages_id which may be incorrectly provided here is causing the lack of results... Could be wrong. Also this looks only at the master_categories_id and doesn't cross reference which products are listed in each category (linked product for example) though having such product displayed could also cause problems if not properly "considered."

                            
// dd($products_query);
//original file has a while statement at this point to run thru the products that belong to each category where I can only get one product per category to show up. So the while statement below is not working.
                            
while(!$products_query->EOF) {    

// d($products_query);

//tried to make an array in case one does't exist but doesn't work        
//$products[] = array('products_id' => $products_query->fields['products_id'], 
    //                  'products_name' => $products_query->fields['products_name'], 
    //                  'products_quantity' => $products_query->fields['products_quantity'],
    //                  'product_date_available' => $products_query->fields['product_date_available']); 


                

                // Would suggest converting the below to have the html outside of the echo statement(s) and only be echoing the php applicable information.

                    echo "        <tr>\n"
                    .    "          <td valign=\"top\" align=\"left\" width=\"50%\" class=\"dataTableContent\">\n"
                    . $products_query->fields['products_name']
                    .    "          </td>\n"
                    .    "        <td valign=\"top\" align=\"right\" width=\"20%\" class=\"dataTableContent\">\n"
                    . zen_draw_input_field('product_qty_' . $products_query->fields['products_id'], $products_query->fields['products_quantity'], 'maxlength=10, size=7', false, $type = 'text', false)
                    .    "            </td>\n"
                    .    "            <td valign=\"top\" align=\"right\" width=\"30%\" class=\"dataTableContent\">\n"
                    . zen_draw_input_field('product_date_available_' . $products_query->fields['products_id'], 
                            isset($products_query->fields['products_date_available']) ? 
                               $products_query->fields['products_date_available'] : "now",
                            'maxlength=15, size=10', false, $type = 'text', false)
                    .    "        </td>\n"
                    .    "        </tr>\n";
                    
// this marks the end of the movement thru the while statement.                    
$products_query->MoveNext();
                

            
    
        }    
        
            echo "      </table>\n<br>\n"
            .    "  </td>\n"
            .    "</tr>\n";
        
    }    
    
    }

        echo     "<tr>\n"
        .    "  <td valign=\"center\" colspan=2>\n"
        .    zen_draw_separator('pixel_black.gif', '100%', 1)
        .    "  </td>"
            .    "</tr>\n"
        .      "<tr>\n"
            .    "  <td valign=\"top\" align=\"right\" colspan=2>\n<br>\n"
        .    zen_image_submit('button_update.gif', IMAGE_UPDATE)
            .    "  </td>\n"
            .    "</tr>\n";

?>

</table>
<!-- end body text -->

</form>
<!-- end of body -->

<?php
    // Footer.

    require(DIR_WS_INCLUDES . 'footer.php');
?>


</body>
</html>

<?php
    require(DIR_WS_INCLUDES . 'application_bottom.php');
?>
28 Feb 2016, 13:26
#7
delia avatar

delia

Totally Zenned

Join Date:
May 2006
Posts:
2,383
Plugin Contributions:
5

Re: Inventory control for fast updating

That was the fix! Thanks so much.