owebia / magento2-module-advanced-shipping

Other
90 stars 28 forks source link

Shipping method for bundle products #93

Closed laura5101 closed 3 years ago

laura5101 commented 3 years ago

Hi there,

We are using the Owebia shipping methods on our Magento site. For the most part they work exceptionally well, but we've had a niche issue crop up and I'm not sure what the best logic is to solve it.

We use Magento's "bundles" to sell products with several components - the components within these bundles are listed as £0 and are each the default component (customers aren't offered a choice). So we might have:

BUNDLE 1 = £30 Component 1 (simple product) = £0 Component 2 (simple product) = £0 Component 3 (simple product) = £0

BUNDLE 2 = £20 Component 1 (simple product) = £0 Component 2 (virtual product) = £0

On the rest of our range we vary the shipping methods we offer based on the number of products in the order - so if you've only ordered one product you can choose Royal Mail or DPD, if you have ordered two products or more you can choose DPD next working day or DPD standard (but not Royal Mail), if you've ordered 5 or more you can only choose DPD standard, etc, etc.

But on bundles, I'm struggling to correctly calculate the number of products in an order - particularly if someone decides to order more than one bundle in an order. The logic needs to count the number of components, not the number of bundles. And to add a final layer of complexity, virtual products also need to be excluded from this count!!

The code I'm using to try and determine the number of products in the order is as follows:

` // Count items in the cart $num_of_all_items = array_sum( array_map( function ( $item ) { return $item->qty; }, $request->all_items ) );

// Count number of virtual products in the cart $num_of_virtual_products = array_sum( array_map( function ( $item ) { if ( $item->product->attribute_set->attribute_set_id == '9' ) return $item->qty; }, $request->all_items ) ); $num_of_all_items = $num_of_all_items - $num_of_virtual_products;

// Count number of bundle parent products in the cart $num_of_bundle_parent_products = array_sum( array_map( function ( $item ) { if ( $item->product_type == 'bundle' ) return $item->qty; }, $request->all_items ) ); $num_of_all_items = $num_of_all_items - $num_of_bundle_parent_products;`

This works fine if there is only one bundle in the order, or only one of each type of bundle. The problem with this code is that Magento doesn't actually add ALL the components to the basket when you add multiple bundles. So if I add 3 x BUNDLE 1 to my cart, Magento adds:

3 x PARENT BUNDLE 1 x COMPONENT 1 1 x COMPONENT 2 1 x COMPONENT 3

So when I come to calculate the number of items using my code above, i get:

$num_of_all_items = 6 $num_of_virtual_products = 0 $num_of_all_items = 6 - 0 = 6 $num_of_bundle_parent_products = 3 $num_of_all_items = 6 - 3 = 3

When the actual answer should be 9 products (12-3 not 6-3)

What is the best way to correctly count the total number of products in an order, so that I can correctly offer the right shipping method based on parcel size???

Many thanks!!

Laura

owebia commented 3 years ago

Hi,

You can try something like this:

$getParentItem = function ($child) use ($request) {
    $parentItemId = $child->parent_item_id;
    if (!$parentItemId) {
        return null;
    }
    $parent = null;
    foreach ($request->all_items as $item) {
        if ($item->item_id == $parentItemId) {
            $parent = $item;
        }
    }
    return $parent;
};

// Count items in the cart
$num_of_all_items = array_sum(
    array_map(
        function ( $item ) use ( $getParentItem, $request ) {
            // Exclude virtual products
            if ($item->product->attribute_set->attribute_set_id == '9') {
                return 0;
            }
            // If the product is a bundle, multiply by the parent's quantity
            $parent = $getParentItem($item);
            return ($parent ? $parent->qty : 1) * $item->qty;
        },
        $request->all_items
    )
);

Please notice that:

This is because the PHP is not executed but transformed into an Abstract Syntax Tree (AST).
The evaluation of the AST has some limitations.

Best Regards, A.L.