3

I have added shipping cost for the orders that are synced from Amazon. For some reason I had to set custom shipping flat price in woo-orders created for Amazon-order. It is done as follow:

    $OrderOBJ = wc_get_order(2343);
    $item = new WC_Order_Item_Shipping();

    $new_ship_price = 10;

    $shippingItem = $OrderOBJ->get_items('shipping');

    $item->set_method_title( "Amazon shipping rate" );
    $item->set_method_id( "amazon_flat_rate:17" );
    $item->set_total( $new_ship_price );
    $OrderOBJ->update_item( $item );

    $OrderOBJ->calculate_totals();
    $OrderOBJ->save()

The problem is, I have to update orders in each time the status is changed in Amazon, there is no problem doing that, problem is I have to update the shipping cost also if it is updated. But I have not found anyway to do so. Can anyone tell me how to update the shipping items of orders set in this way? Or is it the fact that, once shipping item is set then we cannot update or delete it?

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
Tekraj Shrestha
  • 1,228
  • 3
  • 20
  • 48

3 Answers3

6

To add or update shipping items use the following:

$order_id = 2343;
$order    = wc_get_order($order_id);
$cost     = 10;
$items    = (array) $order->get_items('shipping');
$country  = $order->get_shipping_country();

// Set the array for tax calculations
$calculate_tax_for = array(
    'country' => $country_code,
    'state' => '', // Can be set (optional)
    'postcode' => '', // Can be set (optional)
    'city' => '', // Can be set (optional)
);

if ( sizeof( $items ) == 0 ) {
    $item  = new WC_Order_Item_Shipping();
    $items = array($item);
    $new_item = true;
}

// Loop through shipping items
foreach ( $items as $item ) {
    $item->set_method_title( __("Amazon shipping rate") );
    $item->set_method_id( "amazon_flat_rate:17" ); // set an existing Shipping method rate ID
    $item->set_total( $cost ); // (optional)

    $item->calculate_taxes( $calculate_tax_for ); // Calculate taxes

    if( isset($new_item) && $new_item ) {
        $order->add_item( $item );
    } else {
        $item->save()
    }
}
$order->calculate_totals();

It should better work…


To remove shipping items use te following:

$order_id = 2343;
$order    = wc_get_order($order_id);
$items    = (array) $order->get_items('shipping');

if ( sizeof( $items ) > 0 ) {
    // Loop through shipping items
    foreach ( $items as $item_id => $item ) {
        $order->remove_item( $item_id );
    }
    $order->calculate_totals();
}

Related: Add a shipping to an order programmatically in Woocommerce 3

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you for the answer. I did some workaround and implemented it. One question though, in order to just update, I need to delete and add right ? There is no such update in this case right ? – Tekraj Shrestha May 08 '19 at 17:19
  • 1
    @SuzAannshrestha Not necessarily… For instance if delete / create works, keep it that way. I will make some testing later on, to see how update only, could be managed, in the best way. – LoicTheAztec May 08 '19 at 17:35
  • There arose a simple problem while implementing it. While adding shipping amount this way, if vat is allowed it automatically adds the vat amount and increases the total shipping price. Is there any way that I can exclude vat in shipping ? thanks. – Tekraj Shrestha May 14 '19 at 10:18
  • 2
    @SuzAannshrestha So in this case don't use `$item->calculate_taxes()`, so remove it. Instead add those two lines: `$item->set_taxes(['total' => []]);` and `$item-> set_total_tax(0);` that will null taxes for shipping items. – LoicTheAztec May 14 '19 at 15:08
  • When I added these two lines, an error popup, which said, cannot use protected function as 'set_total_tax' is protected. While seeing set_taxes() function I saw it used set_total_tax, so I tried to send 0 value like this $shipping->set_taxes(['total' => [0]]); but it doesn't sets VAT 0. its still 20 % – Tekraj Shrestha May 16 '19 at 06:38
  • @SuzAannshrestha so just set the tax total amount to zero `$item-> set_total_tax(0);` – LoicTheAztec May 16 '19 at 07:12
  • $item-> set_total_tax(0); this cannot be accessed from my plugin as it is protected function – Tekraj Shrestha May 16 '19 at 07:36
  • Also this tax is set to 0 with $shipping->set_taxes(['total' => [0]]); too, but when $ord->calculate_totals(); all the taxes are reupdated. foreach ($this->get_shipping_methods() as $item_id => $item) { if (false !== $shipping_tax_class && !$is_vat_exempt) { $item->calculate_taxes(array_merge($calculate_tax_for, array('tax_class' => $shipping_tax_class))); } else { $item->set_taxes(false); } } – Tekraj Shrestha May 16 '19 at 07:37
  • If I comment foreach ($this->get_shipping_methods() as $item_id => $item) { /*if (false !== $shipping_tax_class && !$is_vat_exempt) { $item->calculate_taxes(array_merge($calculate_tax_for, array('tax_class' => $shipping_tax_class))); } else {*/ $item->set_taxes(false); //} } like this, the tax is not added, and works fine. – Tekraj Shrestha May 16 '19 at 07:38
  • @SuzAannshrestha So the problem is in your tax rate settings for shipping… You should not tick the optional checkbox "shipping" on all your tax rates settings. – LoicTheAztec May 16 '19 at 07:41
  • So there is no way to exclude tax inclusion if shipping is checked in tax rate ? – Tekraj Shrestha May 16 '19 at 07:43
  • @SuzAannshrestha If you have set in your tax rates the option for shipping, that mean that shipping is taxable, so when using calculate_totals() method, woocommerce will always set taxes for shipping items. **For now I don't know how you can make to avoid that.** – LoicTheAztec May 16 '19 at 07:47
  • So what is the best way to make a workaround ? I must tick shipping because when order is created from woocommerce it must be added. I need to exclude it when orders are created from my plugins codes. – Tekraj Shrestha May 16 '19 at 07:49
1

The WC_Order_Item_Shipping object can be added to an order using either of 2 methods.

  1. WC_ORDER->add_shipping( WC_Order_Item_Shipping ) This is deprecated in WooCommerce V3.
  2. WC_ORDER->add_item( WC_Order_Item_Shipping )

If you need to persist this change on the database then use WC_ORDER->save();

References: woocommerce.github.io.../#add_shipping woocommerce.github.io.../#add_item

Samuel Nwaokoro
  • 154
  • 1
  • 11
1

Just get order and delete item by id

$ordr_id = 4414;
$item_id = 986;

$order = wc_get_order($ordr_id);
$order->remove_item($item_id);
$order->calculate_totals();
White Shot
  • 115
  • 4