Me too...
I've run into the same issue... with live rates. I'm not sure what shipping plugins you're using but, regardless, I believe the problem is CT checks the "shippable subtotal" to see if it is less than or equal to 0 and, if it is, no shipping is provided. The following is in regards to the live rates plugins.
The problem is with shippable_subtotal()
Ultimately, running shippable_subtotal()
on the cart goes through all of the products that are "shippable" and then runs $item->price_subtotal()
for each item in the cart. If the price of the product has been set to $0, it's shippable subtotal becomes $0 as well.
Instead of checking that the shippable subtotal is less than or equal to 0, CT should check to see if the cart has shippable items. Just because the subtotal of shippable items is 0, doesn't mean the products don't need to be shipped. I think this is a bug.
For example...
Specifically, the code I'm referring to is in Cartthrob's live rate shipping plugins that I use (Cartthrob_shipping_fedex.php
starting on line 668 and Cartthrob_shipping_usps.php
starting on line 797):
function get_shipping()
{
$cart_hash = $this->core->cart->custom_data('cart_hash');
if ($this->core->cart->count() <= 0 || $this->core->cart->shippable_subtotal() <= 0)
{
return 0;
}
[...]
As you can see, if $this->core->cart->shippable_subtotal() <= 0
, 0 is returned as the shipping cost. This is why shipping isn't charged.
So what can we do?
There would need to be some pretty extreme modifications made to the core Cartthrob shipping plugins to fix this issue because it appears all of them use the shippable_subtotal()
method to calculate the final shipping price.
However, for the live rates plugins, I had to modify the core code (which is obviously discouraged) to make this work.
The solution is to remove the $this->core->cart->shippable_subtotal()
check and replace it with count($this->core->cart->shippable_items) === 0
. The new code within the live rates plugins for get_shipping()
would need to be modified to look like so:
function get_shipping()
{
$cart_hash = $this->core->cart->custom_data('cart_hash');
if ($this->core->cart->count() <= 0 || count($this->core->cart->shippable_items()) === 0
{
return 0;
}
[...]
Partial Answer
I recognize this solution is only for the live rates plugins but I wanted to submit the answer because your question wasn't specific on which plugin was being used. I haven't used the built-in shipping plugins so I don't have experience with their code. Someone else may be able to gain insight from my partial answer and expand on it for the built-in plugins.