mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
Cover preventing to view customers cart from the orders resource
This commit is contained in:
parent
b090f472c6
commit
d6b36dafc9
9 changed files with 304 additions and 6 deletions
|
|
@ -10,7 +10,7 @@ Feature: Being unable to see details of a cart
|
|||
And the customer added "PHP T-Shirt" product to the cart
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui
|
||||
Scenario: Seeing basic information about an order
|
||||
@ui @api
|
||||
Scenario: Being unable to see the details of a cart
|
||||
When I try to view the summary of the customer's latest cart
|
||||
Then I should be informed that the order does not exist
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Sylius\Behat\Context\Api\Admin;
|
|||
use ApiPlatform\Api\IriConverterInterface;
|
||||
use Behat\Behat\Context\Context;
|
||||
use Sylius\Behat\Client\ApiClientInterface;
|
||||
use Sylius\Behat\Client\RequestFactoryInterface;
|
||||
use Sylius\Behat\Client\ResponseCheckerInterface;
|
||||
use Sylius\Behat\Context\Api\Resources;
|
||||
use Sylius\Behat\Context\Api\Subresources;
|
||||
|
|
@ -29,6 +30,7 @@ use Sylius\Component\Core\Model\ChannelInterface;
|
|||
use Sylius\Component\Core\Model\CustomerInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\PaymentMethodInterface;
|
||||
use Sylius\Component\Core\Model\ShipmentInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
use Sylius\Component\Currency\Model\CurrencyInterface;
|
||||
use Sylius\Component\Order\OrderTransitions;
|
||||
|
|
@ -43,6 +45,7 @@ final class ManagingOrdersContext implements Context
|
|||
public function __construct(
|
||||
private ApiClientInterface $client,
|
||||
private ResponseCheckerInterface $responseChecker,
|
||||
private RequestFactoryInterface $requestFactory,
|
||||
private IriConverterInterface $iriConverter,
|
||||
private SecurityServiceInterface $adminSecurityService,
|
||||
private SharedStorageInterface $sharedStorage,
|
||||
|
|
@ -104,6 +107,30 @@ final class ManagingOrdersContext implements Context
|
|||
$this->client->addFilter('checkoutCompletedAt[after]', $dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When specify its tracking code as :trackingCode
|
||||
*/
|
||||
public function specifyItsTrackingCodeAs(string $trackingCode): void
|
||||
{
|
||||
$shipment = $this->sharedStorage->get('order')->getShipments()->first();
|
||||
|
||||
$this->client->buildUpdateRequest(
|
||||
Resources::SHIPMENTS,
|
||||
(string) $shipment->getId(),
|
||||
);
|
||||
|
||||
$this->client->addRequestData('tracking', $trackingCode);
|
||||
$this->client->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I try to view the summary of the (customer's latest cart)$/
|
||||
*/
|
||||
public function iTryToViewTheSummaryOfTheCustomersLatestCart(OrderInterface $cart): void
|
||||
{
|
||||
$this->client->show(Resources::ORDERS, $cart->getTokenValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify filter date to as :dateTime
|
||||
*/
|
||||
|
|
@ -989,6 +1016,77 @@ final class ManagingOrdersContext implements Context
|
|||
Assert::same($this->getTotalAsInt($subTotal), $orderItem['unitPrice'] * $orderItem['quantity'] + $unitPromotionAdjustments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that the order has been successfully shipped
|
||||
*/
|
||||
public function iShouldBeNotifiedThatTheOrderHasBeenSuccessfullyShipped(): void
|
||||
{
|
||||
$response = $this->client->getLastResponse();
|
||||
Assert::true(
|
||||
$this->responseChecker->isUpdateSuccessful($response),
|
||||
'Order could not be shipped. Reason: ' . $response->getContent(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then it should have shipment in state shipped
|
||||
*/
|
||||
public function itShouldHaveShipmentInStateShipped(): void
|
||||
{
|
||||
$shipmentIri = $this->responseChecker->getValue(
|
||||
$this->client->show(Resources::ORDERS, $this->sharedStorage->get('order')->getTokenValue()),
|
||||
'shipments',
|
||||
)[0];
|
||||
|
||||
Assert::true(
|
||||
$this->responseChecker->hasValue($this->client->showByIri($shipmentIri['@id']), 'state', ShipmentInterface::STATE_SHIPPED),
|
||||
sprintf('Shipment for this order is not %s', ShipmentInterface::STATE_SHIPPED),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then this order should have order shipping state :orderShippingState
|
||||
*/
|
||||
public function thisOrderShouldHaveOrderShippingState(string $orderShippingState): void
|
||||
{
|
||||
$ordersResponse = $this->client->index(Resources::ORDERS);
|
||||
|
||||
Assert::true(
|
||||
$this->responseChecker->hasItemWithValue($ordersResponse, 'shippingState', strtolower($orderShippingState)),
|
||||
sprintf('Order does not have %s shipping state', $orderShippingState),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not be able to ship this order
|
||||
*/
|
||||
public function iShouldNotBeAbleToShipThisOrder(): void
|
||||
{
|
||||
$order = $this->sharedStorage->get('order');
|
||||
|
||||
$this->client->applyTransition(
|
||||
Resources::SHIPMENTS,
|
||||
(string) $order->getShipments()->first()->getId(),
|
||||
ShipmentTransitions::TRANSITION_SHIP,
|
||||
);
|
||||
|
||||
Assert::false(
|
||||
$this->responseChecker->isUpdateSuccessful($this->client->getLastResponse()),
|
||||
'Order has been shipped, but should not.',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be informed that the order does not exist
|
||||
*/
|
||||
public function iShouldBeInformedThatTheOrderDoesNotExist(): void
|
||||
{
|
||||
Assert::same(
|
||||
$this->responseChecker->getError($this->client->getLastResponse()),
|
||||
'Not Found',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then there should be :count shipping address changes in the registry
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ final class CartContext implements Context
|
|||
* @Given /^I (?:have|had) (product "[^"]+") in the (cart)$/
|
||||
* @Given /^I have (product "[^"]+") added to the (cart)$/
|
||||
* @Given /^the (?:customer|visitor) has (product "[^"]+") in the (cart)$/
|
||||
* @Given /^the (?:customer|visitor) added ("[^"]+" product) to the (cart)$/
|
||||
* @When /^the (?:customer|visitor) try to add (product "[^"]+") in the customer (cart)$/
|
||||
*/
|
||||
public function iAddedProductToTheCart(ProductInterface $product, ?string $tokenValue): void
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\ApiBundle\Doctrine\QueryExtension;
|
||||
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryCollectionExtensionInterface;
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
|
||||
use Sylius\Component\Core\Model\AdminUserInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
|
||||
/** @experimental */
|
||||
final class OrderExtension implements ContextAwareQueryCollectionExtensionInterface, QueryItemExtensionInterface
|
||||
{
|
||||
/**
|
||||
* @param array<string> $orderStatesToFilterOut
|
||||
*/
|
||||
public function __construct(
|
||||
private UserContextInterface $userContext,
|
||||
private array $orderStatesToFilterOut,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $context
|
||||
*/
|
||||
public function applyToCollection(
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
string $resourceClass,
|
||||
string $operationName = null,
|
||||
array $context = [],
|
||||
): void {
|
||||
if (!is_a($resourceClass, OrderInterface::class, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->userContext->getUser();
|
||||
if ($user instanceof AdminUserInterface && in_array('ROLE_API_ACCESS', $user->getRoles(), true)) {
|
||||
|
||||
$stateParameter = $queryNameGenerator->generateParameterName('state');
|
||||
$rootAlias = $queryBuilder->getRootAliases()[0];
|
||||
|
||||
$queryBuilder
|
||||
->andWhere(sprintf('%s.state != :%s', $rootAlias, $stateParameter))
|
||||
->setParameter($stateParameter, $this->orderStatesToFilterOut)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $context
|
||||
* @param array<mixed> $identifiers
|
||||
*/
|
||||
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []): void
|
||||
{
|
||||
$this->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context);
|
||||
}
|
||||
}
|
||||
|
|
@ -129,6 +129,15 @@
|
|||
<tag name="api_platform.doctrine.orm.query_extension.item" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryExtension\OrderExtension">
|
||||
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
|
||||
<argument type="collection" >
|
||||
<argument type="constant">Sylius\Component\Order\Model\OrderInterface::STATE_CART</argument>
|
||||
</argument>
|
||||
<tag name="api_platform.doctrine.orm.query_extension.collection" />
|
||||
<tag name="api_platform.doctrine.orm.query_extension.item" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryItemExtension\TaxonItemExtension">
|
||||
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
|
||||
<tag name="api_platform.doctrine.orm.query_extension.item" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Bundle\ApiBundle\Doctrine\QueryExtension;
|
||||
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
|
||||
use Sylius\Component\Core\Model\AdminUserInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\ShopUserInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
final class OrderExtensionSpec extends ObjectBehavior
|
||||
{
|
||||
function let(UserContextInterface $userContext): void
|
||||
{
|
||||
$this->beConstructedWith($userContext, ['cart']);
|
||||
}
|
||||
|
||||
function it_does_not_apply_conditions_to_collection_for_shop_user(
|
||||
UserContextInterface $userContext,
|
||||
QueryBuilder $queryBuilder,
|
||||
ShopUserInterface $shopUser,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$userContext->getUser()->willReturn($shopUser);
|
||||
|
||||
$queryBuilder->getRootAliases()->shouldNotBeCalled();
|
||||
|
||||
$this->applyToCollection(
|
||||
$queryBuilder,
|
||||
$queryNameGenerator,
|
||||
OrderInterface::class,
|
||||
Request::METHOD_GET,
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
function it_does_not_apply_conditions_to_item_for_shop_user(
|
||||
UserContextInterface $userContext,
|
||||
QueryBuilder $queryBuilder,
|
||||
ShopUserInterface $shopUser,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$userContext->getUser()->willReturn($shopUser);
|
||||
$queryBuilder->getRootAliases()->shouldNotBeCalled();
|
||||
|
||||
$this->applyToItem(
|
||||
$queryBuilder,
|
||||
$queryNameGenerator,
|
||||
OrderInterface::class,
|
||||
[],
|
||||
Request::METHOD_GET,
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
function it_applies_conditions_to_collection_for_admin(
|
||||
UserContextInterface $userContext,
|
||||
AdminUserInterface $adminUser,
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$userContext->getUser()->willReturn($adminUser);
|
||||
$adminUser->getRoles()->willReturn(['ROLE_API_ACCESS']);
|
||||
|
||||
$queryBuilder->getRootAliases()->willReturn(['o']);
|
||||
|
||||
$queryNameGenerator->generateParameterName('state')->shouldBeCalled()->willReturn('state');
|
||||
$queryBuilder->andWhere('o.state != :state')->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject());
|
||||
$queryBuilder->setParameter('state', ['cart'])->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject());
|
||||
|
||||
$this->applyToCollection(
|
||||
$queryBuilder,
|
||||
$queryNameGenerator,
|
||||
OrderInterface::class,
|
||||
Request::METHOD_GET,
|
||||
);
|
||||
}
|
||||
|
||||
function it_applies_conditions_to_item_for_admin(
|
||||
UserContextInterface $userContext,
|
||||
AdminUserInterface $adminUser,
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$queryBuilder->getRootAliases()->willReturn(['o']);
|
||||
|
||||
$userContext->getUser()->willReturn($adminUser);
|
||||
$adminUser->getRoles()->willReturn(['ROLE_API_ACCESS']);
|
||||
|
||||
$queryBuilder->getRootAliases()->willReturn(['o']);
|
||||
|
||||
$queryNameGenerator->generateParameterName('state')->shouldBeCalled()->willReturn('state');
|
||||
$queryBuilder->andWhere('o.state != :state')->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject());
|
||||
$queryBuilder->setParameter('state', ['cart'])->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject());
|
||||
|
||||
$this->applyToItem(
|
||||
$queryBuilder,
|
||||
$queryNameGenerator,
|
||||
OrderInterface::class,
|
||||
[],
|
||||
Request::METHOD_GET,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -72,8 +72,8 @@ final class OrdersTest extends JsonApiTestCase
|
|||
$fixtures = $this->loadFixturesFromFiles([
|
||||
'authentication/api_administrator.yaml',
|
||||
'channel.yaml',
|
||||
'customer.yaml',
|
||||
'customer_order.yaml',
|
||||
'order/customer.yaml',
|
||||
'order/fulfilled_order.yaml',
|
||||
]);
|
||||
|
||||
/** @var CustomerInterface $customer */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Sylius\Component\Core\Model\Order:
|
|||
currencyCode: "USD"
|
||||
localeCode: "en_US"
|
||||
state: "fulfilled"
|
||||
checkoutState: "fulfilled"
|
||||
tokenValue: "token"
|
||||
customer: "@customer_tony"
|
||||
billingAddress: "@billing_address"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
"shipments": [],
|
||||
"currencyCode": "USD",
|
||||
"localeCode": "en_US",
|
||||
"checkoutState": "cart",
|
||||
"checkoutState": "fulfilled",
|
||||
"paymentState": "cart",
|
||||
"shippingState": "cart",
|
||||
"tokenValue": "token",
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
"items": [],
|
||||
"itemsTotal": 0,
|
||||
"total": 0,
|
||||
"state": "new",
|
||||
"state": "fulfilled",
|
||||
"itemsSubtotal": 0,
|
||||
"taxTotal": 0,
|
||||
"shippingTaxTotal": 0,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue