feature #15635 [API][Behat] covering tests for managing promotions (Wojdylak)

This PR was merged into the 1.13 branch.

Discussion
----------

| Q               | A                                                            |
|-----------------|--------------------------------------------------------------|
| Branch?         | 1.13
| Bug fix?        | no
| New feature?    | yes
| BC breaks?      | no
| Deprecations?   | no
| Related tickets | N/A
| License         | MIT


Commits
-------

9e8e797c81 [ApiBundle][ProductTaxon] Move deleting productTaxon to productTaxon resource
59c2798883 [ApiBundle][CatalogPromotion] Add order filters
4036f1f132 [Behat] Add API test coverage for features/promotion/tracking_usage folder
e8f1a0a831 [ApiBundle] Add contract tests for ProductTaxon resource
6de508c911 [ChannelsTest] use inArray to check locales
This commit is contained in:
Grzegorz Sadowski 2023-12-14 07:03:58 +01:00 committed by GitHub
commit 79845047c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 442 additions and 67 deletions

View file

@ -14,7 +14,8 @@ Feature: Modifying taxons assigned to an existing product
@ui @api
Scenario: Modifying taxons assigned to a product
When I change that the "T-Shirt" product belongs to the "T-Shirts" taxon
When I change that the "T-Shirt" product does not belong to the "Clothes" taxon
And I add "T-Shirts" taxon to the "T-Shirt" product
Then the product "T-Shirt" should have the "T-Shirts" taxon
@ui @api

View file

@ -16,16 +16,16 @@ Feature: Not reapplying catalog promotions on variants once the products taxo
And there is disabled catalog promotion "Surprise sale" between "2021-07-01" and "2022-05-04" available in "Web-US" channel that reduces price by "90%" and applies on "Dishes" taxon
And I am logged in as an administrator
@ui
@api @ui
Scenario: Changing products taxon to taxon with scheduled catalog promotion
When I change that the "T-Shirt" product does not belong to the "Clothes" taxon
And I change that the "T-Shirt" product belongs to the "Shirts" taxon
And I add "Shirts" taxon to the "T-Shirt" product
Then the visitor should see that the "PHP T-Shirt" variant is not discounted
And the visitor should still see "$100.00" as the price of the "T-Shirt" product in the "Web-US" channel
@ui
@api @ui
Scenario: Changing products taxon to taxon with disabled catalog promotion
When I change that the "T-Shirt" product does not belong to the "Clothes" taxon
And I change that the "T-Shirt" product belongs to the "Dishes" taxon
And I add "Dishes" taxon to the "T-Shirt" product
Then the visitor should see that the "PHP T-Shirt" variant is not discounted
And the visitor should still see "$100.00" as the price of the "T-Shirt" product in the "Web-US" channel

View file

@ -16,12 +16,12 @@ Feature: Reapplying catalog promotions on variants once the products taxon ch
And there is another catalog promotion "Summer sale" that reduces price by "50%" and applies on "Dishes" taxon
And I am logged in as an administrator
@ui
@api @ui
Scenario: Removing a taxon from a product
When I change that the "T-Shirt" product does not belong to the "Clothes" taxon
Then the visitor should see that the "PHP T-Shirt" variant is not discounted
@ui @api
@api @ui
Scenario: Adding a taxon to a product
When I assign the "Dishes" taxon to the "Mug" product
Then the visitor should see that the "PHP Mug" variant is discounted from "$10.00" to "$5.00" with "Summer sale" promotion

View file

@ -16,69 +16,69 @@ Feature: Sorting listed catalog promotion
And its priority is 2
And I am logged in as an administrator
@ui
@api @ui
Scenario: Catalog promotions are sorted by ascending code by default
When I browse catalog promotions
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "a"
@ui
@api @ui
Scenario: Changing the code sorting order to descending
When I browse catalog promotions
And I sort catalog promotions by descending code
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "not-b"
@ui
@api @ui
Scenario: Sorting catalog promotions by name in ascending order
When I browse catalog promotions
And I sort catalog promotions by ascending name
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "a"
@ui
@api @ui
Scenario: Sorting catalog promotion by name in descending order
When I browse catalog promotions
And I sort catalog promotions by descending name
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "c"
@ui @no-postgres
@api @ui @no-postgres
Scenario: Sorting catalog promotion by start date in ascending order
When I browse catalog promotions
And I sort catalog promotions by ascending "start date"
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "not-b"
@ui @no-postgres
@api @ui @no-postgres
Scenario: Sorting catalog promotion by start date in descending order
When I browse catalog promotions
And I sort catalog promotions by descending "start date"
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "a"
@ui @no-postgres
@api @ui @no-postgres
Scenario: Sorting catalog promotion by end date in ascending order
When I browse catalog promotions
And I sort catalog promotions by ascending "end date"
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "a"
@ui @no-postgres
@api @ui @no-postgres
Scenario: Sorting catalog promotion by end date in descending order
When I browse catalog promotions
And I sort catalog promotions by descending "end date"
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "c"
@ui
@api @ui
Scenario: Sorting catalog promotion by priority in ascending order
When I browse catalog promotions
And I sort catalog promotions by ascending priority
Then I should see 3 catalog promotions on the list
And the first catalog promotion should have code "not-b"
@ui
@api @ui
Scenario: Sorting catalog promotion by priority in descending order
When I browse catalog promotions
And I sort catalog promotions by descending priority

View file

@ -16,7 +16,7 @@ Feature: Checking a promotion usage after placing an order
And there is a promotion "Christmas promotion"
And I am logged in as an administrator
@ui
@api @ui
Scenario: Seeing item fixed discount promotion usage unchanged after order placement
Given the promotion gives "$10.00" off on every product with minimum price at "$50.00"
And the promotion gives another "$5.00" off on every product classified as "T-Shirts"
@ -26,7 +26,7 @@ Feature: Checking a promotion usage after placing an order
When I browse promotions
Then the promotion "Christmas promotion" should not be used
@ui
@api @ui
Scenario: Seeing item fixed discount promotion usage increased after order placement
Given the promotion gives "$10.00" off on every product with minimum price at "$50.00"
And the promotion gives another "$5.00" off on every product classified as "Mugs"
@ -36,7 +36,7 @@ Feature: Checking a promotion usage after placing an order
When I browse promotions
Then the promotion "Christmas promotion" should be used 1 time
@ui
@api @ui
Scenario: Seeing shipping percentage discount promotion usage unchanged after order placement
Given the promotion gives "100%" discount on shipping to every order
And there is a customer "john.doe@gmail.com" that placed an order "#00000022"

View file

@ -12,7 +12,7 @@ Feature: Decreasing a promotion coupon usage after cancelling an order
And the store has promotion "Christmas sale" with coupon "SANTA2016"
And I am logged in as an administrator
@ui
@api @ui
Scenario: Seeing promotion coupon usage decreased after order cancellation
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt" using "SANTA2016" coupon
@ -21,7 +21,7 @@ Feature: Decreasing a promotion coupon usage after cancelling an order
When I browse all coupons of "Christmas sale" promotion
Then "SANTA2016" coupon should be used 0 times
@ui
@api @ui
Scenario: Seeing promotion coupon usage decreased to 1 after second order cancellation
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt" using "SANTA2016" coupon

View file

@ -12,7 +12,7 @@ Feature: Decreasing a promotion usage after cancelling an order
And there is a promotion "Limited promotion" limited to 5 usages
And I am logged in as an administrator
@ui
@api @ui
Scenario: Seeing promotion usage decreased after order cancellation
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt"

View file

@ -12,7 +12,7 @@ Feature: Increasing a promotion coupon usage after placing an order
And the store has promotion "Christmas sale" with coupon "SANTA2016"
And I am logged in as an administrator
@ui
@api @ui
Scenario: Seeing promotion coupon usage increased after order placement
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt" using "SANTA2016" coupon
@ -20,7 +20,7 @@ Feature: Increasing a promotion coupon usage after placing an order
When I browse all coupons of "Christmas sale" promotion
Then "SANTA2016" coupon should be used 1 time
@ui
@api @ui
Scenario: Seeing promotion coupon usage increased correctly after few orders placement
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt" using "SANTA2016" coupon

View file

@ -13,7 +13,7 @@ Feature: Increasing a promotion usage after placing an order
And it gives "$10.00" discount to every order
And I am logged in as an administrator
@ui
@api @ui
Scenario: Seeing promotion usage increased after order placement
Given there is a customer "john.doe@gmail.com" that placed an order "#00000022"
And the customer bought a single "PHP T-Shirt"

View file

@ -888,6 +888,18 @@ final class ManagingCatalogPromotionsContext implements Context
$this->client->filter();
}
/**
* @When I sort catalog promotions by :order :field
*/
public function iSortCatalogPromotionByOrderField(string $order, string $field): void
{
$this->client->addFilter(
sprintf('order[%s]', lcfirst(str_replace(' ', '', ucwords($field)))),
$order === 'descending' ? 'desc' : 'asc',
);
$this->client->filter();
}
/**
* @When I request the removal of :catalogPromotion catalog promotion
*/
@ -1554,6 +1566,24 @@ final class ManagingCatalogPromotionsContext implements Context
);
}
/**
* @Then I should see :count catalog promotions on the list
*/
public function iShouldSeeCountCatalogPromotionsOnTheList(int $count): void
{
Assert::count($this->responseChecker->getCollection($this->client->getLastResponse()), $count);
}
/**
* @Then the first catalog promotion should have code :code
*/
public function theFirstCatalogPromotionShouldHaveCode(string $code): void
{
$catalogPromotions = $this->responseChecker->getCollection($this->client->getLastResponse());
Assert::same(reset($catalogPromotions)['code'], $code);
}
private function catalogPromotionAppliesOnVariants(ProductVariantInterface ...$productVariants): bool
{
$response = $this->responseChecker->getResponseContent($this->client->getLastResponse());

View file

@ -28,21 +28,11 @@ final class ManagingProductTaxonsContext implements Context
{
}
/**
* @When I change that the :product product belongs to the :taxon taxon
*/
public function iChangeThatTheProductBelongsToTheTaxon(ProductInterface $product, TaxonInterface $taxon): void
{
$this->client->buildUpdateRequest(Resources::PRODUCT_TAXONS, (string) $product->getProductTaxons()->current()->getId());
$this->client->updateRequestData(['taxon' => $this->iriConverter->getIriFromResource($taxon)]);
$this->client->update();
}
/**
* @When I assign the :taxon taxon to the :product product
* @When I (try to) add :taxon taxon to the :product product
*/
public function iAddTaxonToTheProduct(TaxonInterface $taxon, ProductInterface $product): void
public function iAddTaxonToTheProduct(ProductInterface $product, TaxonInterface $taxon): void
{
$this->client->buildCreateRequest(Resources::PRODUCT_TAXONS);
$this->client->addRequestData('taxon', $this->iriConverter->getIriFromResource($taxon));
@ -76,15 +66,22 @@ final class ManagingProductTaxonsContext implements Context
public function iTryToAssignTheProductTaxonOfProductAndTaxonToTheProduct(
ProductInterface $productTaxonProduct,
TaxonInterface $productTaxonTaxon,
ProductInterface $product,
): void {
$productTaxon = $productTaxonProduct->getProductTaxons()->filter(
fn (ProductTaxonInterface $productTaxon) => $productTaxonTaxon === $productTaxon->getTaxon(),
$this->iAddTaxonToTheProduct($productTaxonProduct, $productTaxonTaxon);
}
/**
* @When I change that the :product product does not belong to the :taxon taxon
*/
public function iChangeThatTheProductDoesNotBelongToTheTaxon(
ProductInterface $product,
TaxonInterface $taxon,
): void {
$productTaxon = $product->getProductTaxons()->filter(
fn (ProductTaxonInterface $productTaxon) => $taxon === $productTaxon->getTaxon(),
)->first();
$this->client->buildUpdateRequest(Resources::PRODUCTS, $product->getCode());
$this->client->addRequestData('productTaxons', [$this->iriConverter->getIriFromResource($productTaxon)]);
$this->client->update();
$this->client->delete(Resources::PRODUCT_TAXONS, (string) $productTaxon->getId());
}
/**

View file

@ -557,13 +557,13 @@ final class ManagingProductsContext implements Context
*/
public function thisProductTaxonShouldBe(ProductInterface $product, TaxonInterface $taxon): void
{
$productTaxonId = $this->getProductTaxonId($product);
$response = $this->client->show(Resources::PRODUCT_TAXONS, (string) $productTaxonId);
$productTaxonIri = $this->responseChecker->getValue($response, 'taxon');
$productTaxonCodes = explode('/', $productTaxonIri);
Assert::same(array_pop($productTaxonCodes), $taxon->getCode());
$this->client->index(Resources::PRODUCT_TAXONS);
Assert::true(
$this->responseChecker->hasItemWithValues($this->client->getLastResponse(), [
'product' => $this->sectionAwareIriConverter->getIriFromResourceInSection($product, 'admin'),
'taxon' => $this->sectionAwareIriConverter->getIriFromResourceInSection($taxon, 'admin'),
])
);
}
/**
@ -871,14 +871,6 @@ final class ManagingProductsContext implements Context
return $this->sharedStorage->has('response') ? $this->sharedStorage->get('response') : $this->client->getLastResponse();
}
private function getProductTaxonId(ProductInterface $product): string
{
$productResponse = $this->client->show(Resources::PRODUCTS, (string) $product->getCode());
$productTaxonUrl = explode('/', $this->responseChecker->getValue($productResponse, 'productTaxons')[0]);
return array_pop($productTaxonUrl);
}
private function getAttributeValueInProperType(
ProductAttributeInterface $productAttribute,
string $value,

View file

@ -40,6 +40,7 @@ final class ManagingPromotionCouponsContext implements Context
/**
* @Given /^I am browsing coupons of (this promotion)$/
* @When /^I want to view all coupons of (this promotion)$/
* @When /^I browse all coupons of ("[^"]+" promotion)$/
*/
public function iWantToViewAllCouponsOfThisPromotion(PromotionInterface $promotion): void
{
@ -610,6 +611,24 @@ final class ManagingPromotionCouponsContext implements Context
Assert::false($this->responseChecker->hasValue($this->client->update(), 'code', 'NEW_CODE'));
}
/**
* @Then /^("[^"]+" coupon) should be used (\d+) time(?:|s)$/
*/
public function couponShouldHaveUsageLimit(PromotionCouponInterface $promotionCoupon, int $used): void
{
$returnedPromotionCoupon = current($this->responseChecker->getCollectionItemsWithValue(
$this->client->getLastResponse(),
'code',
$promotionCoupon->getCode(),
));
Assert::same(
$returnedPromotionCoupon['used'],
$used,
sprintf('The promotion coupon %s has been used %s times', $promotionCoupon->getCode(), $returnedPromotionCoupon['used']),
);
}
private function sortBy(string $order, string $field): void
{
$this->client->sort([$field => str_starts_with($order, 'de') ? 'desc' : 'asc']);

View file

@ -827,6 +827,25 @@ final class ManagingPromotionsContext implements Context
Assert::same($item[$field], $value);
}
/**
* @Then the promotion :promotion should be used :usage time(s)
* @Then the promotion :promotion should not be used
*/
public function thePromotionShouldBeUsedTime(PromotionInterface $promotion, int $usage = 0): void
{
$returnedPromotion = current($this->responseChecker->getCollectionItemsWithValue(
$this->client->getLastResponse(),
'code',
$promotion->getCode()
));
Assert::same(
$returnedPromotion['used'],
$usage,
sprintf('The promotion %s has been used %s times', $promotion->getName(), $returnedPromotion['used']),
);
}
private function addToRequestAction(string $type, array $configuration): void
{
$data['actions'][] = [

View file

@ -25,11 +25,10 @@ final class ManagingProductTaxonsContext implements Context
}
/**
* @When I change that the :product product belongs to the :taxon taxon
* @When I add :taxon taxon to the :product product
* @When I assign the :taxon taxon to the :product product
*/
public function iChangeThatTheProductBelongsToTheTaxon(ProductInterface $product, TaxonInterface $taxon): void
public function iAddTaxonToTheProduct(ProductInterface $product, TaxonInterface $taxon): void
{
$this->updateSimpleProductPage->open(['id' => $product->getId()]);
$this->updateSimpleProductPage->selectProductTaxon($taxon);

View file

@ -27,6 +27,7 @@ default:
- sylius.behat.context.setup.order
- sylius.behat.context.setup.payment
- sylius.behat.context.setup.product
- sylius.behat.context.setup.product_taxon
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.taxonomy

View file

@ -44,8 +44,11 @@ final class ProductTaxonDataPersister implements ContextAwareDataPersisterInterf
$this->eventBus->dispatch(new ProductUpdated($product->getCode()));
}
/** @param ProductTaxonInterface $data */
public function remove($data, array $context = [])
{
return $this->decoratedDataPersister->remove($data, $context);
$this->decoratedDataPersister->remove($data, $context);
$this->eventBus->dispatch(new ProductUpdated($data->getProduct()->getCode()));
}
}

View file

@ -29,6 +29,11 @@
<attribute>sylius.api.catalog_promotion_start_date_filter</attribute>
<attribute>sylius.api.catalog_promotion_end_date_filter</attribute>
<attribute>Sylius\Bundle\ApiBundle\Filter\Doctrine\CatalogPromotionChannelFilter</attribute>
<attribute>sylius.api.order_filter.code</attribute>
<attribute>sylius.api.order_filter.name</attribute>
<attribute>sylius.api.order_filter.start_date</attribute>
<attribute>sylius.api.order_filter.end_date</attribute>
<attribute>sylius.api.order_filter.priority</attribute>
</attribute>
<attribute name="normalization_context">
<attribute name="groups">admin:catalog_promotion:read</attribute>

View file

@ -14,6 +14,10 @@
<attribute name="normalization_context">
<attribute name="groups">admin:product_taxon:read</attribute>
</attribute>
<attribute name="filters">
<attribute>sylius.api.search_filter.product.code</attribute>
<attribute>sylius.api.search_filter.taxon.code</attribute>
</attribute>
</collectionOperation>
<collectionOperation name="admin_post">
<attribute name="method">POST</attribute>
@ -46,6 +50,11 @@
<attribute name="groups">shop:product_taxon:read</attribute>
</attribute>
</itemOperation>
<itemOperation name="admin_delete">
<attribute name="method">DELETE</attribute>
<attribute name="path">/admin/product-taxons/{id}</attribute>
</itemOperation>
</itemOperations>
<property name="id" identifier="true" writable="false" />

View file

@ -59,8 +59,6 @@
</attribute>
<attribute name="productTaxons">
<group>admin:product:read</group>
<group>admin:product:create</group>
<group>admin:product:update</group>
<group>shop:product:read</group>
</attribute>
<attribute name="options">

View file

@ -32,5 +32,11 @@
<group>admin:product_taxon:create</group>
<group>shop:product_taxon:read</group>
</attribute>
<attribute name="position">
<group>admin:product_taxon:read</group>
<group>admin:product_taxon:update</group>
<group>admin:product_taxon:create</group>
<group>shop:product_taxon:read</group>
</attribute>
</class>
</serializer>

View file

@ -339,5 +339,55 @@
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.search_filter.product.code" parent="api_platform.doctrine.orm.search_filter" public="true">
<argument type="collection">
<argument key="product.code">exact</argument>
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.search_filter.taxon.code" parent="api_platform.doctrine.orm.search_filter" public="true">
<argument type="collection">
<argument key="taxon.code">exact</argument>
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.order_filter.code" parent="api_platform.doctrine.orm.order_filter" public="true">
<argument type="collection">
<argument key="code" />
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.order_filter.name" parent="api_platform.doctrine.orm.order_filter" public="true">
<argument type="collection">
<argument key="name" />
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.order_filter.start_date" parent="api_platform.doctrine.orm.order_filter" public="true">
<argument type="collection">
<argument key="startDate" />
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.order_filter.end_date" parent="api_platform.doctrine.orm.order_filter" public="true">
<argument type="collection">
<argument key="endDate" />
</argument>
<tag name="api_platform.filter" />
</service>
<service id="sylius.api.order_filter.priority" parent="api_platform.doctrine.orm.order_filter" public="true">
<argument type="collection">
<argument key="priority" />
</argument>
<tag name="api_platform.filter" />
</service>
</services>
</container>

View file

@ -39,8 +39,15 @@ final class ProductTaxonDataPersisterSpec extends ObjectBehavior
function it_uses_decorated_data_persister_to_remove_product_taxon(
ContextAwareDataPersisterInterface $decoratedDataPersister,
ProductTaxonInterface $productTaxon,
ProductInterface $product,
MessageBusInterface $eventBus,
): void {
$productTaxon->getProduct()->willReturn($product);
$product->getCode()->willReturn('t_shirt');
$message = new ProductUpdated('t_shirt');
$decoratedDataPersister->remove($productTaxon, [])->shouldBeCalled();
$eventBus->dispatch($message)->willReturn(new Envelope($message))->shouldBeCalled();
$this->remove($productTaxon, []);
}

View file

@ -0,0 +1,135 @@
<?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\ProductInterface;
use Sylius\Component\Core\Model\ProductTaxonInterface;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Tests\Api\JsonApiTestCase;
use Sylius\Tests\Api\Utils\AdminUserLoginTrait;
use Symfony\Component\HttpFoundation\Response;
final class ProductTaxonsTest extends JsonApiTestCase
{
use AdminUserLoginTrait;
/** @test */
public function it_gets_a_product_taxon(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'product/product_taxon.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var ProductTaxonInterface $productTaxon */
$productTaxon = $fixtures['product_mug_taxon_mugs'];
$this->client->request(
method: 'GET',
uri: sprintf('/api/v2/admin/product-taxons/%s', $productTaxon->getId()),
server: $header,
);
$this->assertResponse(
$this->client->getResponse(),
'admin/product_taxon/get_product_taxon_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_gets_product_taxons(): void
{
$this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'product/product_taxon.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
$this->client->request(method: 'GET', uri: '/api/v2/admin/product-taxons', server: $header);
$this->assertResponse(
$this->client->getResponse(),
'admin/product_taxon/get_product_taxons_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_creates_a_product_taxon(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'product/product_taxon.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var ProductInterface $product */
$product = $fixtures['product_mug'];
/** @var TaxonInterface $taxon */
$taxon = $fixtures['taxon_caps'];
$this->client->request(
method: 'POST',
uri: '/api/v2/admin/product-taxons',
server: $header,
content: json_encode([
'product' => sprintf('/api/v2/admin/products/%s', $product->getCode()),
'taxon' => sprintf('/api/v2/admin/taxons/%s', $taxon->getCode()),
'position' => 10,
], \JSON_THROW_ON_ERROR),
);
$this->assertResponse(
$this->client->getResponse(),
'admin/product_taxon/post_product_taxon_response',
Response::HTTP_CREATED,
);
}
/** @test */
public function it_updates_a_product_taxon(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'product/product_taxon.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var ProductTaxonInterface $productTaxon */
$productTaxon = $fixtures['product_cap_taxon_caps'];
$this->client->request(
method: 'PUT',
uri: sprintf('/api/v2/admin/product-taxons/%s', $productTaxon->getId()),
server: $header,
content: json_encode([
'position' => 1,
], \JSON_THROW_ON_ERROR),
);
$this->assertResponse(
$this->client->getResponse(),
'admin/product_taxon/put_product_taxon_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_deletes_a_product_taxon(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'product/product_taxon.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var ProductTaxonInterface $productTaxon */
$productTaxon = $fixtures['product_cap_taxon_caps'];
$this->client->request(
method: 'DELETE',
uri: sprintf('/api/v2/admin/product-taxons/%s', $productTaxon->getId()),
server: $header,
);
$this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT);
}
}

View file

@ -0,0 +1,25 @@
Sylius\Component\Core\Model\Product:
product_mug:
code: 'MUG'
channels: ['@channel_web']
currentLocale: 'en_US'
product_cap:
code: 'CAP'
channels: ['@channel_web']
currentLocale: 'en_US'
Sylius\Component\Core\Model\Taxon:
taxon_mugs:
code: 'MUGS'
taxon_caps:
code: 'CAPS'
Sylius\Component\Core\Model\ProductTaxon:
product_mug_taxon_mugs:
product: '@product_mug'
taxon: '@taxon_mugs'
position: 1
product_cap_taxon_caps:
product: '@product_cap'
taxon: '@taxon_caps'
position: 2

View file

@ -13,10 +13,7 @@
"defaultTaxZone": null,
"taxCalculationStrategy": "order_items_based",
"currencies": [],
"locales": [
"\/api\/v2\/admin\/locales\/en_US",
"\/api\/v2\/admin\/locales\/pl_PL"
],
"locales": "@array@.inArray(\"/api\/v2\/admin\/locales\/en_US\").inArray(\"\/api\/v2\/admin\/locales\/pl_PL\")",
"countries": [],
"themeName": null,
"contactEmail": "web@sylius.com",

View file

@ -0,0 +1,9 @@
{
"@context": "\/api\/v2\/contexts\/ProductTaxon",
"@id": "\/api\/v2\/admin\/product-taxons\/@integer@",
"@type": "ProductTaxon",
"id": @integer@,
"product": "\/api\/v2\/admin\/products\/MUG",
"taxon": "\/api\/v2\/admin\/taxons\/MUGS",
"position": 1
}

View file

@ -0,0 +1,55 @@
{
"@context": "\/api\/v2\/contexts\/ProductTaxon",
"@id": "\/api\/v2\/admin\/product-taxons",
"@type": "hydra:Collection",
"hydra:member": [
{
"@id": "\/api\/v2\/admin\/product-taxons\/@integer@",
"@type": "ProductTaxon",
"id": @integer@,
"product": "\/api\/v2\/admin\/products\/MUG",
"taxon": "\/api\/v2\/admin\/taxons\/MUGS",
"position": 1
},
{
"@id": "\/api\/v2\/admin\/product-taxons\/@integer@",
"@type": "ProductTaxon",
"id": @integer@,
"product": "\/api\/v2\/admin\/products\/CAP",
"taxon": "\/api\/v2\/admin\/taxons\/CAPS",
"position": 2
}
],
"hydra:totalItems": 2,
"hydra:search": {
"@type": "hydra:IriTemplate",
"hydra:template": "\/api\/v2\/admin\/product-taxons{?product.code,product.code[],taxon.code,taxon.code[]}",
"hydra:variableRepresentation": "BasicRepresentation",
"hydra:mapping": [
{
"@type": "IriTemplateMapping",
"variable": "product.code",
"property": "product.code",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "product.code[]",
"property": "product.code",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "taxon.code",
"property": "taxon.code",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "taxon.code[]",
"property": "taxon.code",
"required": false
}
]
}
}

View file

@ -0,0 +1,9 @@
{
"@context": "\/api\/v2\/contexts\/ProductTaxon",
"@id": "\/api\/v2\/admin\/product-taxons\/@integer@",
"@type": "ProductTaxon",
"id": @integer@,
"product": "\/api\/v2\/admin\/products\/MUG",
"taxon": "\/api\/v2\/admin\/taxons\/CAPS",
"position": 10
}

View file

@ -0,0 +1,9 @@
{
"@context": "\/api\/v2\/contexts\/ProductTaxon",
"@id": "\/api\/v2\/admin\/product-taxons\/@integer@",
"@type": "ProductTaxon",
"id": @integer@,
"product": "\/api\/v2\/admin\/products\/CAP",
"taxon": "\/api\/v2\/admin\/taxons\/CAPS",
"position": 1
}