2

I have a magento script that runs from command line that needs to get a price quote based off of the weight of an item. (Feel free to improve any of this script) I don't want to adjust the weight in the database but I want to adjust it for when I get the shipping quote.

<?php
setlocale(LC_MONETARY, 'en_US');
require_once("/usr/share/nginx/html/app/Mage.php");
umask(0);
ini_set('display_errors',true); Mage::setIsDeveloperMode(true);

Mage::app('admin')->setUseSessionInUrl(false);
$userModel = Mage::getModel('admin/user');
$userModel->setUserId(0);
Mage::getSingleton('admin/session')->setUser($userModel);

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$aprox='';

//Mage::app();
$mask = " %7s | %-30s | %-15s | %-30s \n";
// Need to figure out how to temporarily adjust a products weight without saving it.
function calculate_weight($weight){
        // If under 1lb 1.5 x $weight
        // If 1lb to 5lbs 1.25 x $weight
        // If 5lb+ 1.2 x $weight
        if ($weight < 1) { return $weight * 1.5;}
        elseif ($weight < 5) { return $weight * 1.25;}
        else return $weight * 1.2;
    }
function getShippingEstimate($productId,$productQty,$countryId,$postcode ) {
    global $mask, $aprox;
    $quote = Mage::getModel('sales/quote')->setStoreId(Mage::app()->getStore('default')->getId());
    //Check if is SKU or Number.
    if (is_numeric($productId)){

        $_product = Mage::getModel('catalog/product')->load($productId);

    } else
    {

        $model = Mage::getModel('catalog/product');
        $product_id = $model->getIdBySku($productId);
        $_product = $model->load($product_id);
        //var_dump($prod);
        //exit;
    }
    $cost = $_product->getCost();
    $name = $_product->getName();
    $minPriceWithShipping = $_product->getMinPriceWithShipping();
    $shippingPrice = $_product->getShippingPrice();
    $aprox = $shippingPrice+($cost*$productQty);
    printf($mask, number_format((float)$cost, 2, '.',''), $name, number_format((float)$minPriceWithShipping, 2, '.',''),number_format((float)$aprox, 2, '.','') . '  QTY:'.$productQty);
    $_product->getStockItem()->setUseConfigManageStock(false);
    $_product->getStockItem()->setManageStock(false);

    $weight = $_product->getWeight();

    if ($weight <= 0) { echo $weight; return 9999.99; }
    // php getShipping.php ons6467 1 57.87   1.6000 Weight

    echo $weight." Weight \n";
    $weight = calculate_weight($weight);
    echo $weight." New Weight \n";
    //echo $_product->setWeight($weight);    <---  This breaks th code    I just want to temporarily adjust the weight for calculations
    // Don't want to save Weight

    $quote->addProduct($_product, $productQty);
    $quote->getShippingAddress()->setCountryId($countryId)->setPostcode($postcode)->setRegion('Main');
    $quote->getShippingAddress()->collectTotals();
    $quote->getShippingAddress()->setCollectShippingRates(true);
    $quote->getShippingAddress()->collectShippingRates();

    $_rates = $quote->getShippingAddress()->getShippingRatesCollection();
    $shippingRates = array();
    foreach ($_rates as $_rate):
        if($_rate->getPrice() > 0) {
            $shippingRates[] =  array("Title" => $_rate->getMethodTitle(), "Price" => $_rate->getPrice(), "Carrier" => $_rate->getCarrier(), "Carrier Title" => $_rate->getCarrierTitle());
        }
    endforeach;
    return $shippingRates;

}


// Place this at the very top of script
$start = microtime(TRUE);

// product id, quantity, country, postcode

$c = (isset($argv[2])) ? $argv[2] : 1;

$rates = getShippingEstimate($argv[1] , $c , "US","04652");// Farthest continental USA Zip code from warehouse that I could find.
function sortr($a, $b) {
    return $a['Price'] - $b["Price"];
}


usort($rates, "sortr");

//$fst = array_shift($rates);

// only min-width of cells is set

foreach($rates as $rate){
    printf($mask, number_format((float)$rate['Price'], 2, '.','') , $rate['Title'],strtoupper($rate['Carrier']) ,'');
}
if (isset($argv[3])) { 
    $v= $argv[3]-$aprox;
    echo "$".number_format((float)$v, 2, '.','') . " Estimated Profit. \n"; 
    }

$finish = microtime(TRUE);

// Subtract the start time from the end time to get our difference in seconds
$totaltime = $finish - $start;

echo "This script took ".$totaltime." seconds to run \n";
5
  • Do we know the shipping cost formula? My idea is NOT no change the product weight before, but modify the shipping rates by percentage or table values based on the weight difference. So create some shipping rule formula based on weight adjustment.
    – Amasty
    Commented Jul 23, 2014 at 10:11
  • It uses UPS/FedEx/USPS Api to get the shipping. How would I go about doing your idea with that?
    – Brad
    Commented Jul 23, 2014 at 15:19
  • I see the issue. There was a chance it is table rate or transparent formula.
    – Amasty
    Commented Jul 23, 2014 at 15:33
  • What do you mean by "This breaks th code" on line $_product->setWeight($weight);?
    – Marius
    Commented Jul 31, 2014 at 7:03
  • it causes an error to be thrown when you don't call $_product->save();
    – Brad
    Commented Jul 31, 2014 at 7:09

3 Answers 3

4
+100

Try to use Mage_Shipping_Model_Shipping::collectRates method.

It takes as a parameter shipping request Mage_Shipping_Model_Rate_Request $request

And the request contains total products weight. So you can modify it using your own logic per each product and then sum up.

No need to save anything in the database.

EDIT

Example:

0) remove weight adjustments from the script

1) add Mage::register('my-commad-line-flag',1); in the script beginning.

2) create custom module, that rewrites just one class:

class Amasty_Example_Model_Shipping_Shipping extends Mage_Shipping_Model_Shipping
{
    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
        // apply the rates only when called from the custom script
        if (Mage::registry('my-commad-line-flag')){
            // re-calculate total package weight
            $total = 0;
            foreach($request->getAllItems() as $item){
                // use your function here
                $total += my_custom_weight_adjustment($item->getWeight()) * $item->getQty();
            }
            $request->setPackageWeight($total);

        }

        parent::collectRates($request);

        return $this;
    }    
}
4
  • Do you know where any demo code is to use this. I'm lost trying to figure this out. Thanks
    – Brad
    Commented Jul 25, 2014 at 20:37
  • Works like a charm!
    – Brad
    Commented Aug 1, 2014 at 23:03
  • Nice! Glad to help ;) Does it mean i get the bounty?
    – Amasty
    Commented Aug 2, 2014 at 4:05
  • I thought I gave you the bounty.. :P Yes you earned it! Thanks
    – Brad
    Commented Aug 2, 2014 at 6:41
0

Not Completely sure but we had a similar issue, what we did was created a database field like "NewWeight" and then you can save the temporary weight in there, setNewWeight("10"); that is the easiest and safest way to go around. But if you dont want to use database , as Amasty suggested you can use collectRates,

I dont have full working code with me but it will be something like

public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
    $result = Mage::getModel('shipping/rate_result');
    $result->append($this->_getXYZShippingRate());
    return $result;
}

protected function _getXYZShippingRate()
{
    /**
     *
     */
    $rate = Mage::getModel('shipping/rate_result_method');

    /*put all of your weight cal logic over here and just get the price and cost so you                   dont have to bother with saving the weight of the product"

        $rate->setCarrier("xyz");
        $rate->setCarrierTitle($this->getConfigData('title'));
        $rate->setMethod(XYZ');
        $rate->setMethodTitle("message");
        $rate->setPrice(100); //whatever the price you have calcuated
        $rate->setCost(99); //whatevr the cost



    return $rate;


}

}

0

I think by far the easiest method of achieving the desired functionality is as follows:

in your getShippingEstimate method, round line 58:

....
$weight = calculate_weight($weight);
$old_weight = $_product->getWeight();
$_product->setWeight($weight);
$_product->save(); //temporarily adjust weight

$quote->addProduct($_product, $productQty);
$quote->getShippingAddress()->setCountryId($countryId)->setPostcode($postcode)->setRegion('Main');
$quote->getShippingAddress()->collectTotals();
$quote->getShippingAddress()->setCollectShippingRates(true);
$quote->getShippingAddress()->collectShippingRates();
$_product->setWeight($old_weight);
$_product->save(); //revert to actual weight
....

It's not the most elegant of solutions, but it is a solution nonetheless. Let me know if this is what you're trying to achieve.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.