mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
[Api][Promotion] Add archivedAt to promotion
This commit is contained in:
parent
d50ec85545
commit
09b1a09f9d
25 changed files with 475 additions and 9 deletions
|
|
@ -10,14 +10,14 @@ Feature: Cart promotions integrity
|
|||
And there is a promotion "Christmas sale"
|
||||
And this promotion gives "$10.00" discount to every order
|
||||
|
||||
@ui
|
||||
@api @ui
|
||||
Scenario: Promotion is applied to the cart when it is valid
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
Then I should be on my cart summary page
|
||||
And I should be notified that the product has been successfully added
|
||||
And my cart total should be "$90.00"
|
||||
|
||||
@ui
|
||||
@api @ui
|
||||
Scenario: Archived promotion is not applied to the cart
|
||||
Given the promotion "Christmas sale" is archived
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Feature: Archiving promotions
|
|||
And there is also a promotion "New Year sale"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui
|
||||
@api @ui
|
||||
Scenario: Archiving a promotion
|
||||
When I browse promotions
|
||||
And I archive the "Christmas sale" promotion
|
||||
|
|
@ -22,7 +22,7 @@ Feature: Archiving promotions
|
|||
When I archive the "Christmas sale" promotion
|
||||
Then the promotion "Christmas sale" should still exist in the registry
|
||||
|
||||
@ui
|
||||
@api @ui
|
||||
Scenario: Seeing only archived promotions
|
||||
Given the promotion "Christmas sale" is archived
|
||||
When I browse promotions
|
||||
|
|
@ -31,7 +31,7 @@ Feature: Archiving promotions
|
|||
And I should see the promotion "Christmas sale" in the list
|
||||
And I should not see the promotion "New Year sale" in the list
|
||||
|
||||
@ui
|
||||
@api @ui
|
||||
Scenario: Restoring an archival promotion
|
||||
Given the promotion "Christmas sale" is archived
|
||||
When I browse promotions
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use Sylius\Component\Core\Promotion\Checker\Rule\HasTaxonRuleChecker;
|
|||
use Sylius\Component\Core\Promotion\Checker\Rule\TotalOfItemsFromTaxonRuleChecker;
|
||||
use Sylius\Component\Customer\Model\CustomerGroupInterface;
|
||||
use Sylius\Component\Promotion\Checker\Rule\ItemTotalRuleChecker;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class ManagingPromotionsContext implements Context
|
||||
|
|
@ -73,6 +74,23 @@ final class ManagingPromotionsContext implements Context
|
|||
$this->client->buildUpdateRequest(Resources::PROMOTIONS, $promotion->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I archive the :promotion promotion
|
||||
*/
|
||||
public function iArchiveThePromotion(PromotionInterface $promotion): void
|
||||
{
|
||||
$this->client->customItemAction(Resources::PROMOTIONS, $promotion->getCode(), Request::METHOD_PATCH, 'archive');
|
||||
$this->client->index(Resources::PROMOTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I restore the :promotion promotion
|
||||
*/
|
||||
public function iRestoreThePromotion(PromotionInterface $promotion): void
|
||||
{
|
||||
$this->client->customItemAction(Resources::PROMOTIONS, $promotion->getCode(), Request::METHOD_PATCH, 'restore');
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify its :field as :value
|
||||
* @When I do not specify its :field
|
||||
|
|
@ -410,6 +428,15 @@ final class ManagingPromotionsContext implements Context
|
|||
$this->client->filter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I filter archival promotions
|
||||
*/
|
||||
public function iFilterArchivalPromotions(): void
|
||||
{
|
||||
$this->client->addFilter('exists[archivedAt]', true);
|
||||
$this->client->filter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I add it
|
||||
* @When I try to add it
|
||||
|
|
@ -456,6 +483,17 @@ final class ManagingPromotionsContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not see the promotion :promotionName in the list
|
||||
*/
|
||||
public function iShouldNotSeeThePromotionInTheList(string $promotionName): void
|
||||
{
|
||||
Assert::false(
|
||||
$this->responseChecker->hasItemWithValue($this->client->getLastResponse(), 'name', $promotionName),
|
||||
sprintf('Promotion with name %s does not exist', $promotionName),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^(this promotion) should be coupon based$/
|
||||
*/
|
||||
|
|
@ -847,6 +885,14 @@ final class ManagingPromotionsContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be viewing non archival promotions
|
||||
*/
|
||||
public function iShouldBeViewingNonArchivalPromotions(): void
|
||||
{
|
||||
$this->client->index(Resources::PROMOTIONS);
|
||||
}
|
||||
|
||||
private function addToRequestAction(string $type, array $configuration): void
|
||||
{
|
||||
$data['actions'][] = [
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ final class ManagingPromotionsContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @When /^I archive the ("[^"]+" promotion)$/
|
||||
* @When I archive the :promotion promotion
|
||||
*/
|
||||
public function iArchiveThePromotion(PromotionInterface $promotion): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ final class PromotionContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @Given /^the (promotion "[^"]+") is archived$/
|
||||
* @Given the promotion :promotion is archived
|
||||
*/
|
||||
public function thisPromotionIsArchived(PromotionInterface $promotion): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ default:
|
|||
- sylius.behat.context.transform.lexical
|
||||
- sylius.behat.context.transform.product
|
||||
- sylius.behat.context.transform.product_variant
|
||||
- sylius.behat.context.transform.promotion
|
||||
- sylius.behat.context.transform.shared_storage
|
||||
- sylius.behat.context.transform.shipping_category
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?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\Applicator;
|
||||
|
||||
use Sylius\Calendar\Provider\DateTimeProviderInterface;
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
|
||||
/** @experimental */
|
||||
final class ArchivingPromotionApplicator implements ArchivingPromotionApplicatorInterface
|
||||
{
|
||||
public function __construct(private DateTimeProviderInterface $calendar)
|
||||
{
|
||||
}
|
||||
|
||||
public function archive(PromotionInterface $data): PromotionInterface
|
||||
{
|
||||
$data->setArchivedAt($this->calendar->now());
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function restore(PromotionInterface $data): PromotionInterface
|
||||
{
|
||||
$data->setArchivedAt(null);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?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\Applicator;
|
||||
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
|
||||
/** @experimental */
|
||||
interface ArchivingPromotionApplicatorInterface
|
||||
{
|
||||
public function archive(PromotionInterface $data): PromotionInterface;
|
||||
|
||||
public function restore(PromotionInterface $data): PromotionInterface;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?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\QueryCollectionExtension;
|
||||
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryCollectionExtensionInterface;
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/** @experimental */
|
||||
final class HideArchivedPromotionExtension implements ContextAwareQueryCollectionExtensionInterface
|
||||
{
|
||||
public function __construct(private string $promotionClass)
|
||||
{
|
||||
}
|
||||
|
||||
public function applyToCollection(
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
string $resourceClass,
|
||||
string $operationName = null,
|
||||
array $context = [],
|
||||
): void {
|
||||
if ($this->promotionClass !== $resourceClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($context['filters']['exists']['archivedAt'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rootAlias = $queryBuilder->getRootAliases()[0];
|
||||
|
||||
$queryBuilder->andWhere($queryBuilder->expr()->isNull(sprintf('%s.archivedAt', $rootAlias)));
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,8 @@
|
|||
<attribute>admin:promotion:show</attribute>
|
||||
<attribute>sylius:admin:promotion:show</attribute>
|
||||
</attribute>
|
||||
<!-- It auto-turned on when adding PATCH itemOperations: https://github.com/api-platform/core/issues/3600 -->
|
||||
<attribute name="skip_null_values">false</attribute>
|
||||
</attribute>
|
||||
<attribute name="openapi_context">
|
||||
<attribute name="description">
|
||||
|
|
@ -81,10 +83,13 @@ Example configuration for `order_fixed_discount` action type:
|
|||
<attribute>admin:promotion:index</attribute>
|
||||
<attribute>sylius:admin:promotion:index</attribute>
|
||||
</attribute>
|
||||
<!-- It auto-turned on when adding PATCH itemOperations: https://github.com/api-platform/core/issues/3600 -->
|
||||
<attribute name="skip_null_values">false</attribute>
|
||||
</attribute>
|
||||
<attribute name="filters">
|
||||
<attribute>sylius.api.promotion_coupon_search_filter</attribute>
|
||||
<attribute>sylius.api.promotion_order_filter</attribute>
|
||||
<attribute>sylius.api.exists_filter.archived_at</attribute>
|
||||
</attribute>
|
||||
</collectionOperation>
|
||||
</collectionOperations>
|
||||
|
|
@ -97,6 +102,8 @@ Example configuration for `order_fixed_discount` action type:
|
|||
<attribute>admin:promotion:show</attribute>
|
||||
<attribute>sylius:admin:promotion:show</attribute>
|
||||
</attribute>
|
||||
<!-- It auto-turned on when adding PATCH itemOperations: https://github.com/api-platform/core/issues/3600 -->
|
||||
<attribute name="skip_null_values">false</attribute>
|
||||
</attribute>
|
||||
</itemOperation>
|
||||
|
||||
|
|
@ -113,6 +120,8 @@ Example configuration for `order_fixed_discount` action type:
|
|||
<attribute>admin:promotion:show</attribute>
|
||||
<attribute>sylius:admin:promotion:show</attribute>
|
||||
</attribute>
|
||||
<!-- It auto-turned on when adding PATCH itemOperations: https://github.com/api-platform/core/issues/3600 -->
|
||||
<attribute name="skip_null_values">false</attribute>
|
||||
</attribute>
|
||||
<attribute name="openapi_context">
|
||||
<attribute name="description">
|
||||
|
|
@ -146,6 +155,37 @@ Example configuration for `order_fixed_discount` action type:
|
|||
</attribute>
|
||||
</itemOperation>
|
||||
|
||||
<itemOperation name="admin_archive">
|
||||
<attribute name="method">PATCH</attribute>
|
||||
<attribute name="path">/promotions/{code}/archive</attribute>
|
||||
<attribute name="input">false</attribute>
|
||||
<attribute name="controller">Sylius\Bundle\ApiBundle\Applicator\ArchivingPromotionApplicatorInterface::archive</attribute>
|
||||
<attribute name="openapi_context">
|
||||
<attribute name="summary">Archives Promotion</attribute>
|
||||
</attribute>
|
||||
<attribute name="normalization_context">
|
||||
<attribute name="groups">
|
||||
<attribute>admin:promotion:read</attribute>
|
||||
<attribute>sylius:admin:promotion:read</attribute>
|
||||
</attribute>
|
||||
</attribute>
|
||||
</itemOperation>
|
||||
<itemOperation name="admin_restore">
|
||||
<attribute name="method">PATCH</attribute>
|
||||
<attribute name="path">/promotions/{code}/restore</attribute>
|
||||
<attribute name="input">false</attribute>
|
||||
<attribute name="controller">Sylius\Bundle\ApiBundle\Applicator\ArchivingPromotionApplicatorInterface::restore</attribute>
|
||||
<attribute name="openapi_context">
|
||||
<attribute name="summary">Restores Archived Promotion</attribute>
|
||||
</attribute>
|
||||
<attribute name="normalization_context">
|
||||
<attribute name="groups">
|
||||
<attribute>admin:promotion:read</attribute>
|
||||
<attribute>sylius:admin:promotion:read</attribute>
|
||||
</attribute>
|
||||
</attribute>
|
||||
</itemOperation>
|
||||
|
||||
<itemOperation name="admin_delete">
|
||||
<attribute name="method">DELETE</attribute>
|
||||
</itemOperation>
|
||||
|
|
|
|||
|
|
@ -198,5 +198,10 @@
|
|||
<group>admin:promotion:update</group>
|
||||
<group>sylius:admin:promotion:update</group>
|
||||
</attribute>
|
||||
|
||||
<attribute name="archivedAt">
|
||||
<group>admin:promotion:read</group>
|
||||
<group>sylius:admin:promotion:read</group>
|
||||
</attribute>
|
||||
</class>
|
||||
</serializer>
|
||||
|
|
|
|||
|
|
@ -33,5 +33,10 @@
|
|||
<service id="Sylius\Bundle\ApiBundle\Applicator\ProductReviewStateMachineTransitionApplicatorInterface" class="Sylius\Bundle\ApiBundle\Applicator\ProductReviewStateMachineTransitionApplicator">
|
||||
<argument id="sm.factory" type="service" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.api.applicator.archiving_promotion" class="Sylius\Bundle\ApiBundle\Applicator\ArchivingPromotionApplicator">
|
||||
<argument type="service" id="Sylius\Calendar\Provider\DateTimeProviderInterface" />
|
||||
</service>
|
||||
<service id="Sylius\Bundle\ApiBundle\Applicator\ArchivingPromotionApplicatorInterface" alias="sylius.api.applicator.archiving_promotion" />
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -140,5 +140,10 @@
|
|||
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
|
||||
<tag name="api_platform.doctrine.orm.query_extension.item" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\HideArchivedPromotionExtension">
|
||||
<argument>%sylius.model.promotion.class%</argument>
|
||||
<tag name="api_platform.doctrine.orm.query_extension.collection" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -410,5 +410,12 @@
|
|||
</argument>
|
||||
<tag name="api_platform.filter" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.api.exists_filter.archived_at" parent="api_platform.doctrine.orm.exists_filter" public="true">
|
||||
<argument type="collection">
|
||||
<argument key="archivedAt" />
|
||||
</argument>
|
||||
<tag name="api_platform.filter" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
<?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\Applicator;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Calendar\Provider\DateTimeProviderInterface;
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
|
||||
final class ArchivingPromotionApplicatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(DateTimeProviderInterface $calendar)
|
||||
{
|
||||
$this->beConstructedWith($calendar);
|
||||
}
|
||||
|
||||
function it_archives_promotion(
|
||||
DateTimeProviderInterface $calendar,
|
||||
PromotionInterface $promotion,
|
||||
): void {
|
||||
$now = new \DateTime();
|
||||
$calendar->now()->willReturn($now);
|
||||
|
||||
$promotion->setArchivedAt($now)->shouldBeCalledOnce();
|
||||
|
||||
$this->archive($promotion)->shouldReturn($promotion);
|
||||
}
|
||||
|
||||
function it_restores_promotion(
|
||||
PromotionInterface $promotion,
|
||||
): void {
|
||||
$promotion->setArchivedAt(null)->shouldBeCalledOnce();
|
||||
|
||||
$this->restore($promotion)->shouldReturn($promotion);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?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\QueryCollectionExtension;
|
||||
|
||||
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
|
||||
final class HideArchivedPromotionExtensionSpec extends ObjectBehavior
|
||||
{
|
||||
function let()
|
||||
{
|
||||
$this->beConstructedWith('promotionClass');
|
||||
}
|
||||
|
||||
function it_does_nothing_if_current_resource_is_not_a_promotion(
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$queryBuilder->getRootAliases()->shouldNotBeCalled();
|
||||
$queryBuilder->andWhere()->shouldNotBeCalled();
|
||||
|
||||
$this->applyToCollection($queryBuilder, $queryNameGenerator, 'taxonClass', 'get', []);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_archived_at_filter_is_already_applied(
|
||||
QueryBuilder $queryBuilder,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$queryBuilder->getRootAliases()->shouldNotBeCalled();
|
||||
$queryBuilder->andWhere()->shouldNotBeCalled();
|
||||
|
||||
$this->applyToCollection($queryBuilder, $queryNameGenerator, 'promotionClass', 'get', ['filters' => ['exists' => ['archivedAt' => 'true']]]);
|
||||
}
|
||||
|
||||
function it_filters_archived_promotions(
|
||||
QueryBuilder $queryBuilder,
|
||||
Expr $expr,
|
||||
QueryNameGeneratorInterface $queryNameGenerator,
|
||||
): void {
|
||||
$queryBuilder->getRootAliases()->willReturn(['o']);
|
||||
|
||||
$expr->isNull('o.archivedAt')->willReturn('o.archivedAt IS NULL');
|
||||
$queryBuilder->expr()->willReturn($expr);
|
||||
$queryBuilder->andWhere('o.archivedAt IS NULL')->shouldBeCalled();
|
||||
|
||||
$this->applyToCollection($queryBuilder, $queryNameGenerator, 'promotionClass', 'get', []);
|
||||
}
|
||||
}
|
||||
|
|
@ -576,6 +576,56 @@ final class PromotionsTest extends JsonApiTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_archives_a_promotion(): void
|
||||
{
|
||||
$fixtures = $this->loadFixturesFromFiles([
|
||||
'authentication/api_administrator.yaml',
|
||||
'channel.yaml',
|
||||
'promotion/promotion.yaml'
|
||||
]);
|
||||
|
||||
/** @var PromotionInterface $promotion */
|
||||
$promotion = $fixtures['promotion_50_off'];
|
||||
|
||||
$this->client->request(
|
||||
method: 'PATCH',
|
||||
uri: sprintf('/api/v2/admin/promotions/%s/archive', $promotion->getCode()),
|
||||
server: $this->headerBuilder()->withJsonLdAccept()->withAdminUserAuthorization('api@example.com')->build(),
|
||||
);
|
||||
|
||||
$this->assertResponse(
|
||||
$this->client->getResponse(),
|
||||
'admin/promotion/archive_promotion',
|
||||
Response::HTTP_OK,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_restore_a_promotion(): void
|
||||
{
|
||||
$fixtures = $this->loadFixturesFromFiles([
|
||||
'authentication/api_administrator.yaml',
|
||||
'channel.yaml',
|
||||
'promotion/promotion.yaml'
|
||||
]);
|
||||
|
||||
/** @var PromotionInterface $promotion */
|
||||
$promotion = $fixtures['promotion_back_to_school'];
|
||||
|
||||
$this->client->request(
|
||||
method: 'PATCH',
|
||||
uri: sprintf('/api/v2/admin/promotions/%s/restore', $promotion->getCode()),
|
||||
server: $this->headerBuilder()->withJsonLdAccept()->withAdminUserAuthorization('api@example.com')->build(),
|
||||
);
|
||||
|
||||
$this->assertResponse(
|
||||
$this->client->getResponse(),
|
||||
'admin/promotion/restore_promotion',
|
||||
Response::HTTP_OK,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_deletes_a_promotion(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,18 @@ Sylius\Component\Core\Model\Promotion:
|
|||
couponBased: true
|
||||
translations:
|
||||
- '@promotion_1_off_en'
|
||||
promotion_back_to_school:
|
||||
code: 'back_to_school'
|
||||
name: 'Back to school'
|
||||
description: 'Get 10% off on all school supplies'
|
||||
channels: ['@channel_web', '@channel_mobile']
|
||||
priority: 3
|
||||
exclusive: false
|
||||
appliesToDiscounted: true
|
||||
couponBased: false
|
||||
archivedAt: <dateTimeBetween('-1 month', 'now')>
|
||||
translations:
|
||||
- '@promotion_back_to_school_en'
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionTranslation:
|
||||
promotion_50_off_en:
|
||||
|
|
@ -33,6 +45,10 @@ Sylius\Component\Promotion\Model\PromotionTranslation:
|
|||
locale: 'en_US'
|
||||
label: '1$ off every item!'
|
||||
translatable: '@promotion_1_off'
|
||||
promotion_back_to_school_en:
|
||||
locale: 'en_US'
|
||||
label: 'Back to school sale!'
|
||||
translatable: '@promotion_back_to_school'
|
||||
|
||||
Sylius\Component\Core\Model\PromotionCoupon:
|
||||
promotion_1_off_coupon_1:
|
||||
|
|
|
|||
32
tests/Api/Responses/admin/promotion/archive_promotion.json
Normal file
32
tests/Api/Responses/admin/promotion/archive_promotion.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/Promotion",
|
||||
"@id": "\/api\/v2\/admin\/promotions\/50_off",
|
||||
"@type": "Promotion",
|
||||
"channels": [
|
||||
"\/api\/v2\/admin\/channels\/MOBILE"
|
||||
],
|
||||
"id": @integer@,
|
||||
"code": "50_off",
|
||||
"name": "50% Off on your first order",
|
||||
"description": "Get 50% off of your first purchase",
|
||||
"priority": 1,
|
||||
"exclusive": true,
|
||||
"usageLimit": 1,
|
||||
"used": 0,
|
||||
"couponBased": false,
|
||||
"coupons": [],
|
||||
"rules": [],
|
||||
"actions": [],
|
||||
"appliesToDiscounted": false,
|
||||
"archivedAt": @date@,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
"en_US": {
|
||||
"@id": "\/api\/v2\/admin\/promotion-translations\/@integer@",
|
||||
"@type": "PromotionTranslation",
|
||||
"id": @integer@,
|
||||
"label": "-50% on first order!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
"coupons": [],
|
||||
"rules": [],
|
||||
"actions": [],
|
||||
"archivedAt": null,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
],
|
||||
"rules": [],
|
||||
"actions": [],
|
||||
"archivedAt": null,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
"coupons": [],
|
||||
"rules": [],
|
||||
"actions": [],
|
||||
"archivedAt": null,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
|
|
@ -75,7 +77,7 @@
|
|||
"hydra:totalItems": 2,
|
||||
"hydra:search": {
|
||||
"@type": "hydra:IriTemplate",
|
||||
"hydra:template": "\/api\/v2\/admin\/promotions{?coupons.code,coupons.code[],order[priority]}",
|
||||
"hydra:template": "\/api\/v2\/admin\/promotions{?coupons.code,coupons.code[],order[priority],exists[archivedAt]}",
|
||||
"hydra:variableRepresentation": "BasicRepresentation",
|
||||
"hydra:mapping": [
|
||||
{
|
||||
|
|
@ -95,6 +97,12 @@
|
|||
"variable": "order[priority]",
|
||||
"property": "priority",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"@type": "IriTemplateMapping",
|
||||
"variable": "exists[archivedAt]",
|
||||
"property": "archivedAt",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"exclusive": true,
|
||||
"usageLimit": 3,
|
||||
"used": 0,
|
||||
"archivedAt": null,
|
||||
"startsAt": "2023-10-04 12:30:00",
|
||||
"endsAt": "2023-11-04 12:30:00",
|
||||
"couponBased": true,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"exclusive": true,
|
||||
"usageLimit": 11,
|
||||
"used": 0,
|
||||
"archivedAt": null,
|
||||
"startsAt": null,
|
||||
"endsAt": null,
|
||||
"couponBased": false,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"code": "50_off",
|
||||
"name": "50% Off on your first order",
|
||||
"description": "Get 50% off of your first purchase",
|
||||
"priority": 2,
|
||||
"priority": 3,
|
||||
"exclusive": true,
|
||||
"usageLimit": 1,
|
||||
"used": 0,
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
"rules": [],
|
||||
"actions": [],
|
||||
"appliesToDiscounted": false,
|
||||
"archivedAt": null,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
|
|
|
|||
31
tests/Api/Responses/admin/promotion/restore_promotion.json
Normal file
31
tests/Api/Responses/admin/promotion/restore_promotion.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/Promotion",
|
||||
"@id": "\/api\/v2\/admin\/promotions\/back_to_school",
|
||||
"@type": "Promotion",
|
||||
"channels": [
|
||||
"\/api\/v2\/admin\/channels\/WEB",
|
||||
"\/api\/v2\/admin\/channels\/MOBILE"
|
||||
],
|
||||
"id": @integer@,
|
||||
"code": "back_to_school",
|
||||
"name": "Back to school",
|
||||
"description": "Get 10% off on all school supplies",
|
||||
"priority": 3,
|
||||
"exclusive": false,
|
||||
"used": 0,
|
||||
"couponBased": false,
|
||||
"coupons": [],
|
||||
"rules": [],
|
||||
"actions": [],
|
||||
"appliesToDiscounted": true,
|
||||
"createdAt": @date@,
|
||||
"updatedAt": @date@,
|
||||
"translations": {
|
||||
"en_US": {
|
||||
"@id": "\/api\/v2\/admin\/promotion-translations\/@integer@",
|
||||
"@type": "PromotionTranslation",
|
||||
"id": @integer@,
|
||||
"label": "Back to school sale!"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue