Forums / Built-in Shipping and Payment Modules / Require UPS ground on only certain cart items

Require UPS ground on only certain cart items

Views: 1,845

Results 1 to 11 of 11
19 Jan 2011, 10:44 PM
#1
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Require UPS ground on only certain cart items

Hi all. Ive found several places where posts and possible solutions within the forums... I have a slightly different problem..

Most of my cart products can ship either UPS or USPS, along with all options I offer (customer is permitted to choose) . However..

For both the shipping calculator, AND the actual checkout process, here is what I need to do:

Certain aerosol products are not allowed to ship by air freight (which means they may not ship next day or express) - and must ONLY ship ground freight. Because of this, USPS shipping is also not permitted on these products. (Only ships UPS ground)

Currently, such items are posted in my store as "Ships UPS only" , however there is no way to prevent customers from selecting next day, or USPS shipping during checkout..

So what I need to do is have a way to flag certain product id's that are only allowed to ship by UPS ground - That's no trouble (I'll add that in to the appropriate areas of admin side of cart , and brain dead simple to pop in a simple database table containing the product id's)

Oh by the way I am somewhat of an accomplished programmer in php myself, though that is not my primary line of work :) So, making changes will be easy enough.

What I am asking, however, is if someone would offer insight into this issue, and possibly point out better places to do the calculations I need to do (shipping calculator must be modified, product_info.php must be modified - as it will detect when an item is in the "no fly" list, and automatically append "SHIPS UPS ONLY" with an appropriate UPS ground shipping icon) - shopping cart and checkout process, as well must be modified to do the same checks.

What I am thinking is to find one appropriate class file (Perhaps I can just write a new class for this, and pop it in the always_include folder, for example? maybe a better location to put it? ) and modify it to include , (this is just an example) - Pseudo-code, if you will..

$validate_shipping = new validate_shipping();
$cart_ships_ups_only = $validate_shipping($cart_array_or_class);
if(false !== $cart_ships_ups_only){
if($we_are_in_shipping_calculator){
  $shipping_options=strip_disallowed_shipping_from($calculator_results);
 echo $display_shipping_options_here;
}
}

Basically, modifying the cart, teh checkout, and the shipping calculator, and product info display so that if any product_id is in the cart, or being looked at, that is in the "no fly" list (stored to a separate table with a simple button-push or checkbox via admin panel during an add or edit of product)

It's pretty simple for my case- if a mixed cart happens (I.E. 5 of an item that ship any method, but 1 of a "No-Fly" product in the cart- entire order only ships UPS) , so I dont think it should be too much trouble..

So , what Im wondering is, if anyone has some insight into where would be the best place to put the core functionality (namely, checking cart when calculating shipping, or during checkout, etc) to see if any product in the cart is on the No-Fly list.. , and also, point out, or poke holes into, what I am thinking..

If I am able to get this done and get it working that way, I'll be only too happy to contribute the final solution - which might solve the issue for some other people..

20 Jan 2011, 2:02 PM
#2
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Require UPS ground on only certain cart items

What distinguishes these UPS Ground only Products from other Products in the products table?

Or, do you have to do this by products_id of these Products?

When you have 1 or more of these Products in the cart, does this mean the Order, regardless of other Products ship UPS Ground only?

Linda McGrath
If you have to think ... you haven't been zenned ...

**Did YOU buy the Zen Cart Team a cup of coffee and a donut today? Just click here to support the Zen Cart Team!!**

Are you using the latest? Perhaps you've a problem that's fixed in the latest version: [Upgrade today!]
Officially PayPal-Certified! Just click here

Try our Zen Cart Recommended Services - Hosting, Payment and more ...
Signup for our Announcements Forums to stay up to date on important changes and updates!

20 Jan 2011, 2:16 PM
#3
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Re: Require UPS ground on only certain cart items

Ajeh:

What distinguishes these UPS Ground only Products from other Products in the products table?
Nothing specific at the moment - I need to create a way to set them apart... I'd been considering/looking at possibly adding a field to products_attributes and set it as an attribute, which might have made it more useful , but so far looks like my best option is a new table with products id and restricted shipping fields, where restricted shipping can set a type for either ups or usps - which is just one part of the solution . > Or, do you have to do this by products_id of these Products?

When you have 1 or more of these Products in the cart, does this mean the Order, regardless of other Products ship UPS Ground only?
yep - that's what I said, I thought - in my case, any order where a product is on the restricted list is in the cart, ships only UPS , regardless of size or cost, etc.

20 Jan 2011, 5:19 PM
#4
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Require UPS ground on only certain cart items

You can try customizing the ups.com shipping module with the code in red:

      $qsize = sizeof($upsQuote);

// bof: test cart vs ground only products
      global $cart;
      // set products_id in format of products_id comma space
      $chk_products = '4, 10, 12, 133';
      // build current cart products_id
      $products = $_SESSION['cart']->get_products();
      $cart_products_id = '';
      for ($i=0; $i<sizeof($products); $i++) {
        $cart_products_id .= (int)$products[$i]['id'];
        if ($i+1 < sizeof($products)) {
          $cart_products_id .= ', ';
        }
      }
      $arr1 = explode(", ", $chk_products);
      $arr2 = explode(", ", $cart_products_id);
      $ups_ground_chk = array_intersect($arr1, $arr2);
// eof: test cart vs ground only products

      for ($i=0; $i<$qsize; $i++) {
        $cost = preg_replace('/[^0-9.]/', '',  $cost);

// bof: test cart vs ground only products
        // skip shipping method if not Ground when 1 or more ground only products in cart
        if (sizeof($ups_ground_chk) > 0 && $type != 'GND') {
          // skip display of shipping method
        } else {
          $methods[] = array('id' => $type,
                             'title' => $this->types[$type],
                             'cost' => ($cost * $shipping_num_boxes) + (MODULE_SHIPPING_UPS_HANDLING_METHOD == 'Box' ? MODULE_SHIPPING_UPS_HANDLING * $shipping_num_boxes : MODULE_SHIPPING_UPS_HANDLING) );
        }
// eof: test cart vs ground only products
      }

      $this->quotes['methods'] = $methods;

Linda McGrath
If you have to think ... you haven't been zenned ...

**Did YOU buy the Zen Cart Team a cup of coffee and a donut today? Just click here to support the Zen Cart Team!!**

Are you using the latest? Perhaps you've a problem that's fixed in the latest version: [Upgrade today!]
Officially PayPal-Certified! Just click here

Try our Zen Cart Recommended Services - Hosting, Payment and more ...
Signup for our Announcements Forums to stay up to date on important changes and updates!

20 Jan 2011, 8:16 PM
#5
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Re: Require UPS ground on only certain cart items

Ajeh:

You can try customizing the ups.com shipping module with the code in red:

Perfect! that is about what I was thinking to do - but you picked out a better location for it than I was gonna make use of it ..

Now just have to apply it to usps as well (We ship by choice of UPS or USPS) .. but I should be able to find it.

Thank you.

21 Jan 2011, 2:05 AM
#6
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Re: Require UPS ground on only certain cart items

Mostly resolved.

I have one minor thing that I want to do, that I have not yet figured out - and that is, I want the usps module to return a reasult set that will simply parse into the estimator and rate chart - You'll see it in the code to follow in usps.php where, for now I simply return an error value.
NOTE all paths I mention are from the /catalog/ directory..
file: /includes/databse.php
Bottom of the file, about line 98

//BOM: UPS RESTRICTION on products - NOTE: Must run the following query on store's database manually - if your db uses a prefix, you need to edit the query
//create table restricted_products (id int(11) unsigned not null auto_increment,products_id int(11) not null default 0, primary key id(id), index productid(products_id))type=MyISAM;
define('TABLE_RESTRICTED_PRODUCTS',DB_PREFIX.'restricted_products');
//EOM: UPS RESTRICTION on products

file:/includes/languages/english/modules/shipping/usps.php
end of file, around like 28

//BOM: UPS Ground only restriction
//NOTE: This language string is desired to be shown in the rate chart and/or estimator, need to adjust usps.php module to get a correct return
define('MODULE_SHIPPING_USPS_RESTRICTED','<br />Due to a restricted product in your shopping cart, we are only able to offer UPS Ground shipping.');

//EOM: UPS Ground only restriction

file: /includes/modules/shipping/ups.php
around line 179, after $qsize variable

      $qsize = sizeof($upsQuote);
      //BOM: Restricted shipping to UPS ground only
      $restricted_products = array();
global $db;
$ups_only=$db->Execute("select * from ".TABLE_RESTRICTED_PRODUCTS." order by products_id");
while(!$ups_only->EOF)
{
	array_push($restricted_products,$ups_only->fields['products_id']);
   $ups_only->MoveNext();
}
//Testing:
//$restricted_products = array('130');
$restricted_in_cart = $_SESSION['cart']->get_products();
while($check_is_restricted=array_shift($restricted_in_cart))
{
	if(in_array($check_is_restricted['id'],$restricted_products))
	{
		$is_ground_only = true;//setting this just in case I want to use it elsewhere
		$allowed_methods = array('GND');
   }

}
      //EOM: Restricted shipping to UPS ground only

File: /includes/modules/shipping/usps.php
around line 183-185

    $this->_setWeight($shipping_pounds, $shipping_ounces);
    $uspsQuote = $this->_getQuote();
    //BOM: UPS ground on restricted items
//At this point, since we are checking for ground only shipments, we want to force UPS , so return
//a value indicating items in cart are restricted and must ship UPS ground only
$restricted_products = array();
global $db;
$ups_only=$db->Execute("select * from ".TABLE_RESTRICTED_PRODUCTS." order by products_id");
while(!$ups_only->EOF)
{
	array_push($restricted_products,$ups_only->fields['products_id']);
   $ups_only->MoveNext();
}
//Testing:
//$restricted_products = array('130');
$restricted_in_cart = $_SESSION['cart']->get_products();
while($check_is_restricted=array_shift($restricted_in_cart))
{
	if(in_array($check_is_restricted['id'],$restricted_products))
	{
//TODO: Need to set up so that the quotes returns a single line which can be parsed and displayed *only* (without allowing it to be selected) somewhere in both estimator and quote/shipping method selection.. havent gotten to that yet, so returning an error for now. 
		$this->quotes = array('module' => $this->title,'error' => MODULE_SHIPPING_USPS_RESTRICTED);
      return $this->quotes;
   }

}
//EOM: UPS ground on restricted items
    if (is_array($uspsQuote)) {
      if (isset($uspsQuote['error'])) {

Now for the admin side- I just made a simple hack rather than a more correct modular plugin - quick and dirty does the job well enough

file: {ADMIN_FOLDER}/includes/modules/product/collect_info.php
around line 504 (of mine) insert a new table row just before the close table tag:

         <!-- BOM: Restrict product to UPS ground only ---> 
          <?php
          $restricted_check=$db->Execute("select * from restricted_products where products_id='".$pinfo->products_id."'");
          if(!$restricted_check->EOF)
          {
          	$is_restricted=1;
          	
          }
          ?>
          <tr>
            <td class="main"><?php echo 'Restricted Product'; ?></td>

            <td class="main"><?php echo zen_draw_separator('pixel_trans.gif', '24', '15') . ' ' . zen_draw_checkbox_field('is_restricted', '1',$is_restricted,1); ?></td>


          </tr>
          <!-- EOM: Restrict product to UPS ground only -->

        </table></td>

and finally ..
file: {ADMIN_FOLDER}/includes/modules/update_product.php
starting around line 85 ...

      $db->Execute("insert into " . TABLE_PRODUCTS_TO_CATEGORIES . "

                    (products_id, categories_id)

                    values ('" . (int)$products_id . "', '" . (int)$current_category_id . "')");
//BOM: Restricted product to ground shipping only.
if(!empty($_POST['is_restricted']) && $_POST['is_restricted'] == 1)
{
$db->Execute("insert into restricted_products (products_id) values ('" . (int)$products_id . "')");
}
else
{
//However if we uncheck the box later, we need to remove it...
	$db->execute("delete from restricted_products where products_id in ('" . (int)$products_id . "')");
	//var_dump($_POST['is_restricted']);
}
//EOM: Restricted product to ground shipping only

      ///////////////////////////////////////////////////////

      //// INSERT PRODUCT-TYPE-SPECIFIC *INSERTS* HERE //////





      ////    *END OF PRODUCT-TYPE-SPECIFIC INSERTS* ////////

      ///////////////////////////////////////////////////////

    } elseif ($action == 'update_product') {

      $update_sql_data = array( 'products_last_modified' => 'now()',

                                'master_categories_id' => ($_POST['master_category'] > 0 ? zen_db_prepare_input($_POST['master_category']) : zen_db_prepare_input($_POST['master_categories_id'])));



      $sql_data_array = array_merge($sql_data_array, $update_sql_data);



      zen_db_perform(TABLE_PRODUCTS, $sql_data_array, 'update', "products_id = '" . (int)$products_id . "'");

		//BOM: Restricted product to ground shipping only.
if(!empty($_POST['is_restricted']) && $_POST['is_restricted'] == 1)
{
$db->Execute("insert into restricted_products (products_id) values ('" . (int)$products_id . "')");
}
else
{
//However if we uncheck the box later, we need to remove it...
	$db->execute("delete from restricted_products where products_id in ('" . (int)$products_id . "')");
	
}
//EOM: Restricted product to ground shipping only

      // reset products_price_sorter for searches etc.

      zen_update_products_price_sorter((int)$products_id);



      ///////////////////////////////////////////////////////

      //// INSERT PRODUCT-TYPE-SPECIFIC *UPDATES* HERE //////

Pretty simplistic, but it does exactly the job I need it to do, and for products so added to the restricted products table, it does indeed work exactly as intended - forces UPS Ground as the only possible shipping option when specific restricted products are selected.

I'm sure the code above can be used as the basis for some module or plugin to solve several other "similar, but not identical" issues that other people may have.

21 Jan 2011, 2:24 AM
#7
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Require UPS ground on only certain cart items

You could try changing the USPS code in the function quote for something like:

    $uspsQuote = $this->_getQuote();
// bof: test cart vs ground only products
      global $cart;
      // set products_id in format of products_id comma space
      $chk_products = '4, 10, 12, 133';
      // build current cart products_id
      $products = $_SESSION['cart']->get_products();
      $cart_products_id = '';
      for ($i=0; $i<sizeof($products); $i++) {
        $cart_products_id .= (int)$products[$i]['id'];
        if ($i+1 < sizeof($products)) {
          $cart_products_id .= ', ';
        }
      }
      $arr1 = explode(", ", $chk_products);
      $arr2 = explode(", ", $cart_products_id);
      $ups_ground_chk = array_intersect($arr1, $arr2);
// eof: test cart vs ground only products

    if (is_array($uspsQuote)) {
      if (isset($uspsQuote['error']) || sizeof($ups_ground_chk) > 0) {
        if (sizeof($ups_ground_chk) > 0) {
        $this->quotes = array('module' => $this->title,
                              'error' => 'UPS GROUND ONLY');
        } else {
        $this->quotes = array('module' => $this->title,
                              'error' => $uspsQuote['error']);
        }
      } else {

Linda McGrath
If you have to think ... you haven't been zenned ...

**Did YOU buy the Zen Cart Team a cup of coffee and a donut today? Just click here to support the Zen Cart Team!!**

Are you using the latest? Perhaps you've a problem that's fixed in the latest version: [Upgrade today!]
Officially PayPal-Certified! Just click here

Try our Zen Cart Recommended Services - Hosting, Payment and more ...
Signup for our Announcements Forums to stay up to date on important changes and updates!

21 Jan 2011, 4:26 PM
#8
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Re: Require UPS ground on only certain cart items

Ajeh:

You could try changing the USPS code in the function quote for something like:

$uspsQuote = $this->_getQuote();

// bof: test cart vs ground only products
global $cart;
// set products_id in format of products_id comma space
$chk_products = '4, 10, 12, 133';
// build current cart products_id
$products = $_SESSION['cart']->get_products();
$cart_products_id = '';
for ($i=0; $i<sizeof($products); $i++) {
$cart_products_id .= (int)$products[$i]['id'];
if ($i+1 < sizeof($products)) {
$cart_products_id .= ', ';
}
}
$arr1 = explode(", ", $chk_products);
$arr2 = explode(", ", $cart_products_id);
$ups_ground_chk = array_intersect($arr1, $arr2);
// eof: test cart vs ground only products

if (is_array($uspsQuote)) {
  if (isset($uspsQuote['error']) || sizeof($ups_ground_chk) > 0) {
    if (sizeof($ups_ground_chk) > 0) {
    $this->quotes = array('module' => $this->title,
                          'error' => 'UPS GROUND ONLY');
    } else {
    $this->quotes = array('module' => $this->title,
                          'error' => $uspsQuote['error']);
    }
  } else {

Umm yeah - that's what I dom, although with a bit less code, but the returned value does *not* show up in the rate chart shown to the customer, I am assuming the error message returned is used elsewhere, or I am not formatting mine right - makes no sense to continue processing and run an API call when it is not necessary to do so, so I set a return immediately when it is ground-only freight. 
see below - contained in the above mods I posted. 

$restricted_in_cart = $_SESSION['cart']->get_products();
while($check_is_restricted=array_shift($restricted_in_cart))
{
if(in_array($check_is_restricted['id'],$restricted_products))
{
//TODO: Need to set up so that the quotes returns a single line which can be parsed and displayed only (without allowing it to be selected) somewhere in both estimator and quote/shipping method selection.. havent gotten to that yet, so returning an error for now. - error does not display in rate chart for some reason
$this->quotes = array('module' => $this->title,'error' => MODULE_SHIPPING_USPS_RESTRICTED);
return $this->quotes;
}

}

21 Jan 2011, 4:38 PM
#9
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Require UPS ground on only certain cart items

You would really need to test what works best for you ...

The suggestion to put it on the error message in USPS is it is a quick method to get the message in the correct location of the checkout_shipping without having to do a lot of re-working of the code based on the contents of the cart ...

That section of code testing the cart could also be placed in a function so that it only needs to be maintained in one file and then called from two shipping modules ...

Linda McGrath
If you have to think ... you haven't been zenned ...

**Did YOU buy the Zen Cart Team a cup of coffee and a donut today? Just click here to support the Zen Cart Team!!**

Are you using the latest? Perhaps you've a problem that's fixed in the latest version: [Upgrade today!]
Officially PayPal-Certified! Just click here

Try our Zen Cart Recommended Services - Hosting, Payment and more ...
Signup for our Announcements Forums to stay up to date on important changes and updates!

21 Jan 2011, 5:50 PM
#10
Join Date:
Apr 2009
Posts:
36
Plugin Contributions:
0

Re: Require UPS ground on only certain cart items

figured it out - what I needed was the error to display on the estimator, and since I was crafting a customized return, I needed to get the object created properly ..

this is what I needed to do :) and now the shipping estimate chart shows the error message. just a slight template tweak to the shipping estimator template file, and I got it the way I want it .. Thanks for the tips, Ajeh!
My original code returned the 'error' element, but , the shipping chart also needed a methods sub-array in order to actually display the error.. (because it doesnt check for error element unless the sizeof methods element is 1 or more)

while($check_is_restricted=array_shift($restricted_in_cart))
{
   if(in_array($check_is_restricted['id'],$restricted_products))
   {
   	$this->quotes = array('module' => $this->title,'error' => MODULE_SHIPPING_USPS_RESTRICTED,'methods'=>array('id'=>'usps'));
     return $this->quotes;
  }

}
21 Jan 2011, 5:59 PM
#11
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Require UPS ground on only certain cart items

You are most welcome ... thanks for the update that this is now working for you ... :smile:

Linda McGrath
If you have to think ... you haven't been zenned ...

**Did YOU buy the Zen Cart Team a cup of coffee and a donut today? Just click here to support the Zen Cart Team!!**

Are you using the latest? Perhaps you've a problem that's fixed in the latest version: [Upgrade today!]
Officially PayPal-Certified! Just click here

Try our Zen Cart Recommended Services - Hosting, Payment and more ...
Signup for our Announcements Forums to stay up to date on important changes and updates!