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 eef18aef2b..76a6fd88fa 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 @@ -8,19 +8,20 @@ Feature: Choosing a required address in the checkout for a channel Given the store operates on a single channel in "United States" And I am logged in as an administrator - @todo + @api Scenario: Adding a new channel with a required address in the checkout When I want to create a new channel And I specify its code as "MOBILE" And I name it "Mobile Store" And I choose "USD" as the base currency 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 And I add it Then I should be notified that it has been successfully created And the required address in the checkout for the "Mobile Store" channel should be shipping - @todo + @api Scenario: Changing a required address in the checkout for an existing channel Given the store operates on a channel named "Web Store" When I want to modify this channel diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php index fd31aedac2..d9c87b1b3b 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingChannelsContext.php @@ -188,6 +188,30 @@ final class ManagingChannelsContext implements Context $this->client->index(Resources::CHANNELS); } + /** + * @When /^I choose (billing|shipping) address as a required address in the checkout$/ + */ + public function iChooseAddressAsARequiredAddressInTheCheckout(string $type): void + { + $this->client->addRequestData('shippingAddressInCheckoutRequired', $type === 'shipping'); + } + + /** + * @When /^I want to modify (this channel)$/ + */ + public function iWantToModifyThisChannel(ChannelInterface $channel): void + { + $this->client->buildUpdateRequest(Resources::CHANNELS, $channel->getCode()); + } + + /** + * @When I save my changes + */ + public function iSaveMyChanges(): void + { + $this->client->update(); + } + /** * @Then I should be notified that it has been successfully created */ @@ -230,4 +254,27 @@ final class ManagingChannelsContext implements Context { Assert::same($this->responseChecker->countCollectionItems($this->client->getLastResponse()), $count); } + + /** + * @Then /^the required address in the checkout for the ("[^"]+" channel) should be (billing|shipping)$/ + */ + public function theDefaultTaxZoneForTheChannelShouldBe(ChannelInterface $channel, string $type): void + { + Assert::true($this->responseChecker->hasValue( + $this->client->getLastResponse(), + 'shippingAddressInCheckoutRequired', + $type === 'shipping', + )); + } + + /** + * @Then I should be notified that it has been successfully edited + */ + public function iShouldBeNotifiedThatItHasBeenSuccessfullyEdited(): void + { + Assert::true( + $this->responseChecker->isUpdateSuccessful($this->client->getLastResponse()), + 'Channel could not be edited', + ); + } } 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 c3444d015e..89fcd23258 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Channel.xml @@ -64,6 +64,14 @@ Use $code to retrieve a channel resource. + + + PUT + /admin/channels/{code} + + admin:channel:update + + @@ -92,6 +100,7 @@ + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml index 69fbc730e3..af833fb9cb 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Channel.xml @@ -94,6 +94,11 @@ admin:channel:read admin:channel:create + + admin:channel:read + admin:channel:create + admin:channel:update + admin:channel:read admin:channel:create diff --git a/src/Sylius/Bundle/CoreBundle/Migrations/Version20220728115129.php b/src/Sylius/Bundle/CoreBundle/Migrations/Version20220728115129.php new file mode 100644 index 0000000000..de272feafc --- /dev/null +++ b/src/Sylius/Bundle/CoreBundle/Migrations/Version20220728115129.php @@ -0,0 +1,26 @@ +addSql('ALTER TABLE sylius_channel ADD shipping_address_in_checkout_required TINYINT(1) DEFAULT 0 NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE sylius_channel DROP shipping_address_in_checkout_required'); + } +} diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/Channel.orm.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/Channel.orm.xml index 4b8fd5dbe0..014f0ff9ad 100644 --- a/src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/Channel.orm.xml +++ b/src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/Channel.orm.xml @@ -24,6 +24,11 @@ + + + + + diff --git a/src/Sylius/Component/Core/Model/Channel.php b/src/Sylius/Component/Core/Model/Channel.php index 8d61bdb246..de78b010dc 100644 --- a/src/Sylius/Component/Core/Model/Channel.php +++ b/src/Sylius/Component/Core/Model/Channel.php @@ -74,6 +74,8 @@ class Channel extends BaseChannel implements ChannelInterface /** @var bool */ protected $accountVerificationRequired = true; + protected bool $shippingAddressInCheckoutRequired = false; + /** @var ShopBillingDataInterface|null */ protected $shopBillingData; @@ -264,6 +266,16 @@ class Channel extends BaseChannel implements ChannelInterface $this->accountVerificationRequired = $accountVerificationRequired; } + public function isShippingAddressInCheckoutRequired(): bool + { + return $this->shippingAddressInCheckoutRequired; + } + + public function setShippingAddressInCheckoutRequired(bool $shippingAddressInCheckoutRequired): void + { + $this->shippingAddressInCheckoutRequired = $shippingAddressInCheckoutRequired; + } + public function getShopBillingData(): ?ShopBillingDataInterface { return $this->shopBillingData; diff --git a/src/Sylius/Component/Core/Model/ChannelInterface.php b/src/Sylius/Component/Core/Model/ChannelInterface.php index ec9cd5d1d4..515ec7caad 100644 --- a/src/Sylius/Component/Core/Model/ChannelInterface.php +++ b/src/Sylius/Component/Core/Model/ChannelInterface.php @@ -67,6 +67,10 @@ interface ChannelInterface extends public function setAccountVerificationRequired(bool $accountVerificationRequired): void; + public function isShippingAddressInCheckoutRequired(): bool; + + public function setShippingAddressInCheckoutRequired(bool $shippingAddressInCheckoutRequired): void; + public function getShopBillingData(): ?ShopBillingDataInterface; public function setShopBillingData(ShopBillingDataInterface $shopBillingData): void; diff --git a/src/Sylius/Component/Core/spec/Model/ChannelSpec.php b/src/Sylius/Component/Core/spec/Model/ChannelSpec.php index 6a350d2895..25b86be016 100644 --- a/src/Sylius/Component/Core/spec/Model/ChannelSpec.php +++ b/src/Sylius/Component/Core/spec/Model/ChannelSpec.php @@ -172,6 +172,17 @@ final class ChannelSpec extends ObjectBehavior $this->isAccountVerificationRequired()->shouldReturn(false); } + function it_does_not_have_shipping_address_in_checkout_required_by_default(): void + { + $this->isShippingAddressInCheckoutRequired()->shouldReturn(false); + } + + function it_can_set_shipping_address_in_checkout_required(): void + { + $this->setShippingAddressInCheckoutRequired(true); + $this->isShippingAddressInCheckoutRequired()->shouldReturn(true); + } + function its_menu_taxon_is_mutable(TaxonInterface $taxon): void { $this->setMenuTaxon($taxon); diff --git a/tests/Api/Admin/ChannelsTest.php b/tests/Api/Admin/ChannelsTest.php new file mode 100644 index 0000000000..b931a27ab3 --- /dev/null +++ b/tests/Api/Admin/ChannelsTest.php @@ -0,0 +1,91 @@ +loadFixturesFromFiles(['authentication/api_administrator.yaml', 'currency.yaml', 'locale.yaml']); + $header = $this->getLoggedHeader(); + + $this->client->request( + 'POST', + '/api/v2/admin/channels', + [], + [], + $header, + json_encode([ + 'name' => 'Web Store', + 'code' => 'WEB', + 'baseCurrency' => '/api/v2/admin/currencies/USD', + 'defaultLocale' => '/api/v2/admin/locales/en_US', + 'taxCalculationStrategy' => 'order_items_based', + 'shippingAddressInCheckoutRequired' => true, + + ], JSON_THROW_ON_ERROR) + ); + + $this->assertResponse( + $this->client->getResponse(), + 'admin/post_channel_response', + Response::HTTP_CREATED + ); + } + + /** @test */ + public function it_updates_an_existing_channel(): void + { + $fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml']); + + /** @var ChannelInterface $channel */ + $channel = $fixtures['channel_web']; + + $header = $this->getLoggedHeader(); + + $this->client->request( + 'PUT', + '/api/v2/admin/channels/' . $channel->getCode(), + [], + [], + $header, + json_encode([ + 'shippingAddressInCheckoutRequired' => true, + ], JSON_THROW_ON_ERROR) + ); + + $this->assertResponse( + $this->client->getResponse(), + 'admin/put_channel_response', + Response::HTTP_OK + ); + } + + private function getLoggedHeader(): array + { + $token = $this->logInAdminUser('api@example.com'); + $authorizationHeader = self::$container->getParameter('sylius.api.authorization_header'); + $header['HTTP_' . $authorizationHeader] = 'Bearer ' . $token; + + return array_merge($header, self::CONTENT_TYPE_HEADER); + } +} diff --git a/tests/Api/DataFixtures/ORM/currency.yaml b/tests/Api/DataFixtures/ORM/currency.yaml new file mode 100644 index 0000000000..5b7399c731 --- /dev/null +++ b/tests/Api/DataFixtures/ORM/currency.yaml @@ -0,0 +1,3 @@ +Sylius\Component\Currency\Model\Currency: + currency_usd: + code: 'USD' diff --git a/tests/Api/DataFixtures/ORM/locale.yaml b/tests/Api/DataFixtures/ORM/locale.yaml new file mode 100644 index 0000000000..762938d09d --- /dev/null +++ b/tests/Api/DataFixtures/ORM/locale.yaml @@ -0,0 +1,3 @@ +Sylius\Component\Locale\Model\Locale: + locale_en: + code: 'en_US' diff --git a/tests/Api/Responses/Expected/admin/post_channel_response.json b/tests/Api/Responses/Expected/admin/post_channel_response.json new file mode 100644 index 0000000000..3bdcdda4fb --- /dev/null +++ b/tests/Api/Responses/Expected/admin/post_channel_response.json @@ -0,0 +1,30 @@ +{ + "@context": "\/api\/v2\/contexts\/Channel", + "@id": "\/api\/v2\/admin\/channels\/WEB", + "@type": "Channel", + "id":"@integer@", + "code": "WEB", + "name": "Web Store", + "enabled": true, + "baseCurrency": "\/api\/v2\/admin\/currencies\/USD", + "defaultLocale": "\/api\/v2\/admin\/locales\/en_US", + "defaultTaxZone": null, + "taxCalculationStrategy": "order_items_based", + "currencies": [], + "locales": [], + "countries": [], + "themeName": null, + "contactEmail": null, + "contactPhoneNumber": null, + "skippingShippingStepAllowed": false, + "skippingPaymentStepAllowed": false, + "accountVerificationRequired": true, + "shippingAddressInCheckoutRequired": true, + "shopBillingData": null, + "menuTaxon": null, + "description": null, + "hostname": null, + "color": null, + "createdAt": @string@, + "updatedAt": @string@ +} diff --git a/tests/Api/Responses/Expected/admin/put_channel_response.json b/tests/Api/Responses/Expected/admin/put_channel_response.json new file mode 100644 index 0000000000..1e755021b2 --- /dev/null +++ b/tests/Api/Responses/Expected/admin/put_channel_response.json @@ -0,0 +1,33 @@ +{ + "@context": "\/api\/v2\/contexts\/Channel", + "@id": "\/api\/v2\/admin\/channels\/WEB", + "@type": "Channel", + "id":"@integer@", + "code": "WEB", + "name": "Web Channel", + "enabled": true, + "baseCurrency": "\/api\/v2\/admin\/currencies\/USD", + "defaultLocale": "\/api\/v2\/admin\/locales\/en_US", + "defaultTaxZone": null, + "taxCalculationStrategy": "order_items_based", + "currencies": [], + "locales": [ + "\/api\/v2\/admin\/locales\/en_US", + "\/api\/v2\/admin\/locales\/pl_PL" + ], + "countries": [], + "themeName": null, + "contactEmail": "web@sylius.com", + "contactPhoneNumber": null, + "skippingShippingStepAllowed": false, + "skippingPaymentStepAllowed": false, + "accountVerificationRequired": true, + "shippingAddressInCheckoutRequired": true, + "shopBillingData": null, + "menuTaxon": null, + "description": "Lorem ipsum", + "hostname": "localhost", + "color": "black", + "createdAt": @string@, + "updatedAt": @string@ +}