Skip to content

Commit

Permalink
Merge pull request Sylius#8629 from Zales0123/default-shipping-method…
Browse files Browse the repository at this point in the history
…-fixes

[Shipping][OrderProcessing] Default shipping method fixes
  • Loading branch information
pamil committed May 23, 2018
2 parents 61b8cb5 + 90de95c commit f400ca4
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 17 deletions.
@@ -0,0 +1,41 @@
@checkout
Feature: Seeing default shipping method selected based on shipping address
In order to select correct shipping method for my order
As a Customer
I want to be able to choose only shipping methods that match shipping category of all my items

Background:
Given the store operates on a channel named "Web"
And the store has a product "Star Trek Ship" priced at "$19.99"
And the store ships to "United Kingdom"
And the store ships to "United States"
And the store has a zone "United Kingdom" with code "UK"
And this zone has the "United Kingdom" country member
And the store has a zone "United States" with code "US"
And this zone has the "United States" country member
And the store has "DHL" shipping method with "$10.00" fee within the "US" zone
And the store has "FedEx" shipping method with "$20.00" fee within the "UK" zone
And I am a logged in customer

@ui
Scenario: Seeing default shipping method selected based on country from shipping address
Given I have product "Star Trek Ship" in the cart
And I am at the checkout addressing step
When I specify the shipping address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
And I complete the addressing step
Then I should be on the checkout shipping step
And I should see selected "DHL" shipping method
And I should not see "FedEx" shipping method

@ui
Scenario: Seeing default shipping method selected based on country from shipping address after readdressing
Given I have product "Star Trek Ship" in the cart
And I am at the checkout addressing step
When I specify the shipping address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
And I complete the addressing step
And I decide to change my address
And I specify the shipping address as "Ankh Morpork", "Frost Alley", "90210", "United Kingdom" for "Jon Snow"
And I complete the addressing step
Then I should be on the checkout shipping step
And I should see selected "FedEx" shipping method
And I should not see "DHL" shipping method
Expand Up @@ -191,6 +191,14 @@ public function iShouldSeeShippingMethod($shippingMethodName)
Assert::true($this->selectShippingPage->hasShippingMethod($shippingMethodName));
}

/**
* @Then I should see selected :shippingMethodName shipping method
*/
public function iShouldSeeSelectedShippingMethod($shippingMethodName)
{
Assert::same($this->selectShippingPage->getSelectedShippingMethodName(), $shippingMethodName);
}

/**
* @Then I should not see :shippingMethodName shipping method
*/
Expand Down
19 changes: 19 additions & 0 deletions src/Sylius/Behat/Page/Shop/Checkout/SelectShippingPage.php
Expand Up @@ -14,6 +14,7 @@
namespace Sylius\Behat\Page\Shop\Checkout;

use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\ElementNotFoundException;
use Sylius\Behat\Page\SymfonyPage;

Expand Down Expand Up @@ -57,6 +58,24 @@ public function getShippingMethods()
return $shippingMethods;
}

/**
* {@inheritdoc}
*/
public function getSelectedShippingMethodName(): ?string
{
$shippingMethods = $this->getSession()->getPage()->findAll('css', '#sylius-shipping-methods .item');

/** @var NodeElement $shippingMethod */
foreach ($shippingMethods as $shippingMethod) {
if (null !== $shippingMethod->find('css', 'input:checked')) {
return $shippingMethod->find('css', '.content label')->getText();
}
}

return null;
}


/**
* {@inheritdoc}
*/
Expand Down
Expand Up @@ -27,6 +27,11 @@ public function selectShippingMethod($shippingMethod);
*/
public function getShippingMethods();

/**
* @return string|null
*/
public function getSelectedShippingMethodName(): ?string;

/**
* @return bool
*/
Expand Down
1 change: 1 addition & 0 deletions src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
Expand Up @@ -70,6 +70,7 @@
</service>
<service id="sylius.shipping_method_resolver.default" class="Sylius\Component\Core\Resolver\DefaultShippingMethodResolver">
<argument type="service" id="sylius.repository.shipping_method" />
<argument type="service" id="sylius.zone_matcher" />
</service>
<service id="sylius.updater.order.exchange_rate" class="Sylius\Component\Core\Updater\OrderExchangeRateUpdater">
<argument type="service" id="sylius.repository.currency" />
Expand Down
Expand Up @@ -30,6 +30,7 @@
<service id="sylius.order_processing.order_shipment_processor" class="Sylius\Component\Core\OrderProcessing\OrderShipmentProcessor">
<argument type="service" id="sylius.shipping_method_resolver.default" />
<argument type="service" id="sylius.factory.shipment" />
<argument type="service" id="sylius.shipping_methods_resolver" />
<tag name="sylius.order_processor" priority="50"/>
</service>

Expand Down
Expand Up @@ -20,6 +20,7 @@
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Shipping\Exception\UnresolvedDefaultShippingMethodException;
use Sylius\Component\Shipping\Resolver\DefaultShippingMethodResolverInterface;
use Sylius\Component\Shipping\Resolver\ShippingMethodsResolverInterface;
use Webmozart\Assert\Assert;

final class OrderShipmentProcessor implements OrderProcessorInterface
Expand All @@ -34,16 +35,31 @@ final class OrderShipmentProcessor implements OrderProcessorInterface
*/
private $shipmentFactory;

/**
* @var ShippingMethodsResolverInterface|null
*/
private $shippingMethodsResolver;

/**
* @param DefaultShippingMethodResolverInterface $defaultShippingMethodResolver
* @param FactoryInterface $shipmentFactory
* @param ShippingMethodsResolverInterface|null $shippingMethodsResolver
*/
public function __construct(
DefaultShippingMethodResolverInterface $defaultShippingMethodResolver,
FactoryInterface $shipmentFactory
FactoryInterface $shipmentFactory,
?ShippingMethodsResolverInterface $shippingMethodsResolver = null
) {
$this->defaultShippingMethodResolver = $defaultShippingMethodResolver;
$this->shipmentFactory = $shipmentFactory;
$this->shippingMethodsResolver = $shippingMethodsResolver;

if (2 === func_num_args() || null === $shippingMethodsResolver) {
@trigger_error(
'Not passing ShippingMethodsResolverInterface explicitly is deprecated since 1.2 and will be prohibited in 2.0',
E_USER_DEPRECATED
);
}
}

/**
Expand Down Expand Up @@ -85,7 +101,7 @@ public function process(BaseOrderInterface $order): void
private function getOrderShipment(OrderInterface $order): ?ShipmentInterface
{
if ($order->hasShipments()) {
return $order->getShipments()->first();
return $this->getExistingShipmentWithProperMethod($order);
}

try {
Expand All @@ -101,4 +117,29 @@ private function getOrderShipment(OrderInterface $order): ?ShipmentInterface
return null;
}
}

/**
* @param OrderInterface $order
*
* @return ShipmentInterface|null
*/
private function getExistingShipmentWithProperMethod(OrderInterface $order): ?ShipmentInterface
{
/** @var ShipmentInterface $shipment */
$shipment = $order->getShipments()->first();

if (null === $this->shippingMethodsResolver) {
return $shipment;
}

if (!in_array($shipment->getMethod(), $this->shippingMethodsResolver->getSupportedMethods($shipment), true)) {
try {
$shipment->setMethod($this->defaultShippingMethodResolver->getDefaultShippingMethod($shipment));
} catch (UnresolvedDefaultShippingMethodException $exception) {
return null;
}
}

return $shipment;
}
}
Expand Up @@ -13,6 +13,9 @@

namespace Sylius\Component\Core\Resolver;

use Sylius\Component\Addressing\Matcher\ZoneMatcherInterface;
use Sylius\Component\Addressing\Model\ZoneInterface;
use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ShipmentInterface as CoreShipmentInterface;
use Sylius\Component\Core\Repository\ShippingMethodRepositoryInterface;
Expand All @@ -29,12 +32,28 @@ class DefaultShippingMethodResolver implements DefaultShippingMethodResolverInte
*/
private $shippingMethodRepository;

/**
* @var ZoneMatcherInterface|null
*/
private $zoneMatcher;

/**
* @param ShippingMethodRepositoryInterface $shippingMethodRepository
* @param ZoneMatcherInterface|null $zoneMatcher
*/
public function __construct(ShippingMethodRepositoryInterface $shippingMethodRepository)
{
public function __construct(
ShippingMethodRepositoryInterface $shippingMethodRepository,
?ZoneMatcherInterface $zoneMatcher = null
) {
$this->shippingMethodRepository = $shippingMethodRepository;
$this->zoneMatcher = $zoneMatcher;

if (1 === func_num_args() || null === $zoneMatcher) {
@trigger_error(
'Not passing ZoneMatcherInterface explicitly is deprecated since 1.2 and will be prohibited in 2.0',
E_USER_DEPRECATED
);
}
}

/**
Expand All @@ -45,14 +64,36 @@ public function getDefaultShippingMethod(ShipmentInterface $shipment): ShippingM
/** @var CoreShipmentInterface $shipment */
Assert::isInstanceOf($shipment, CoreShipmentInterface::class);

$order = $shipment->getOrder();

/** @var ChannelInterface $channel */
$channel = $shipment->getOrder()->getChannel();
$channel = $order->getChannel();
/** @var AddressInterface $shippingAddress */
$shippingAddress = $order->getShippingAddress();

$shippingMethods = $this->shippingMethodRepository->findEnabledForChannel($channel);
$shippingMethods = $this->getShippingMethods($channel, $shippingAddress);
if (empty($shippingMethods)) {
throw new UnresolvedDefaultShippingMethodException();
}

return $shippingMethods[0];
}

/**
* @param ChannelInterface $channel
* @param AddressInterface|null $address
*
* @return array|ShippingMethodInterface[]
*/
private function getShippingMethods(ChannelInterface $channel, ?AddressInterface $address): array
{
if (null === $address || null === $this->zoneMatcher) {
return $this->shippingMethodRepository->findEnabledForChannel($channel);
}

/** @var ZoneInterface[] $zones */
$zones = $this->zoneMatcher->matchAll($address);

return $this->shippingMethodRepository->findEnabledForZonesAndChannel($zones, $channel);
}
}

0 comments on commit f400ca4

Please sign in to comment.