Calculating shipping charges by weight

Hi, i'm pretty new to Drupal Commerce. At my internship they asked me to do research about Drupal and webshops. So i started looking into Drupal Commerce.

I need a module, or a way without having to edit code, to calculate a shipping price by weight.
I already added the weight field everywhere I could. And now I'm trying to figure out the Commerce Shipping module, but somehow it won't work.
I added a condition 'entity has field' to get the weight in a variable. But it won't make any calculations. If I add 40 to the price, it will work, but if I try to add weight*3 it won't work.

I alse need a way to have promotions on products. So the original price has to be crossed out and the new one has to be shown, so the buyer knows he is getting a good deal. I've tried Commerce Price Savings Formatter, but it only shows the promotion on the detail page of a product. I tried to edit the rule for this promotion, but since my knowledge about Drupal isn't that big I couldn't get that fixed.

Anyone who can help me?
Next week is my last week at the internship, so I hope I'll find a sollution fast.

Posted: Dec 17, 2011


rfay Randy Fay on December 17, 2011

Did you already see these screencasts?

* [Introduction to Commerce Shipping](http://www.commerceguys.com/resources/articles/246)
* [Commerce UPS](http://www.commerceguys.com/resources/articles/247) which explains the standard ways of handling weight and dimensions.
* [Free shipping based on order total and role](http://www.commerceguys.com/resources/articles/248)
* [Adding calculation rules](http://www.commerceguys.com/resources/articles/249)

You'll find some other resources in those tutorials on http://commerceguys.com that explain various kinds of promotions. [Commerce Discount Campaign Feature](http://www.commerceguys.com/resources/articles/252) may give you some ideas about your campaigns.

marcmarc on December 17, 2011

Yes, I've watched them all. The screencasts helped, but I still couldn't realise what I need.

And my traineeship doesn't want me to use the UPS module. I think this is because they want to be able to choose different shipping services.

For the last 4 days I've read and watched all the information I could find, nothing helped.

marcmarc on December 18, 2011

Wow, thanks for the screencast, I didn't expect this.
I'll try out it immediately.

Thanks again ! Much appreciated.
I'll put this in my report, so my traineeship knows there's an amazing support for Drupal Commerce.

Laurent Bekaert on January 5, 2012

Hi thanks for this screencast.

I'm new to rules and this got me started.
I'm trying to calculate the shipping cost per weight with thresholds. i.e
7€ for packages lighter than 2kg
9€ for packages between 2kg and 10kg
And 11€ for packages between 10kg and 30kg.

30kg is the maximum per package, so that if the total order weights 35kg the cost would need to be 20€.

I'm not sure this can be done with rules... Is it possible? I didn't find how to make the conditional calculation based on the weight of the order.

Do you have any tips/ pointers for me?

Kind regards

dilari on January 18, 2012

Although potentialy everything seems possible, I have a real hard time figuring out this type of conditions.
Rules does not seem to be the best way to achieve such a thing, but what would be an alternative?
My scenario is this:
I have two types of products with each their own properties (weight, dimensions,...). The order can be shipped worldwide. The service we use for this has different rates per weight and also per region( I'm simplifying things here ). We have (roughly) three regions: within the netherlands, within the european union and the rest of the world.(in reality the european union is also subdivided in three different regions, but lets keep it as simple as possible).

I figured what I need to do is setup different 'flat rates' with no actual rate (rate of € 0,-) per region and use conditions using the shipping adres 'country' value to apply the correct service to the order.

So three flatrate services:

  • - shipping within the Netherlands (S1)
  • - shipping within the european union except NL (S2)
  • - shipping outside the european union (S3)

In order to know which of these services to apply I created:

  • S1:
    • - a condition for S1, to see if the country is NL
  • S2:
    • - a condition for S2, negated comparison to the country value of NL
    • - AND
    • - a condition for S2 using a component (conditionSet(OR)) with a list of all the european countries in it (except NL)
  • S3:
    • - a condition for S3, negated comparison to the country value of NL
    • - AND
    • - a condition for S3 using a negated component (conditionSet(OR)) with a list of all the european countries in it (except NL)

This seems to work as expected. When testing, the right service is selected for the shipping address. So far so good.

The next thing to do would be to know the weight of the total order and use that to determine the price category for the current region. There are three categories: up to 2kg, between 2kg and 10kg, and above 10kg.
So I've tried the above hints, but I really can't get it to work together with the defined services or other rules / conditions. I 'm confused about where to use these weight conditions/actions..

So the question is. How to go about this ?

pushka on January 23, 2012

I'd really like to know how to calculate the shipping cost using weight thresholds/sliding scale.

My feeling is that it's not achievable simply using Rules and needs some kind of custom module... :/

pushka on February 2, 2012

aha :)

Apply the patch here to Commerce Physical Product module : http://drupal.org/node/1344962#comment-5261936

Then you can set up a shipping service for each weight bracket (e.g. 0-1kg, 1-2kg) with corresponding cost.

The patch enables you to easily add conditions to each service (e.g. total weight < 1kg and NOT weight < 2kg).

That's it! Note that the patch only handles kg right now.

denisov on February 28, 2012

We got error when trying to import your rules:
Integrity check for the imported configuratoin failed. Error message: Unknown action component_rules_calculate_shipping_amount_by_weight_of_line_item.

If we reproduce step-by-step your screencast we can't get access to 'line-item-calculated-shipping-cost' (09:14 of your video).

Could you help us to understand our mistake?

lesmotspourleweb on July 19, 2012

Thanks a lot for this video !
I would never have found how to do that by myself. The rules for my shop are different (need to calculate the total weight of the shipping before applying the rate) but I think I can do it.

Drupal Commerce is a great project documentation still has to be written. You Commerce Guys are doing a tremendous job for that. My offices are just a few meters from Commerce Guys France; I'll bring them a bottle of champagne to thank you for this video ! ... When the project is finished and the customer has paid me :-)

Robokits on April 4, 2013

Thanks for this. I followed it carefully and although my situation is slightly different I got it to work in the end. Warning, make sure that your variable data types match, if they don't they won't appear in the data selector! This caught me and I spent some time going around in circles until I found what the problem was.

Hitby on April 11, 2013

Thanks for the very informative screencast. I've been struggling with this for some time.
I have followed your instructions on a kickstart 2 site and it appears to be working correctly. The only issue I have is that although the shipping is displayed correctly under SHIPPING SERVICE - Weight based shipping: £36.53. In the breakdown box on the checkout screens it is displayed as Weight based shipping - £XX.XX which shows the standard starting charge and then Shipping - £XX.XX which shows the extra value calculated from the weight. Is it possible to just have a single Weight based shipping field that displays the total cost?

If it isn't is it possible to change the titles around so that the standard charge is called 'shipping' and the extra is called 'weight based shipping' as this would make more sense?

Thanks again for your screencast!

gllphillips on October 19, 2014

Hi Rfay,
Thx to your videos I got so far in Drupal Commerce in just few days. In your video, you add the final shipping price per line item, and got the final shipping total. But I have a different scenario where the shipping amount calculated for the total amount of total line items, not individually, because shipping provider has different rates depending on the total weight ( like first 10kg, $10 each, next each 1kg $8 each). I did the calculation but need to add the amount to the total, not line item each. I tried the action "Apply shipping rate to an order" but it gave me an error "Notice: Undefined offset: 10000 in commerce_shipping_rate_apply() (line 212 of mysite\sites\all\modules\commerce_shipping\commerce_shipping.rules.inc).

Please can anyone help me with this.

marcmarc on December 20, 2011

As last option I tried the screencast again with a clean install of Drupal Commerce and it worked!!

But I have found an error in your screencast. When making the rule "Calculate shipping amount by weight of line item" you say in the screencast to add an Integer datatype labeled 'Shipping cost for a line item', but when I check your exported code, I see it's a Decimal number. You probably changed this in the part you cut out. Maybe you should add this to the videos description, to make sure other people notice this.

Now back to promotions. I will try this again myself on my clean Drupal, and make a new topic if I have any trouble. Do you have suggestions if I should use the campaign tutorial or try some module?

Maybe an admin should change this topic title to 'Shipment by weight' since this is the problem discussed.
Edit: just noticed I can do this myself :)

solstar on March 17, 2012

Good catch on the Decimal number! I wasn't seeing the line-item-calculated-shipping-cost value in the data selector (at around 9:10 in the video) There's so many steps in the process. Since I'm new to rules, I was adhering so closely to Randy Fay's (excellent by the way) step by step instructions, I had overlooked this. You saved me an hour of head scratching. Thanks marcmarc!

edacafa on February 15, 2013

I thought I was going to shoot myself! Finally figure this problem out! thank god there was a link under the video or I'd be lost

Anyway,. thanks!!!!

ShaunP1989 on January 5, 2012

I have just done that, apart from the rounding up to 1kg.

Instead of calculating the price it costs to ship each line item and returning it, you simply just return the weight, then where you previously totaled the price, you total the weight. You'll need to add a variable to store it in. Then after the look is complete you can convert the weight into a price.

I currently have an issue, whereby if I set a condition to check for the country...such that I can provide different shipping rates for different countries. So my test case is setting to check the country code is uk and when I select United Kingdom from the list the shipping doesn't turn up as it should. Any ideas...?

Is there anyway to link a shipping service to a calculation rule?

salapataras on February 17, 2012


I need some help.

If the total weigth of the order is under the limit of 4Kg, I want the total shipping cost to be 5.5€
else the the shipping cost is as the video example.

Please help me...

ñull on March 27, 2012

It should be noted here that not all calculation results are Integer. Assigning a Decimal to an Integer component return value is denied. I had to change the return value to Decimal

jonshot on July 23, 2012

I've seen a few people in the comments asking how to create different shipping bands based on the total weight of a user's shopping cart. I tried doing this myself using built in rules but couldn't figure it out. In the end, I created a custom condition which I could use to compare the total cart weight, much in the same way as it's possible to compare the total quantity of items in the cart.

In a custom module create:

function cartweightcondition_rules_condition_info() {
  return array(
      'commerce_order_compare_total_product_weight' => array(
        'label' => t('Total product weight comparison'),
        'parameter' => array(
          'commerce_order' => array(
            'type' => 'commerce_order',
            'label' => t('Order'),
            'description' => t('The order whose product line item weights should be totalled.
              If the specified order does not exist, the comparison will act as if it is against a weight of 0.'),
          'operator' => array(
            'type' => 'text',
            'label' => t('Operator'),
            'description' => t('The comparison operator to use against the total number of products on the order.'),
            'default value' => '>=',
            'options list' => 'commerce_numeric_comparison_operator_options_list',
            'restriction' => 'input',
          'value' => array(
            'type' => 'text',
            'label' => t('Weight'),
            'default value' => 1,
            'description' => t('The value to compare against the total weight of products on the order.'),
        'group' => t('Commerce Order'),
        'callbacks' => array(
          'execute' => 'cartweightcondition_rules_compare_total_weight',

And then the condition callback itself:

function cartweightcondition_rules_compare_total_weight($order, $operator, $value) {
  if (!empty($order)) {

    $wrapper = entity_metadata_wrapper('commerce_order', $order);          
    $line_items = $wrapper->commerce_line_items;
    if (!empty($line_items)) {          
      $total_weight = 0;
      foreach ($line_items as $line_item) {
        if (!$line_item instanceof EntityMetadataWrapper) {
          $line_item = entity_metadata_wrapper('commerce_line_item', $line_item);
        if($line_item->type->value() == 'product') { 
          $line_item_weight = $line_item->commerce_product->get('field_weight')->value(); //Name of the field containing the product weight.
          $total_weight += $line_item_weight['weight'] * $line_item->quantity->value();

    switch ($operator) {
      case '<':
        return $total_weight < $value;
      case '<=':
        return $total_weight <= $value;
      case '=':
        return $total_weight == $value;
      case '>=':
        return $total_weight >= $value;
      case '>':
        return $total_weight > $value;

  return FALSE;

I hard coded the weight field in the example above, but it should be possible to pass this in to the function as a variable without too much work.

To use the condition, create a new calculation rule and add 'Total product weight comparison' from under 'Commerce Order' as a condition. Choose 'commerce-line-item:order' in the 'Order' data selection and then add an 'Add an amount to the unit price' action and choose 'shipping' as the price component type. repeat for each shipping band and that's it!


sjk413 on September 19, 2012

Hey Jonny,

I like the look of you're module, though I haven't had a chance to try it yet.

I've just got a "Calculate shipping based on bounds of total cart weight" solution working using just standard rules. If anyone's interested in a screencast of how I got this working I'd be happy to throw one together.

If anyone's still struggling with this, let me know and I'll put together a screen cast.

Basically, my configuration does this:

  1. loops through the weights of each product in the cart and totals them.
  2. does a data comparison on that total cart weight
  3. sets a shipping price relevent for which ever bound the falls into

And the best bit... All you need is standard rules!!

baggie on November 20, 2013


I was wondering whether you have got around to that screencast? I'm really stuck and it sounds like you have the perfect solution.


MelindaK on February 4, 2014

I have kinda a same problem. And i have to slove it with grams not with kilos. So if u ready with that screen cast would be awesome.

nelslynn on April 3, 2014

How does one assign a shipping by weight calculations to a SINGLE shipping method? I have multiple shipping methods, Pickup, Delivery and FedEx Ground. I'd like to assign a shipping calculation to the "FedEx Ground" option only. Pickup and Delivery have their own flat rate calculations. Thanks for any help with this.

Anthony Rabot on September 5, 2014

Hi all,

It's my first project on Drupal Commerce. I used Ubercart in the past, so i have a little experience with flats rates.

I split my destinations in 10 groups / zones (Z1 to Z10)

I define my flat rates for slices like Z1 0 to 39kg : 22€, Z1 40kg to 70 Kg : 27€. For this step it's ok.

But for order weight heavier than 100 kg, i have to define a price for 1kg which is multiplied by total weight of order.

For example : Z1 flat rate for 1kg is 0.23€
If total order weight is 200 kg, my flat rate has to be 46€
If total order weight is 250 kg, my flat rate has to be 57,5€ and so on ...

I watched a lot of tutoriels in general from Randy Fay http://vimeo.com/33838479 ... and i can't do it successful.

I imagine i have to use calculations rules but i don't understand what to do in what order.

I don't know if my demand is understandable but i hope some experts will be able to help me.

Thanks in advance and all my apologies for my english.

Have a nice day.