diff --git a/features/channel/managing_channels/adding_channel.feature b/features/channel/managing_channels/adding_channel.feature
index 30b6d2ef91..aa48daf64c 100644
--- a/features/channel/managing_channels/adding_channel.feature
+++ b/features/channel/managing_channels/adding_channel.feature
@@ -16,6 +16,7 @@ Feature: Adding a new channel
And I specify its code as "MOBILE"
And I name it "Mobile channel"
And I choose "Euro" as the base currency
+ And I make it available in "English (United States)"
And I choose "English (United States)" as a default locale
And I select the "Order items based" as tax calculation strategy
And I add it
@@ -33,6 +34,7 @@ Feature: Adding a new channel
And I set its contact phone number as "11331122"
And I define its color as "blue"
And I choose "Euro" as the base currency
+ And I make it available in "English (United States)"
And I choose "English (United States)" as a default locale
And I choose "United States" and "Poland" as operating countries
And I select the "Order items based" as tax calculation strategy
diff --git a/features/channel/managing_channels/adding_channel_with_shop_billing_data.feature b/features/channel/managing_channels/adding_channel_with_shop_billing_data.feature
index 6c6ea0eee4..dd3e351a7f 100644
--- a/features/channel/managing_channels/adding_channel_with_shop_billing_data.feature
+++ b/features/channel/managing_channels/adding_channel_with_shop_billing_data.feature
@@ -16,6 +16,7 @@ Feature: Adding a new channel with shop billing data
And I specify its code as "MOBILE"
And I name it "Mobile channel"
And I choose "Euro" as the base currency
+ And I make it available in "English (United States)"
And I choose "English (United States)" as a default locale
And I select the "Order items based" as tax calculation strategy
And I specify company as "Ragnarok"
diff --git a/features/channel/managing_channels/adding_new_channel_with_menu_taxon.feature b/features/channel/managing_channels/adding_new_channel_with_menu_taxon.feature
index 943ae8e4aa..899fb6c75f 100644
--- a/features/channel/managing_channels/adding_new_channel_with_menu_taxon.feature
+++ b/features/channel/managing_channels/adding_new_channel_with_menu_taxon.feature
@@ -17,6 +17,7 @@ Feature: Adding a new channel with menu taxon
And I specify its code as "MOBILE"
And I name it "Mobile channel"
And I choose "Euro" as the base currency
+ And I make it available in "English (United States)"
And I choose "English (United States)" as a default locale
And I select the "Order items based" as tax calculation strategy
And I specify menu taxon as "Clothes"
diff --git a/features/channel/managing_channels/choosing_required_address_in_checkout_for_channel.feature b/features/channel/managing_channels/choosing_required_address_in_checkout_for_channel.feature
index 718788f7ce..bd44a3db81 100644
--- a/features/channel/managing_channels/choosing_required_address_in_checkout_for_channel.feature
+++ b/features/channel/managing_channels/choosing_required_address_in_checkout_for_channel.feature
@@ -14,6 +14,7 @@ Feature: Choosing a required address in the checkout for a channel
And I specify its code as "MOBILE"
And I name it "Mobile Store"
And I choose "USD" as the base currency
+ And I make it available in "English (United States)"
And I choose "English (United States)" as a default locale
And I select the "Order items based" as tax calculation strategy
And I choose shipping address as a required address in the checkout
diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php
index 4a8d6ed929..e9690cc99c 100644
--- a/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php
+++ b/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php
@@ -265,8 +265,8 @@ final class ManagingChannelsContext implements Context
public function iShouldBeNotifiedThatItHasBeenSuccessfullyCreated(): void
{
Assert::true(
- $this->responseChecker->isCreationSuccessful($this->client->getLastResponse()),
- 'Channel could not be created',
+ $this->responseChecker->isCreationSuccessful($response = $this->client->getLastResponse()),
+ 'Channel could not be created: ' . $response->getContent(),
);
}
diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml
index 7003380820..5a2dc00909 100644
--- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml
+++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml
@@ -42,6 +42,7 @@
admin:channel:read
+ sylius
@@ -77,6 +78,7 @@
admin:channel:read
+ sylius
diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml
index df0ba4ce96..92f00cc2b1 100644
--- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml
+++ b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml
@@ -111,5 +111,20 @@
admin:channel:readadmin:channel:create
+
+ admin:channel:read
+ admin:channel:create
+ admin:channel:update
+
+
+ admin:channel:read
+ admin:channel:create
+ admin:channel:update
+
+
+ admin:channel:read
+ admin:channel:create
+ admin:channel:update
+
diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml
index 69c63ee9bf..d85303db33 100644
--- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml
+++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml
@@ -102,5 +102,10 @@
+
+
+
+
+
diff --git a/src/Sylius/Bundle/ApiBundle/Serializer/ChannelExcludedTaxonsDenormalizer.php b/src/Sylius/Bundle/ApiBundle/Serializer/ChannelExcludedTaxonsDenormalizer.php
new file mode 100644
index 0000000000..bc32287279
--- /dev/null
+++ b/src/Sylius/Bundle/ApiBundle/Serializer/ChannelExcludedTaxonsDenormalizer.php
@@ -0,0 +1,62 @@
+denormalizer->denormalize($data, $type, $format, $context);
+ Assert::isInstanceOf($channel, ChannelInterface::class);
+
+ $channel->clearTaxonsExcludedFromShowingLowestPrice();
+
+ foreach ($data['taxonsExcludedFromShowingLowestPrice'] ?? [] as $excludedTaxonIri) {
+ /** @var TaxonInterface $taxon */
+ $taxon = $this->iriConverter->getItemFromIri($excludedTaxonIri);
+
+ $channel->addTaxonExcludedFromShowingLowestPrice($taxon);
+ }
+
+ return $channel;
+ }
+}
diff --git a/src/Sylius/Bundle/ApiBundle/spec/Serializer/ChannelExcludedTaxonsDenormalizerSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Serializer/ChannelExcludedTaxonsDenormalizerSpec.php
new file mode 100644
index 0000000000..3f2fcb7fa3
--- /dev/null
+++ b/src/Sylius/Bundle/ApiBundle/spec/Serializer/ChannelExcludedTaxonsDenormalizerSpec.php
@@ -0,0 +1,147 @@
+beConstructedWith($iriConverter);
+ }
+
+ function it_does_not_support_denormalization_when_the_denormalizer_has_already_been_called(): void
+ {
+ $this->supportsDenormalization([], 'string', context: [self::ALREADY_CALLED => true])->shouldReturn(false);
+ }
+
+ function it_does_not_support_denormalization_when_data_is_not_an_array(): void
+ {
+ $this->supportsDenormalization('string', 'string')->shouldReturn(false);
+ }
+
+ function it_does_not_support_denormalization_when_type_is_not_a_channel(): void
+ {
+ $this->supportsDenormalization([], 'string')->shouldReturn(false);
+ }
+
+ function it_throws_an_exception_when_denormalizing_an_object_that_is_not_a_channel(
+ DenormalizerInterface $denormalizer,
+ ): void {
+ $this->setDenormalizer($denormalizer);
+
+ $denormalizer->denormalize([], 'string', null, [self::ALREADY_CALLED => true])->willReturn(new \stdClass());
+
+ $this->shouldThrow(\InvalidArgumentException::class)->during('denormalize', [[], 'string']);
+ }
+
+ function it_adds_excluded_taxons_from_data(
+ DenormalizerInterface $denormalizer,
+ IriConverterInterface $iriConverter,
+ TaxonInterface $firstTaxon,
+ TaxonInterface $secondTaxon,
+ ChannelInterface $channel,
+ ): void {
+ $this->setDenormalizer($denormalizer);
+
+ $data = ['taxonsExcludedFromShowingLowestPrice' => [
+ '/api/v2/taxons/first-new-taxon',
+ '/api/v2/taxons/second-new-taxon',
+ ]];
+
+ $channel->getTaxonsExcludedFromShowingLowestPrice()->willReturn(new ArrayCollection());
+
+ $denormalizer->denormalize($data, 'string', null, [self::ALREADY_CALLED => true])->willReturn($channel);
+
+ $channel->clearTaxonsExcludedFromShowingLowestPrice()->shouldBeCalled();
+
+ $iriConverter->getItemFromIri('/api/v2/taxons/first-new-taxon')->shouldBeCalledTimes(1)->willReturn($firstTaxon);
+ $iriConverter->getItemFromIri('/api/v2/taxons/second-new-taxon')->shouldBeCalledTimes(1)->willReturn($secondTaxon);
+
+ $channel->addTaxonExcludedFromShowingLowestPrice($firstTaxon)->shouldBeCalledTimes(1);
+ $channel->addTaxonExcludedFromShowingLowestPrice($secondTaxon)->shouldBeCalledTimes(1);
+
+ $this->denormalize($data, 'string')->shouldReturn($channel);
+ }
+
+ function it_removes_excluded_taxons_when_data_has_none(
+ DenormalizerInterface $denormalizer,
+ IriConverterInterface $iriConverter,
+ TaxonInterface $firstTaxon,
+ TaxonInterface $secondTaxon,
+ ChannelInterface $channel,
+ ): void {
+ $this->setDenormalizer($denormalizer);
+
+ $data = [];
+
+ $denormalizer->denormalize($data, 'string', null, [self::ALREADY_CALLED => true])->willReturn($channel);
+
+ $channel->getTaxonsExcludedFromShowingLowestPrice()->willReturn(new ArrayCollection([
+ $firstTaxon->getWrappedObject(),
+ $secondTaxon->getWrappedObject(),
+ ]));
+
+ $channel->clearTaxonsExcludedFromShowingLowestPrice()->shouldBeCalled();
+
+ $iriConverter->getItemFromIri(Argument::cetera())->shouldNotBeCalled();
+
+ $channel->addTaxonExcludedFromShowingLowestPrice(Argument::any())->shouldNotBeCalled();
+
+ $this->denormalize($data, 'string')->shouldReturn($channel);
+ }
+
+ function it_replaces_current_excluded_taxons_with_ones_from_data(
+ DenormalizerInterface $denormalizer,
+ IriConverterInterface $iriConverter,
+ TaxonInterface $firstCurrentTaxon,
+ TaxonInterface $secondCurrentTaxon,
+ TaxonInterface $firstNewTaxon,
+ TaxonInterface $secondNewTaxon,
+ ChannelInterface $channel,
+ ): void {
+ $this->setDenormalizer($denormalizer);
+
+ $data = ['taxonsExcludedFromShowingLowestPrice' => [
+ '/api/v2/taxons/first-new-taxon',
+ '/api/v2/taxons/second-new-taxon',
+ ]];
+
+ $denormalizer->denormalize($data, 'string', null, [self::ALREADY_CALLED => true])->willReturn($channel);
+
+ $channel->getTaxonsExcludedFromShowingLowestPrice()->willReturn(new ArrayCollection([
+ $firstCurrentTaxon->getWrappedObject(),
+ $secondCurrentTaxon->getWrappedObject(),
+ ]));
+
+ $channel->clearTaxonsExcludedFromShowingLowestPrice()->shouldBeCalled();
+
+ $iriConverter->getItemFromIri('/api/v2/taxons/first-new-taxon')->shouldBeCalledTimes(1)->willReturn($firstNewTaxon);
+ $iriConverter->getItemFromIri('/api/v2/taxons/second-new-taxon')->shouldBeCalledTimes(1)->willReturn($secondNewTaxon);
+
+ $channel->addTaxonExcludedFromShowingLowestPrice($firstNewTaxon)->shouldBeCalledTimes(1);
+ $channel->addTaxonExcludedFromShowingLowestPrice($secondNewTaxon)->shouldBeCalledTimes(1);
+
+ $this->denormalize($data, 'string')->shouldReturn($channel);
+ }
+}
diff --git a/src/Sylius/Bundle/ChannelBundle/Resources/translations/validators.en.yml b/src/Sylius/Bundle/ChannelBundle/Resources/translations/validators.en.yml
index 3346274b6b..906fde7a00 100644
--- a/src/Sylius/Bundle/ChannelBundle/Resources/translations/validators.en.yml
+++ b/src/Sylius/Bundle/ChannelBundle/Resources/translations/validators.en.yml
@@ -4,5 +4,8 @@ sylius:
not_blank: Please enter channel code.
regex: Channel code can only be comprised of letters, numbers, dashes and underscores.
unique: Channel code has to be unique.
+ lowest_price_for_discounted_products_checking_period:
+ greater_than: 'Value must be greater than {{ compared_value }}'
+ less_than: 'Value must be less than {{ compared_value }}'
name:
not_blank: Please enter channel name.
diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/services/price_history/listeners.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/services/price_history/listeners.xml
index cf26195259..75ad7b5310 100644
--- a/src/Sylius/Bundle/CoreBundle/Resources/config/services/price_history/listeners.xml
+++ b/src/Sylius/Bundle/CoreBundle/Resources/config/services/price_history/listeners.xml
@@ -24,7 +24,7 @@
%sylius_core.price_history.batch_size%
-
+
diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/validation/Channel.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/validation/Channel.xml
index 6f68d60d52..986a21647b 100644
--- a/src/Sylius/Bundle/CoreBundle/Resources/config/validation/Channel.xml
+++ b/src/Sylius/Bundle/CoreBundle/Resources/config/validation/Channel.xml
@@ -54,5 +54,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+