From 89cc7a22a45a8da2d353a4b90518ac70e7b26f64 Mon Sep 17 00:00:00 2001 From: Jan Goralski Date: Mon, 4 Sep 2023 14:23:19 +0200 Subject: [PATCH] [Api][Admin] Cover product attributes removing --- ...leting_multiple_product_attributes.feature | 2 +- ...ure => deleting_product_attribute.feature} | 8 ++-- .../deleting_text_product_attribute.feature | 15 ------- .../ManagingProductAttributesContext.php | 41 +++++++++++++++++++ .../Admin/ManagingPaymentMethodsContext.php | 8 ---- .../ManagingProductAttributesContext.php | 2 +- .../Admin/ManagingShippingMethodsContext.php | 8 ---- .../Context/Ui/Admin/NotificationContext.php | 6 +-- .../product/managing_product_attributes.yml | 3 ++ .../ProductAttributeDataPersister.php | 37 +++++++++++++++++ .../ProductAttributeCannotBeRemoved.php | 14 +++++++ .../config/api_resources/ProductAttribute.xml | 5 +++ .../Resources/config/app/config.yaml | 1 + .../config/services/data_persisters.xml | 5 +++ tests/Api/Admin/ProductAttributesTest.php | 21 ++++++++++ .../ORM/product/product_attribute.yaml | 13 +++++- .../get_product_attributes_response.json | 21 +++++++++- 17 files changed, 167 insertions(+), 43 deletions(-) rename features/product/managing_product_attributes/{remove_product_attribute.feature => deleting_product_attribute.feature} (86%) delete mode 100644 features/product/managing_product_attributes/deleting_text_product_attribute.feature create mode 100644 src/Sylius/Bundle/ApiBundle/DataPersister/ProductAttributeDataPersister.php create mode 100644 src/Sylius/Bundle/ApiBundle/Exception/ProductAttributeCannotBeRemoved.php diff --git a/features/product/managing_product_attributes/deleting_multiple_product_attributes.feature b/features/product/managing_product_attributes/deleting_multiple_product_attributes.feature index 1544fe8b98..e55e1abdc1 100644 --- a/features/product/managing_product_attributes/deleting_multiple_product_attributes.feature +++ b/features/product/managing_product_attributes/deleting_multiple_product_attributes.feature @@ -10,7 +10,7 @@ Feature: Deleting multiple product attributes And the store has a integer product attribute "Pages" And I am logged in as an administrator - @ui @javascript + @ui @javascript @no-api Scenario: Deleting multiple product attributes at once When I browse product attributes And I check the "Publisher" product attribute diff --git a/features/product/managing_product_attributes/remove_product_attribute.feature b/features/product/managing_product_attributes/deleting_product_attribute.feature similarity index 86% rename from features/product/managing_product_attributes/remove_product_attribute.feature rename to features/product/managing_product_attributes/deleting_product_attribute.feature index 3a59963f12..d1eebb2c0b 100644 --- a/features/product/managing_product_attributes/remove_product_attribute.feature +++ b/features/product/managing_product_attributes/deleting_product_attribute.feature @@ -1,5 +1,5 @@ @managing_product_attributes -Feature:Removing a attribute +Feature: Deleting a product attribute In order to keep my collection of product attributes not cluttered As an administrator I want to be able to remove an attribute that is not assigned to any of the products @@ -8,13 +8,13 @@ Feature:Removing a attribute Given I am logged in as an administrator And the store has a product "44 Magnum" - @ui + @ui @api Scenario: Try deleting a attribute from the registry when product use him Given this product has a text attribute "Gun caliber" with value "11 mm" When I delete this product attribute - Then I should be notified that it has been failed deleted "product attribute" + Then I should be notified that it is in use - @ui + @ui @api Scenario: Deleting a text product attribute when not by used Given the store has a text product attribute "Gun caliber" When I delete this product attribute diff --git a/features/product/managing_product_attributes/deleting_text_product_attribute.feature b/features/product/managing_product_attributes/deleting_text_product_attribute.feature deleted file mode 100644 index 562e7dd120..0000000000 --- a/features/product/managing_product_attributes/deleting_text_product_attribute.feature +++ /dev/null @@ -1,15 +0,0 @@ -@managing_product_attributes -Feature: Deleting a text product attribute - In order to remove test, obsolete or incorrect text product attribute - As an Administrator - I want to be able to delete a text product attribute - - Background: - Given I am logged in as an administrator - - @ui - Scenario: Deleting a text product attribute from the registry - Given the store has a text product attribute "T-Shirt cotton brand" - When I delete this product attribute - Then I should be notified that it has been successfully deleted - And this product attribute should no longer exist in the registry diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingProductAttributesContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingProductAttributesContext.php index 7e864a213b..d69acb76d8 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingProductAttributesContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingProductAttributesContext.php @@ -8,6 +8,7 @@ use Behat\Behat\Context\Context; use Sylius\Behat\Client\ApiClientInterface; use Sylius\Behat\Client\ResponseCheckerInterface; use Sylius\Behat\Context\Api\Resources; +use Sylius\Component\Product\Model\ProductAttributeInterface; use Webmozart\Assert\Assert; final class ManagingProductAttributesContext implements Context @@ -26,6 +27,14 @@ final class ManagingProductAttributesContext implements Context $this->client->index(Resources::PRODUCT_ATTRIBUTES); } + /** + * @When /^I(?:| try to) delete (this product attribute)$/ + */ + public function iDeleteThisProductAttribute(ProductAttributeInterface $attribute): void + { + $this->client->delete(Resources::PRODUCT_ATTRIBUTES, $attribute->getCode()); + } + /** * @Then I should see :count product attributes in the list */ @@ -46,4 +55,36 @@ final class ManagingProductAttributesContext implements Context $attributeName, )); } + + /** + * @Then I should be notified that it has been successfully deleted + */ + public function iShouldBeNotifiedThatItHasBeenSuccessfullyDeleted(): void + { + $this->responseChecker->isDeletionSuccessful($this->client->getLastResponse()); + } + + /** + * @Then /^(this product attribute) should no longer exist in the registry$/ + */ + public function thisProductAttributeShouldNoLongerExistInTheRegistry(ProductAttributeInterface $productAttribute): void + { + $response = $this->client->index(Resources::PRODUCT_ATTRIBUTES); + + Assert::false( + $this->responseChecker->hasItemWithValue($response, 'code', $productAttribute->getCode()), + sprintf('Product attribute with code %s exists, but should not', $productAttribute->getCode()), + ); + } + + /** + * @Then I should be notified that it is in use + */ + public function iShouldBeNotifiedThatItIsInUse(): void + { + Assert::contains( + $this->responseChecker->getError($this->client->getLastResponse()), + 'Cannot delete, the product attribute is in use.', + ); + } } diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php index 307eed3e06..a4397f8596 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php @@ -99,14 +99,6 @@ final class ManagingPaymentMethodsContext implements Context $this->indexPage->deleteResourceOnPage(['code' => $paymentMethod->getCode(), 'name' => $paymentMethod->getName()]); } - /** - * @Then I should be notified that it is in use - */ - public function iShouldBeNotifiedThatItIsInUse() - { - $this->notificationChecker->checkNotification('Cannot delete, the Payment method is in use.', NotificationType::failure()); - } - /** * @Then this payment method :element should be :value */ diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingProductAttributesContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingProductAttributesContext.php index e7bf2a9a20..5b7afbf49e 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingProductAttributesContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingProductAttributesContext.php @@ -328,7 +328,7 @@ final class ManagingProductAttributesContext implements Context } /** - * @When /^I delete (this product attribute)$/ + * @When /^I(?:| try to) delete (this product attribute)$/ */ public function iDeleteThisProductAttribute(ProductAttributeInterface $productAttribute) { diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingShippingMethodsContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingShippingMethodsContext.php index 73914acd94..43be6966ce 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingShippingMethodsContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingShippingMethodsContext.php @@ -448,14 +448,6 @@ final class ManagingShippingMethodsContext implements Context Assert::false($this->indexPage->isSingleResourceOnPage(['code' => $shippingMethod->getCode()])); } - /** - * @Then I should be notified that it is in use - */ - public function iShouldBeNotifiedThatItIsInUse() - { - $this->notificationChecker->checkNotification('Cannot delete, the Shipping method is in use.', NotificationType::failure()); - } - /** * @Then I should be notified that amount for :channel channel should not be blank */ diff --git a/src/Sylius/Behat/Context/Ui/Admin/NotificationContext.php b/src/Sylius/Behat/Context/Ui/Admin/NotificationContext.php index 0fd9a391e5..1148a9197d 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/NotificationContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/NotificationContext.php @@ -76,14 +76,14 @@ final class NotificationContext implements Context } /** - * @Then I should be notified that it has been failed deleted :name + * @Then I should be notified that it is in use */ - public function iShouldBeNotifiedThatItHasBeenFailedDeleted(string $name): void + public function iShouldBeNotifiedThatItIsInUse(): void { $this->testHelper->waitUntilNotificationPopups( $this->notificationChecker, NotificationType::failure(), - 'Cannot delete, the ' . ucfirst($name) . ' is in use.', + 'Cannot delete', ); } } diff --git a/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_attributes.yml b/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_attributes.yml index 4581721ed4..48368a2e00 100644 --- a/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_attributes.yml +++ b/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_attributes.yml @@ -10,8 +10,11 @@ default: - sylius.behat.context.setup.admin_api_security - sylius.behat.context.setup.channel - sylius.behat.context.setup.locale + - sylius.behat.context.setup.product - sylius.behat.context.setup.product_attribute + - sylius.behat.context.transform.shared_storage + - sylius.behat.context.api.admin.managing_product_attributes filters: diff --git a/src/Sylius/Bundle/ApiBundle/DataPersister/ProductAttributeDataPersister.php b/src/Sylius/Bundle/ApiBundle/DataPersister/ProductAttributeDataPersister.php new file mode 100644 index 0000000000..54fde60b3c --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/DataPersister/ProductAttributeDataPersister.php @@ -0,0 +1,37 @@ +decoratedDataPersister->persist($data, $context); + } + + public function remove($data, array $context = []) + { + try { + return $this->decoratedDataPersister->remove($data, $context); + } catch (ForeignKeyConstraintViolationException) { + throw new ProductAttributeCannotBeRemoved(); + } + } +} diff --git a/src/Sylius/Bundle/ApiBundle/Exception/ProductAttributeCannotBeRemoved.php b/src/Sylius/Bundle/ApiBundle/Exception/ProductAttributeCannotBeRemoved.php new file mode 100644 index 0000000000..3b8b588d73 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Exception/ProductAttributeCannotBeRemoved.php @@ -0,0 +1,14 @@ + + + DELETE + /admin/product-attributes/{code} + + GET /shop/product-attributes/{code} diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml b/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml index a69a6d4c90..abe54dca4c 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml @@ -52,6 +52,7 @@ api_platform: Sylius\Bundle\ApiBundle\Exception\CannotRemoveCurrentlyLoggedInUser: 422 Sylius\Bundle\ApiBundle\Exception\OrderItemNotFoundException: 422 Sylius\Bundle\ApiBundle\Exception\OrderNoLongerEligibleForPromotion: 422 + Sylius\Bundle\ApiBundle\Exception\ProductAttributeCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProductCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProvinceCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ShippingMethodCannotBeRemoved: 422 diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml index a4fa32e564..00ae7067dd 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml @@ -53,6 +53,11 @@ + + + + + diff --git a/tests/Api/Admin/ProductAttributesTest.php b/tests/Api/Admin/ProductAttributesTest.php index 822eb0adf0..78d597134d 100644 --- a/tests/Api/Admin/ProductAttributesTest.php +++ b/tests/Api/Admin/ProductAttributesTest.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Sylius\Tests\Api\Admin; +use Sylius\Component\Product\Model\ProductAttributeInterface; use Sylius\Tests\Api\JsonApiTestCase; use Sylius\Tests\Api\Utils\AdminUserLoginTrait; use Symfony\Component\HttpFoundation\Response; @@ -35,4 +36,24 @@ final class ProductAttributesTest extends JsonApiTestCase Response::HTTP_OK, ); } + + /** @test */ + public function it_deletes_a_product_attribute(): void + { + $fixtures = $this->loadFixturesFromFiles([ + 'authentication/api_administrator.yaml', + 'product/product_attribute.yaml', + ]); + $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); + /** @var ProductAttributeInterface $productAttribute */ + $productAttribute = $fixtures['product_attribute_text_delete']; + + $this->client->request( + method: 'DELETE', + uri: sprintf('/api/v2/admin/product-attributes/%s', $productAttribute->getCode()), + server: $header, + ); + + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT); + } } diff --git a/tests/Api/DataFixtures/ORM/product/product_attribute.yaml b/tests/Api/DataFixtures/ORM/product/product_attribute.yaml index 6034a57760..2910fde48c 100644 --- a/tests/Api/DataFixtures/ORM/product/product_attribute.yaml +++ b/tests/Api/DataFixtures/ORM/product/product_attribute.yaml @@ -89,13 +89,22 @@ Sylius\Component\Product\Model\ProductAttribute: storage_type: 'text' configuration: [] translatable: true - + product_attribute_text_delete: + fallbackLocale: en_US + currentLocale: en_US + code: 'text_delete' + name: 'text delete' + type: 'text' + storage_type: 'text' + configuration: [] + translatable: false + Sylius\Component\Product\Model\ProductAttributeTranslation: product_attribute_translation_checkbox: locale: pl_PL name: 'mozna myc w zmywarce' translatable: '@product_attribute_checkbox' - + Sylius\Component\Product\Model\ProductAttributeValue: product_attribute_value_checkbox: localeCode: pl_PL diff --git a/tests/Api/Responses/Expected/admin/product_attribute/get_product_attributes_response.json b/tests/Api/Responses/Expected/admin/product_attribute/get_product_attributes_response.json index 667963a7bc..1b6ae2cf53 100644 --- a/tests/Api/Responses/Expected/admin/product_attribute/get_product_attributes_response.json +++ b/tests/Api/Responses/Expected/admin/product_attribute/get_product_attributes_response.json @@ -173,7 +173,26 @@ } }, "type": "text" + }, + { + "@id": "\/api\/v2\/admin\/product-attributes/text_delete", + "@type": "ProductAttribute", + "code": "text_delete", + "configuration": [], + "position": 8, + "storageType": "text", + "translatable": false, + "translations": { + "en_US": { + "@id": "\/api\/v2\/admin\/product-attribute-translations\/@integer@", + "@type": "ProductAttributeTranslation", + "id": "@integer@", + "name": "text delete", + "locale": "en_US" + } + }, + "type": "text" } ], - "hydra:totalItems": 8 + "hydra:totalItems": 9 }