Skip to content

Incorrect free_shipping flag for virtual products #40184

@gexxx05

Description

@gexxx05

Preconditions and environment

  • Magento version 2.4.7-p4

Steps to reproduce

  1. Create two virtual products (test1, test2) and make them buyable in storefront.
  2. Create a cart price rule for free shipping, add skus from created products and select "For matching items only" in dropdown.
    Image
  3. Go to test1 product detail page and add it to cart with qty 1.
  4. Check field applied_rule_ids for item test1 in quote_item table (should have the id of the sales rule created in step 2)
  5. Check field free_shipping for item test1 in quote_item table (should be 1).
  6. Go to test2 product detail page and add it to cart with qty 1.
  7. Check field applied_rule_ids for item test2 in quote_item table (should have the id of the sales rule created in step 2)
  8. Check field free_shipping for item test2 in quote_item table (should be 1 but is 0).
    Image

Expected result

free_shipping should be 1 for item test2, because the sale rule was applied correctly.

Actual result

free_shipping is 0 for item test2, even if the sale rule was applied correctly.

Additional information

The issue is in method isFreeShipping in file vendor\magento\module-offline-shipping\Model\Quote\Address\FreeShipping.php. If you add a virtual product to the cart, free_shipping is set for both addresses (shipping and billing) to 1:

$shippingAddress->setFreeShipping((int)$result);
$this->applyToItems($items, $result);

If you add another virtual product to the cart, the billing address already has free_shipping set to 1, which breaks the loop:

$this->calculator->processFreeShipping($item);
// at least one item matches to the rule and the rule mode is not a strict
if ((bool)$item->getAddress()->getFreeShipping()) {
    $result = true;
    break;
}

This is because only the shipping address is reset before the loop:

$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setFreeShipping(0);

If we reset the billing address before the loop as well, everything works fine andthe free_shipping flag is correct for every quote_item:

$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setFreeShipping(0);
$billingAddress = $quote->getBillingAddress();
$billingAddress ->setFreeShipping(0);

Perhaps someone thought that the free_shipping flag is irrelevant for virtual products. However, if you rely on this, as we do in one of our custom modules, this behaviour is incorrect.

Release note

No response

Triage and priority

  • Severity: S0 - Affects critical data or functionality and leaves users without workaround.
  • Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

Metadata

Metadata

Assignees

Labels

Area: Cart & CheckoutComponent: ShippingIssue: ConfirmedGate 3 Passed. Manual verification of the issue completed. Issue is confirmedPriority: P2A defect with this priority could have functionality issues which are not to expectations.Reported on 2.4.7-p4Indicates original Magento version for the Issue report.Reproduced on 2.4.xThe issue has been reproduced on latest 2.4-develop branch

Type

No type

Projects

Status

Ready for Development

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions