mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-15 01:20:59 +00:00
642 lines
22 KiB
PHP
642 lines
22 KiB
PHP
<?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\Tests\Api\Admin;
|
|
|
|
use Sylius\Component\Core\Model\ChannelInterface;
|
|
use Sylius\Component\Core\Model\ProductVariantInterface;
|
|
use Sylius\Tests\Api\JsonApiTestCase;
|
|
use Sylius\Tests\Api\Utils\AdminUserLoginTrait;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
final class ProductVariantsTest extends JsonApiTestCase
|
|
{
|
|
use AdminUserLoginTrait;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->setUpAdminContext();
|
|
$this->setUpDefaultGetHeaders();
|
|
|
|
parent::setUp();
|
|
}
|
|
|
|
/** @test */
|
|
public function it_denies_access_to_a_product_variants_list_for_not_authenticated_user(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
|
|
$this->client->request('GET', '/api/v2/admin/product-variants');
|
|
|
|
$response = $this->client->getResponse();
|
|
$this->assertSame(Response::HTTP_UNAUTHORIZED, $response->getStatusCode());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_gets_all_product_variants(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'GET',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
);
|
|
$response = $this->client->getResponse();
|
|
|
|
$this->assertResponse($response, 'admin/product_variant/get_product_variants_response', Response::HTTP_OK);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_gets_all_product_variants_when_invalid_product_filter_provided(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
|
|
$this->requestGet(
|
|
uri: '/api/v2/admin/product-variants',
|
|
queryParameters: ['product' => 'INVALID-IRI'],
|
|
);
|
|
|
|
$this->assertResponseSuccessful('admin/product_variant/get_filtered_product_variants');
|
|
}
|
|
|
|
/** @test */
|
|
public function it_gets_a_product_variant(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
|
|
$this->client->request(
|
|
method: 'GET',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
);
|
|
$response = $this->client->getResponse();
|
|
|
|
$this->assertResponse($response, 'admin/product_variant/get_product_variant_response', Response::HTTP_OK);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_creates_a_product_variant_with_all_optional_data(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'MUG_RED',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'optionValues' => ['/api/v2/admin/product-options/COLOR/values/COLOR_RED'],
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
'originalPrice' => 5000,
|
|
'minimumPrice' => 2000,
|
|
],
|
|
],
|
|
'translations' => [
|
|
'en_US' => [
|
|
'name' => 'Red mug',
|
|
],
|
|
],
|
|
'enabled' => false,
|
|
'position' => 1,
|
|
'tracked' => true,
|
|
'onHold' => 5,
|
|
'onHand' => 10,
|
|
'weight' => 100.5,
|
|
'width' => 100.5,
|
|
'height' => 100.5,
|
|
'depth' => 100.5,
|
|
'taxCategory' => '/api/v2/admin/tax-categories/default',
|
|
'shippingCategory' => '/api/v2/admin/shipping-categories/default',
|
|
'shippingRequired' => true,
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponse(
|
|
$this->client->getResponse(),
|
|
'admin/product_variant/post_product_variant_response',
|
|
Response::HTTP_CREATED,
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_creates_a_product_variant_enabled_by_default_with_translation_in_default_locale(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'MUG_3',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponse(
|
|
$this->client->getResponse(),
|
|
'admin/product_variant/post_product_variant_enabled_by_default_with_translation_in_default_locale_response',
|
|
Response::HTTP_CREATED,
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_create_product_variant_with_invalid_channel_code(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'CUP',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'channelPricings' => [
|
|
'NON-EXISTING-CHANNEL' => [
|
|
'price' => 4000,
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'channelPricings[NON-EXISTING-CHANNEL].channelCode',
|
|
'message' => 'Channel with code NON-EXISTING-CHANNEL does not exist.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_create_product_variant_with_empty_channel_code(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'CUP',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'channelPricings' => [
|
|
'' => [
|
|
'price' => 4000,
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'channelPricings[].channelCode',
|
|
'message' => 'Please set channel code.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_create_product_variant_when_channel_code_differs_from_key(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'CUP',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
'channelCode' => 'MOBILE',
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponse(
|
|
$this->client->getResponse(),
|
|
'admin/product_variant/post_product_variant_when_channel_code_differs_from_key',
|
|
Response::HTTP_UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_create_product_variant_without_product(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'CUP',
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'product',
|
|
'message' => 'This value should not be blank.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_create_product_variant_with_invalid_locale_code(): void
|
|
{
|
|
$this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
$this->client->request(
|
|
method: 'POST',
|
|
uri: '/api/v2/admin/product-variants',
|
|
server: $header,
|
|
content: json_encode([
|
|
'code' => 'CUP',
|
|
'product' => '/api/v2/admin/products/MUG_SW',
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
'originalPrice' => 5000,
|
|
'minimumPrice' => 2000,
|
|
],
|
|
],
|
|
'translations' => [
|
|
'NON-EXISTING-LOCALE-CODE' => [
|
|
'name' => 'Yellow mug',
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'translations[NON-EXISTING-LOCALE-CODE]',
|
|
'message' => 'Please choose one of the available locales: en_US, pl_PL, de_DE',
|
|
],
|
|
[
|
|
'propertyPath' => 'translations[NON-EXISTING-LOCALE-CODE].locale',
|
|
'message' => 'This value is not a valid locale.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_updates_the_existing_product_variant(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
/** @var ChannelInterface $channel */
|
|
$channel = $fixtures['channel_web'];
|
|
|
|
$this->client->request(
|
|
method: 'PUT',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
content: json_encode([
|
|
'optionValues' => ['/api/v2/admin/product-options/COLOR/values/COLOR_RED'],
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'@id' => sprintf('/api/v2/admin/product-variants/%s/channel-pricings/%s', $productVariant->getCode(), $channel->getCode()),
|
|
'price' => 3000,
|
|
'originalPrice' => 4000,
|
|
'minimumPrice' => 500,
|
|
],
|
|
'MOBILE' => [
|
|
'price' => 5000,
|
|
'originalPrice' => 5000,
|
|
'minimumPrice' => 1000,
|
|
],
|
|
],
|
|
'translations' => [
|
|
'en_US' => [
|
|
'@id' => sprintf('/api/v2/admin/product-variants/%s/translations/en_US', $productVariant->getCode()),
|
|
'name' => 'Red mug',
|
|
],
|
|
'de_DE' => [
|
|
'name' => 'Rote Tasse',
|
|
],
|
|
],
|
|
'enabled' => false,
|
|
'position' => 2,
|
|
'tracked' => false,
|
|
'onHold' => 0,
|
|
'onHand' => 0,
|
|
'weight' => 50.5,
|
|
'width' => 50.5,
|
|
'height' => 50.5,
|
|
'depth' => 50.5,
|
|
'taxCategory' => '/api/v2/admin/tax-categories/special',
|
|
'shippingCategory' => '/api/v2/admin/shipping-categories/special',
|
|
'shippingRequired' => false,
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponse(
|
|
$this->client->getResponse(),
|
|
'admin/product_variant/put_product_variant_response',
|
|
Response::HTTP_OK,
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_allow_to_update_product_variant_with_invalid_locale_code(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
|
|
$this->client->request(
|
|
method: 'PUT',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
content: json_encode([
|
|
'translations' => [
|
|
'NON-EXISTING-LOCALE-CODE' => [
|
|
'name' => 'Yellow mug',
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'translations[NON-EXISTING-LOCALE-CODE]',
|
|
'message' => 'Please choose one of the available locales: en_US, pl_PL, de_DE',
|
|
],
|
|
[
|
|
'propertyPath' => 'translations[NON-EXISTING-LOCALE-CODE].locale',
|
|
'message' => 'This value is not a valid locale.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_update_a_product_variant_with_duplicate_locale_translation(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
|
|
$this->client->request(
|
|
method: 'PUT',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
content: json_encode([
|
|
'translations' => [
|
|
'en_US' => [
|
|
'name' => 'Mug 3',
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'translations[en_US].locale',
|
|
'message' => 'A translation for the "en_US" locale code already exists.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_update_product_variant_with_duplicate_channel_code_channel_pricings(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
|
|
$this->client->request(
|
|
method: 'PUT',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
content: json_encode([
|
|
'channelPricings' => [
|
|
'WEB' => [
|
|
'price' => 4000,
|
|
'originalPrice' => 5000,
|
|
'minimumPrice' => 2000,
|
|
],
|
|
],
|
|
], \JSON_THROW_ON_ERROR),
|
|
);
|
|
|
|
$this->assertResponseViolations(
|
|
$this->client->getResponse(),
|
|
[
|
|
[
|
|
'propertyPath' => 'channelPricings[WEB].channelCode',
|
|
'message' => 'This channel already has a price for this product variant.',
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_deletes_the_product_variant(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant_2'];
|
|
|
|
$this->client->request(
|
|
method: 'DELETE',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
);
|
|
|
|
$this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_does_not_delete_the_product_variant_in_use(): void
|
|
{
|
|
$fixtures = $this->loadFixturesFromFiles([
|
|
'authentication/api_administrator.yaml',
|
|
'channel/channel.yaml',
|
|
'tax_category.yaml',
|
|
'shipping_category.yaml',
|
|
'product/product_variant.yaml',
|
|
]);
|
|
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
|
|
|
/** @var ProductVariantInterface $productVariant */
|
|
$productVariant = $fixtures['product_variant'];
|
|
|
|
$this->client->request(
|
|
method: 'DELETE',
|
|
uri: sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
|
server: $header,
|
|
);
|
|
|
|
$this->assertResponse(
|
|
$this->client->getResponse(),
|
|
'admin/product_variant/delete_product_variant_in_use_response',
|
|
Response::HTTP_UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
}
|