Skip to content

Commit c74830d

Browse files
committed
MAGETWO-59249: [Backport] - [GitHub] Free shipping rule with table shipping method breaks checkout #6346 - for 2.0
1 parent 18abc3c commit c74830d

File tree

5 files changed

+201
-29
lines changed

5 files changed

+201
-29
lines changed

app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Magento\Framework\Exception\LocalizedException;
99
use Magento\Quote\Model\Quote\Address\RateRequest;
1010

11+
/**
12+
* Table rate shipping model.
13+
*/
1114
class Tablerate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements
1215
\Magento\Shipping\Model\Carrier\CarrierInterface
1316
{
@@ -151,25 +154,32 @@ public function collectRates(RateRequest $request)
151154
$request->setPackageQty($oldQty);
152155

153156
if (!empty($rate) && $rate['price'] >= 0) {
154-
/** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
155-
$method = $this->_resultMethodFactory->create();
156-
157-
$method->setCarrier('tablerate');
158-
$method->setCarrierTitle($this->getConfigData('title'));
159-
160-
$method->setMethod('bestway');
161-
$method->setMethodTitle($this->getConfigData('name'));
162-
163157
if ($request->getFreeShipping() === true || $request->getPackageQty() == $freeQty) {
164158
$shippingPrice = 0;
165159
} else {
166160
$shippingPrice = $this->getFinalPriceWithHandlingFee($rate['price']);
167161
}
168162

169-
$method->setPrice($shippingPrice);
170-
$method->setCost($rate['cost']);
163+
$method = $this->createShippingMethod($shippingPrice, $rate['cost']);
171164

172165
$result->append($method);
166+
} elseif (empty($rate) && $request->getFreeShipping() === true || $request->getPackageQty() == $freeQty) {
167+
168+
/**
169+
* Promotion rule was applied for the whole cart.
170+
* In this case all other shipping methods could be omitted.
171+
* Table rate shipping method with 0$ price must be shown if grand total is more than minimal value.
172+
* Free package weight has been already taken into account.
173+
*/
174+
$request->setPackageValue($freePackageValue);
175+
$request->setPackageQty($freeQty);
176+
177+
$rate = $this->getRate($request);
178+
179+
if (!empty($rate) && $rate['price'] >= 0) {
180+
$method = $this->createShippingMethod(0, 0);
181+
$result->append($method);
182+
}
173183
} else {
174184
/** @var \Magento\Quote\Model\Quote\Address\RateResult\Error $error */
175185
$error = $this->_rateErrorFactory->create(
@@ -233,12 +243,33 @@ public function getCode($type, $code = '')
233243
}
234244

235245
/**
236-
* Get allowed shipping methods
246+
* Get allowed shipping methods.
237247
*
238248
* @return array
239249
*/
240250
public function getAllowedMethods()
241251
{
242252
return ['bestway' => $this->getConfigData('name')];
243253
}
254+
255+
/**
256+
* Get the method object based on the shipping price and cost.
257+
*
258+
* @param float $shippingPrice
259+
* @param float $cost
260+
* @return \Magento\Quote\Model\Quote\Address\RateResult\Method
261+
*/
262+
private function createShippingMethod($shippingPrice, $cost)
263+
{
264+
/** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
265+
$method = $this->_resultMethodFactory->create();
266+
$method->setCarrier('tablerate');
267+
$method->setCarrierTitle($this->getConfigData('title'));
268+
$method->setMethod('bestway');
269+
$method->setMethodTitle($this->getConfigData('name'));
270+
$method->setPrice($shippingPrice);
271+
$method->setCost($cost);
272+
273+
return $method;
274+
}
244275
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
8+
$resource = $objectManager->get(\Magento\Framework\App\ResourceConnection::class);
9+
$connection = $resource->getConnection();
10+
$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class);
11+
$entityTable = $resourceModel->getTable('shipping_tablerate');
12+
$data = [
13+
'website_id' => 1,
14+
'dest_country_id' => 'US',
15+
'dest_region_id' => 0,
16+
'dest_zip' => '*',
17+
'condition_name' => 'package_qty',
18+
'condition_value' => 1,
19+
'price' => 10,
20+
'cost' => 10,
21+
];
22+
$connection->query(
23+
"INSERT INTO {$entityTable} (`website_id`, `dest_country_id`, `dest_region_id`, `dest_zip`, `condition_name`,"
24+
. "`condition_value`, `price`, `cost`) VALUES (:website_id, :dest_country_id, :dest_region_id, :dest_zip,"
25+
. " :condition_name, :condition_value, :price, :cost);",
26+
$data
27+
);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
8+
$resource = $objectManager->get(\Magento\Framework\App\ResourceConnection::class);
9+
$connection = $resource->getConnection();
10+
$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class);
11+
$entityTable = $resourceModel->getTable('shipping_tablerate');
12+
$connection->query("DELETE FROM {$entityTable};");
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Quote\Model;
8+
9+
/**
10+
* Test Shipping Method Management.
11+
*/
12+
class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase
13+
{
14+
/**
15+
* @magentoAppIsolation enabled
16+
* @magentoDbIsolation enabled
17+
* @magentoConfigFixture current_store carriers/tablerate/active 1
18+
* @magentoConfigFixture current_store carriers/tablerate/condition_name package_qty
19+
* @magentoDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php
20+
* @magentoDataFixture Magento/Sales/_files/quote.php
21+
* @magentoDataFixture Magento/OfflineShipping/_files/tablerates.php
22+
*/
23+
public function testEstimateByAddressWithCartPriceRule()
24+
{
25+
$this->executeTestFlow(0, 0);
26+
}
27+
28+
/**
29+
* @magentoAppIsolation enabled
30+
* @magentoDbIsolation enabled
31+
* @magentoConfigFixture current_store carriers/tablerate/active 1
32+
* @magentoConfigFixture current_store carriers/tablerate/condition_name package_qty
33+
* @magentoDataFixture Magento/Sales/_files/quote.php
34+
* @magentoDataFixture Magento/OfflineShipping/_files/tablerates.php
35+
*/
36+
public function testEstimateByAddress()
37+
{
38+
$this->executeTestFlow(5, 10);
39+
}
40+
41+
/**
42+
* Provide testing of shipping method estimation based on address.
43+
*
44+
* @param int $flatRateAmount
45+
* @param int $tableRateAmount
46+
* @return void
47+
*/
48+
private function executeTestFlow($flatRateAmount, $tableRateAmount)
49+
{
50+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
51+
52+
/** @var \Magento\Quote\Model\Quote $quote */
53+
$quote = $objectManager->get(\Magento\Quote\Model\Quote::class);
54+
$quote->load('test01', 'reserved_order_id');
55+
56+
$cartId = $quote->getId();
57+
58+
if (!$cartId) {
59+
$this->fail('quote fixture failed');
60+
}
61+
62+
/** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */
63+
$quoteIdMask = $objectManager->create(\Magento\Quote\Model\QuoteIdMaskFactory::class)
64+
->create();
65+
$quoteIdMask->load($cartId, 'quote_id');
66+
67+
//Use masked cart Id
68+
$cartId = $quoteIdMask->getMaskedId();
69+
70+
$data = [
71+
'data' => [
72+
'country_id' => "US",
73+
'postcode' => null,
74+
'region' => null,
75+
'region_id' => null,
76+
],
77+
];
78+
79+
/** @var \Magento\Quote\Api\Data\EstimateAddressInterface $address */
80+
$address = $objectManager->create(\Magento\Quote\Api\Data\EstimateAddressInterface::class, $data);
81+
82+
/** @var \Magento\Quote\Api\GuestShippingMethodManagementInterface $shippingEstimation */
83+
$shippingEstimation = $objectManager->get(\Magento\Quote\Api\GuestShippingMethodManagementInterface::class);
84+
85+
$result = $shippingEstimation->estimateByAddress($cartId, $address);
86+
87+
$this->assertNotEmpty($result);
88+
89+
$expectedResult = [
90+
'tablerate' => [
91+
'method_code' => 'bestway',
92+
'amount' => $tableRateAmount,
93+
],
94+
'flatrate' => [
95+
'method_code' => 'flatrate',
96+
'amount' => $flatRateAmount,
97+
],
98+
];
99+
100+
foreach ($result as $rate) {
101+
$this->assertEquals($expectedResult[$rate->getCarrierCode()]['amount'], $rate->getAmount());
102+
$this->assertEquals($expectedResult[$rate->getCarrierCode()]['method_code'], $rate->getMethodCode());
103+
}
104+
}
105+
}

dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@
1616
'customer_group_ids' => [\Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID],
1717
'coupon_type' => \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
1818
'conditions' => [
19-
1 =>
20-
[
21-
'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class,
22-
'attribute' => null,
23-
'operator' => null,
24-
'value' => '1',
25-
'is_value_processed' => null,
26-
'aggregator' => 'all',
27-
]
28-
19+
1 => [
20+
'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class,
21+
'attribute' => null,
22+
'operator' => null,
23+
'value' => '1',
24+
'is_value_processed' => null,
25+
'aggregator' => 'all',
26+
],
2927
],
3028
'actions' => [
3129
1 => [
@@ -42,9 +40,9 @@
4240
'operator' => '==',
4341
'value' => '7',
4442
'is_value_processed' => false,
45-
]
46-
]
47-
]
43+
],
44+
],
45+
],
4846
],
4947
'is_advanced' => 1,
5048
'simple_action' => 'by_percent',
@@ -58,17 +56,16 @@
5856
'use_auto_generation' => 0,
5957
'uses_per_coupon' => 0,
6058
'simple_free_shipping' => 1,
61-
6259
'website_ids' => [
63-
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
60+
$objectManager->get(
6461
\Magento\Store\Model\StoreManagerInterface::class
6562
)->getWebsite()->getId()
66-
]
63+
],
6764
];
6865
$salesRule->loadPost($row);
6966
$salesRule->save();
67+
7068
/** @var Magento\Framework\Registry $registry */
7169
$registry = $objectManager->get(\Magento\Framework\Registry::class);
72-
7370
$registry->unregister('cart_rule_free_shipping');
7471
$registry->register('cart_rule_free_shipping', $salesRule);

0 commit comments

Comments
 (0)