mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
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 resource59c2798883[ApiBundle][CatalogPromotion] Add order filters4036f1f132[Behat] Add API test coverage for features/promotion/tracking_usage foldere8f1a0a831[ApiBundle] Add contract tests for ProductTaxon resource6de508c911[ChannelsTest] use inArray to check locales
This commit is contained in:
commit
79845047c1
30 changed files with 442 additions and 67 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@ Feature: Not reapplying catalog promotions on variants once the product’s 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
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ Feature: Reapplying catalog promotions on variants once the product’s 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
|
|
|
|||
|
|
@ -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'][] = [
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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, []);
|
||||
}
|
||||
|
|
|
|||
135
tests/Api/Admin/ProductTaxonsTest.php
Normal file
135
tests/Api/Admin/ProductTaxonsTest.php
Normal 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);
|
||||
}
|
||||
}
|
||||
25
tests/Api/DataFixtures/ORM/product/product_taxon.yaml
Normal file
25
tests/Api/DataFixtures/ORM/product/product_taxon.yaml
Normal 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
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue