mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
[API][Admin] Deleting coupons
This commit is contained in:
parent
41efb5f437
commit
cb3770b564
12 changed files with 265 additions and 5 deletions
|
|
@ -9,7 +9,7 @@ Feature: Deleting a coupon
|
|||
And the store has promotion "Christmas sale" with coupon "SANTA2016"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@domain @ui
|
||||
@domain @ui @api
|
||||
Scenario: Deleted coupon should disappear from the registry
|
||||
When I delete "SANTA2016" coupon related to this promotion
|
||||
Then I should be notified that it has been successfully deleted
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Feature: Not being able to delete a coupon which is in use
|
|||
And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment
|
||||
And I am logged in as an administrator
|
||||
|
||||
@domain @ui
|
||||
@domain @ui @api
|
||||
Scenario: Being unable to delete a used coupon
|
||||
When I try to delete "SANTA2016" coupon related to this promotion
|
||||
Then I should be notified that it is in use and cannot be deleted
|
||||
|
|
|
|||
|
|
@ -805,6 +805,26 @@ parameters:
|
|||
count: 1
|
||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/ProductTaxonDataPersister.php
|
||||
|
||||
-
|
||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\PromotionCouponDataPersister\\:\\:persist\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/PromotionCouponDataPersister.php
|
||||
|
||||
-
|
||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\PromotionCouponDataPersister\\:\\:remove\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/PromotionCouponDataPersister.php
|
||||
|
||||
-
|
||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\PromotionCouponDataPersister\\:\\:remove\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/PromotionCouponDataPersister.php
|
||||
|
||||
-
|
||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\PromotionCouponDataPersister\\:\\:supports\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/PromotionCouponDataPersister.php
|
||||
|
||||
-
|
||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\ProductTaxonDataPersister\\:\\:remove\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
<?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\Behat\Context\Api\Admin;
|
||||
|
|
@ -9,6 +18,7 @@ use Sylius\Behat\Client\ApiClientInterface;
|
|||
use Sylius\Behat\Client\ResponseCheckerInterface;
|
||||
use Sylius\Behat\Context\Api\Resources;
|
||||
use Sylius\Behat\Service\Converter\SectionAwareIriConverterInterface;
|
||||
use Sylius\Component\Core\Model\PromotionCouponInterface;
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
|
|
@ -35,6 +45,15 @@ final class ManagingPromotionCouponsContext implements Context
|
|||
$this->client->filter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I delete ("[^"]+" coupon) related to this promotion$/
|
||||
* @When /^I try to delete ("[^"]+" coupon) related to this promotion$/
|
||||
*/
|
||||
public function iDeleteCouponRelatedToThisPromotion(PromotionCouponInterface $coupon)
|
||||
{
|
||||
$this->client->delete(Resources::PROMOTION_COUPONS, $coupon->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I sort coupons by (ascending|descending) number of uses$/
|
||||
*/
|
||||
|
|
@ -118,6 +137,52 @@ final class ManagingPromotionCouponsContext implements Context
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that it has been successfully deleted
|
||||
*/
|
||||
public function iShouldBeNotifiedThatItHasBeenSuccessfullyDeleted(): void
|
||||
{
|
||||
Assert::true(
|
||||
$this->responseChecker->isDeletionSuccessful($this->client->getLastResponse()),
|
||||
'Promotion coupon could not be deleted',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^(this coupon) should no longer exist in the coupon registry$/
|
||||
*/
|
||||
public function couponShouldNotExistInTheRegistry(PromotionCouponInterface $coupon)
|
||||
{
|
||||
Assert::false($this->responseChecker->hasItemWithValue(
|
||||
$this->client->index(Resources::PROMOTION_COUPONS),
|
||||
'code',
|
||||
$coupon->getCode(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^(this coupon) should still exist in the registry$/
|
||||
*/
|
||||
public function couponShouldStillExistInTheRegistry(PromotionCouponInterface $coupon)
|
||||
{
|
||||
Assert::true($this->responseChecker->hasItemWithValue(
|
||||
$this->client->index(Resources::PROMOTION_COUPONS),
|
||||
'code',
|
||||
$coupon->getCode(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that it is in use and cannot be deleted
|
||||
*/
|
||||
public function iShouldBeNotifiedThatItIsInUseAndCannotBeDeleted(): void
|
||||
{
|
||||
Assert::contains(
|
||||
$this->responseChecker->getError($this->client->getLastResponse()),
|
||||
'Cannot delete, the promotion coupon is in use.',
|
||||
);
|
||||
}
|
||||
|
||||
private function sortBy(string $order, string $field): void
|
||||
{
|
||||
$this->client->sort([$field => str_starts_with($order, 'de') ? 'desc' : 'asc']);
|
||||
|
|
|
|||
|
|
@ -8,12 +8,22 @@ default:
|
|||
- sylius.behat.context.hook.doctrine_orm
|
||||
|
||||
- sylius.behat.context.transform.coupon
|
||||
- sylius.behat.context.transform.address
|
||||
- sylius.behat.context.transform.customer
|
||||
- sylius.behat.context.transform.date_time
|
||||
- sylius.behat.context.transform.lexical
|
||||
- sylius.behat.context.transform.payment
|
||||
- sylius.behat.context.transform.product
|
||||
- sylius.behat.context.transform.promotion
|
||||
- sylius.behat.context.transform.shipping_method
|
||||
- sylius.behat.context.transform.shared_storage
|
||||
|
||||
- sylius.behat.context.setup.channel
|
||||
- sylius.behat.context.setup.payment
|
||||
- sylius.behat.context.setup.product
|
||||
- sylius.behat.context.setup.promotion
|
||||
- sylius.behat.context.setup.shipping
|
||||
- sylius.behat.context.setup.order
|
||||
- sylius.behat.context.setup.admin_api_security
|
||||
|
||||
- sylius.behat.context.api.admin.managing_promotion_coupons
|
||||
|
|
|
|||
|
|
@ -28,6 +28,5 @@ default:
|
|||
- sylius.behat.context.domain.notification
|
||||
- sylius.behat.context.domain.security
|
||||
|
||||
|
||||
filters:
|
||||
tags: "@managing_promotion_coupons&&@domain"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
<?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\DataPersister;
|
||||
|
||||
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Sylius\Bundle\ApiBundle\Exception\PromotionCouponCannotBeRemoved;
|
||||
use Sylius\Component\Core\Model\PromotionCouponInterface;
|
||||
|
||||
/** @experimental */
|
||||
final class PromotionCouponDataPersister implements ContextAwareDataPersisterInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ContextAwareDataPersisterInterface $decoratedDataPersister,
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports($data, array $context = []): bool
|
||||
{
|
||||
return $data instanceof PromotionCouponInterface;
|
||||
}
|
||||
|
||||
public function persist($data, array $context = [])
|
||||
{
|
||||
return $this->decoratedDataPersister->persist($data, $context);
|
||||
}
|
||||
|
||||
public function remove($data, array $context = [])
|
||||
{
|
||||
try {
|
||||
return $this->decoratedDataPersister->remove($data, $context);
|
||||
} catch (ForeignKeyConstraintViolationException) {
|
||||
throw new PromotionCouponCannotBeRemoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?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\Exception;
|
||||
|
||||
/** @experimental */
|
||||
final class PromotionCouponCannotBeRemoved extends \RuntimeException
|
||||
{
|
||||
public function __construct(
|
||||
string $message = 'Cannot delete, the promotion coupon is in use.',
|
||||
int $code = 0,
|
||||
\Throwable $previous = null,
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,10 @@
|
|||
<attribute name="groups">admin:promotion_coupon:read</attribute>
|
||||
</attribute>
|
||||
</itemOperation>
|
||||
|
||||
<itemOperation name="admin_delete">
|
||||
<attribute name="method">DELETE</attribute>
|
||||
</itemOperation>
|
||||
</itemOperations>
|
||||
|
||||
<property name="id" identifier="false" writable="false" />
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@
|
|||
<tag name="api_platform.data_persister" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\PromotionCouponDataPersister">
|
||||
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
|
||||
<tag name="api_platform.data_persister" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\TranslatableDataPersister">
|
||||
<argument type="service" id="sylius.translation_locale_provider" />
|
||||
<tag name="api_platform.data_persister" priority="128" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
<?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\DataPersister;
|
||||
|
||||
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ApiBundle\Exception\PromotionCouponCannotBeRemoved;
|
||||
use Sylius\Component\Core\Model\PromotionCouponInterface;
|
||||
|
||||
final class PromotionCouponDataPersisterSpec extends ObjectBehavior
|
||||
{
|
||||
function let(ContextAwareDataPersisterInterface $dataPersister): void
|
||||
{
|
||||
$this->beConstructedWith($dataPersister);
|
||||
}
|
||||
|
||||
function it_is_a_context_aware_persister(): void
|
||||
{
|
||||
$this->shouldImplement(ContextAwareDataPersisterInterface::class);
|
||||
}
|
||||
|
||||
function it_supports_only_promotion_coupon(PromotionCouponInterface $coupon): void
|
||||
{
|
||||
$this->supports(new \stdClass())->shouldReturn(false);
|
||||
$this->supports($coupon)->shouldReturn(true);
|
||||
}
|
||||
|
||||
function it_uses_inner_persister_to_persist_promotion_coupon(
|
||||
ContextAwareDataPersisterInterface $dataPersister,
|
||||
PromotionCouponInterface $coupon,
|
||||
): void {
|
||||
$dataPersister->persist($coupon, [])->shouldBeCalled();
|
||||
|
||||
$this->persist($coupon);
|
||||
}
|
||||
|
||||
function it_throws_cannot_be_removed_exception_if_constraint_fails_on_removal(
|
||||
ContextAwareDataPersisterInterface $dataPersister,
|
||||
PromotionCouponInterface $coupon,
|
||||
): void {
|
||||
$dataPersister->remove($coupon, [])->willThrow(ForeignKeyConstraintViolationException::class);
|
||||
|
||||
$this->shouldThrow(PromotionCouponCannotBeRemoved::class)->during('remove', [$coupon]);
|
||||
}
|
||||
|
||||
function it_uses_inner_persister_to_remove_promotion_coupon(
|
||||
ContextAwareDataPersisterInterface $dataPersister,
|
||||
PromotionCouponInterface $coupon,
|
||||
): void {
|
||||
$dataPersister->remove($coupon, [])->shouldBeCalled();
|
||||
|
||||
$this->remove($coupon);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Tests\Api\Admin;
|
||||
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
use Sylius\Component\Core\Model\PromotionCouponInterface;
|
||||
use Sylius\Tests\Api\JsonApiTestCase;
|
||||
use Sylius\Tests\Api\Utils\AdminUserLoginTrait;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
|
@ -28,7 +28,7 @@ final class PromotionCouponsTest extends JsonApiTestCase
|
|||
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'promotion.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
/** @var PromotionInterface $promotion */
|
||||
/** @var PromotionCouponInterface $coupon */
|
||||
$coupon = $fixtures['promotion_1_off_coupon_1'];
|
||||
|
||||
$this->client->request(
|
||||
|
|
@ -58,4 +58,22 @@ final class PromotionCouponsTest extends JsonApiTestCase
|
|||
Response::HTTP_OK,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_removes_a_promotion_coupon(): void
|
||||
{
|
||||
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'promotion.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
/** @var PromotionCouponInterface $coupon */
|
||||
$coupon = $fixtures['promotion_1_off_coupon_1'];
|
||||
|
||||
$this->client->request(
|
||||
method: 'DELETE',
|
||||
uri: '/api/v2/admin/promotion-coupons/' . $coupon->getCode(),
|
||||
server: $header,
|
||||
);
|
||||
|
||||
$this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue