mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
[Api][Admin] Cover product attributes removing
This commit is contained in:
parent
5c5b767929
commit
89cc7a22a4
17 changed files with 167 additions and 43 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\ApiBundle\DataPersister;
|
||||
|
||||
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Sylius\Bundle\ApiBundle\Exception\ProductAttributeCannotBeRemoved;
|
||||
use Sylius\Component\Product\Model\ProductAttributeInterface;
|
||||
|
||||
/** @experimental */
|
||||
final class ProductAttributeDataPersister implements ContextAwareDataPersisterInterface
|
||||
{
|
||||
public function __construct(private ContextAwareDataPersisterInterface $decoratedDataPersister)
|
||||
{
|
||||
}
|
||||
|
||||
public function supports($data, array $context = []): bool
|
||||
{
|
||||
return $data instanceof ProductAttributeInterface;
|
||||
}
|
||||
|
||||
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 ProductAttributeCannotBeRemoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\ApiBundle\Exception;
|
||||
|
||||
/** @experimental */
|
||||
final class ProductAttributeCannotBeRemoved extends \RuntimeException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Cannot delete, the product attribute is in use.');
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,11 @@
|
|||
</attribute>
|
||||
</itemOperation>
|
||||
|
||||
<itemOperation name="admin_delete">
|
||||
<attribute name="method">DELETE</attribute>
|
||||
<attribute name="path">/admin/product-attributes/{code}</attribute>
|
||||
</itemOperation>
|
||||
|
||||
<itemOperation name="shop_get">
|
||||
<attribute name="method">GET</attribute>
|
||||
<attribute name="path">/shop/product-attributes/{code}</attribute>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@
|
|||
<tag name="api_platform.data_persister" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\ProductAttributeDataPersister">
|
||||
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
|
||||
<tag name="api_platform.data_persister" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\ProductTaxonDataPersister">
|
||||
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
|
||||
<argument type="service" id="sylius.event_bus" />
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,15 @@ 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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue