mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-13 08:31:32 +00:00
Add contract test for Promotion
This commit is contained in:
parent
f4a3a3e722
commit
609931506e
6 changed files with 518 additions and 1 deletions
|
|
@ -15,7 +15,18 @@ namespace Sylius\Tests\Api\Admin;
|
|||
|
||||
use Sylius\Component\Core\Model\PromotionInterface;
|
||||
use Sylius\Component\Core\Promotion\Action\FixedDiscountPromotionActionCommand;
|
||||
use Sylius\Component\Core\Promotion\Action\PercentageDiscountPromotionActionCommand;
|
||||
use Sylius\Component\Core\Promotion\Action\ShippingPercentageDiscountPromotionActionCommand;
|
||||
use Sylius\Component\Core\Promotion\Action\UnitFixedDiscountPromotionActionCommand;
|
||||
use Sylius\Component\Core\Promotion\Action\UnitPercentageDiscountPromotionActionCommand;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\ContainsProductRuleChecker;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\CustomerGroupRuleChecker;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\HasTaxonRuleChecker;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\NthOrderRuleChecker;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\ShippingCountryRuleChecker;
|
||||
use Sylius\Component\Core\Promotion\Checker\Rule\TotalOfItemsFromTaxonRuleChecker;
|
||||
use Sylius\Component\Promotion\Checker\Rule\CartQuantityRuleChecker;
|
||||
use Sylius\Component\Promotion\Checker\Rule\ItemTotalRuleChecker;
|
||||
use Sylius\Tests\Api\JsonApiTestCase;
|
||||
use Sylius\Tests\Api\Utils\AdminUserLoginTrait;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
|
@ -64,7 +75,14 @@ final class PromotionsTest extends JsonApiTestCase
|
|||
/** @test */
|
||||
public function it_creates_promotion(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml']);
|
||||
$this->loadFixturesFromFiles([
|
||||
'authentication/api_administrator.yaml',
|
||||
'channel.yaml',
|
||||
'country.yaml',
|
||||
'customer_group.yaml',
|
||||
'promotion/product.yaml',
|
||||
'promotion/taxon.yaml',
|
||||
]);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
$this->client->request(
|
||||
|
|
@ -95,6 +113,60 @@ final class PromotionsTest extends JsonApiTestCase
|
|||
'count' => 6
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => CustomerGroupRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'group_code' => 'vip'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => NthOrderRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'nth' => 2
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ShippingCountryRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'country' => 'US'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => HasTaxonRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'taxons' => ['MUGS', 'CAPS']
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => TotalOfItemsFromTaxonRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'taxon' => 'MUGS',
|
||||
'amount' => 1000,
|
||||
],
|
||||
'MOBILE' => [
|
||||
'taxon' => 'CAPS',
|
||||
'amount' => 2000,
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ContainsProductRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'product_code' => 'CAP',
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ItemTotalRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'amount' => 333,
|
||||
],
|
||||
'MOBILE' => [
|
||||
'amount' => 222,
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => [
|
||||
[
|
||||
|
|
@ -103,6 +175,49 @@ final class PromotionsTest extends JsonApiTestCase
|
|||
'WEB' => [
|
||||
'amount' => 1000,
|
||||
],
|
||||
'MOBILE' => [
|
||||
'amount' => 2000,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => UnitFixedDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'amount' => 3000,
|
||||
'filters' => [
|
||||
'price_range_filter' => [
|
||||
'min' => 1000,
|
||||
'max' => 10000,
|
||||
],
|
||||
],
|
||||
],
|
||||
'MOBILE' => [
|
||||
'amount' => 4000,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => PercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'percentage' => 5,
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => UnitPercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'percentage' => 10,
|
||||
],
|
||||
'MOBILE' => [
|
||||
'percentage' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ShippingPercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'percentage' => 20,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
|
@ -185,6 +300,145 @@ final class PromotionsTest extends JsonApiTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_create_a_promotion_with_invalid_rules(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
$this->client->request(
|
||||
method: 'POST',
|
||||
uri: '/api/v2/admin/promotions',
|
||||
server: $header,
|
||||
content: json_encode([
|
||||
'name' => 'T-Shirts discount',
|
||||
'code' => 'tshirts_discount',
|
||||
'rules' => [
|
||||
[
|
||||
'type' => CartQuantityRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'count' => 'invalid'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => CustomerGroupRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'group_code' => 'wrong'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => NthOrderRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'nth' => 'invalid'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ShippingCountryRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'country' => 'wrong'
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => HasTaxonRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'taxons' => ['wrong']
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => TotalOfItemsFromTaxonRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'taxon' => 'wrong',
|
||||
'amount' => 'invalid',
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ContainsProductRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'product_code' => 'wrong',
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ItemTotalRuleChecker::TYPE,
|
||||
'configuration' => [
|
||||
'MOBILE' => [
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
], JSON_THROW_ON_ERROR),
|
||||
);
|
||||
|
||||
$this->assertResponse(
|
||||
$this->client->getResponse(),
|
||||
'admin/promotion/post_promotion_with_invalid_rules_response',
|
||||
Response::HTTP_UNPROCESSABLE_ENTITY,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_create_a_promotion_with_invalid_actions(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
$this->client->request(
|
||||
method: 'POST',
|
||||
uri: '/api/v2/admin/promotions',
|
||||
server: $header,
|
||||
content: json_encode([
|
||||
'name' => 'T-Shirts discount',
|
||||
'code' => 'tshirts_discount',
|
||||
'actions' => [
|
||||
[
|
||||
'type' => FixedDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'amount' => 'invalid',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => UnitFixedDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'filters' => 'invalid'
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => PercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'percentage' => -5,
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => UnitPercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
'WEB' => [
|
||||
'percentage' => 110,
|
||||
],
|
||||
'MOBILE' => [
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => ShippingPercentageDiscountPromotionActionCommand::TYPE,
|
||||
'configuration' => [
|
||||
],
|
||||
],
|
||||
],
|
||||
], JSON_THROW_ON_ERROR),
|
||||
);
|
||||
|
||||
$this->assertResponse(
|
||||
$this->client->getResponse(),
|
||||
'admin/promotion/post_promotion_with_invalid_actions_response',
|
||||
Response::HTTP_UNPROCESSABLE_ENTITY,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_updates_promotion(): void
|
||||
{
|
||||
|
|
|
|||
9
tests/Api/DataFixtures/ORM/promotion/product.yaml
Normal file
9
tests/Api/DataFixtures/ORM/promotion/product.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Sylius\Component\Core\Model\Product:
|
||||
product_cap:
|
||||
code: 'CAP'
|
||||
channels: ['@channel_web']
|
||||
currentLocale: 'en_US'
|
||||
product_socks:
|
||||
code: 'SOCKS'
|
||||
channels: ['@channel_web']
|
||||
currentLocale: 'en_US'
|
||||
5
tests/Api/DataFixtures/ORM/promotion/taxon.yaml
Normal file
5
tests/Api/DataFixtures/ORM/promotion/taxon.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Sylius\Component\Core\Model\Taxon:
|
||||
taxon_mugs:
|
||||
code: 'MUGS'
|
||||
taxon_caps:
|
||||
code: 'CAPS'
|
||||
|
|
@ -26,6 +26,84 @@
|
|||
"configuration": {
|
||||
"count": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "customer_group",
|
||||
"configuration": {
|
||||
"group_code": "vip"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "nth_order",
|
||||
"configuration": {
|
||||
"nth": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "shipping_country",
|
||||
"configuration": {
|
||||
"country": "US"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "has_taxon",
|
||||
"configuration": {
|
||||
"taxons": [
|
||||
"MUGS",
|
||||
"CAPS"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "total_of_items_from_taxon",
|
||||
"configuration": {
|
||||
"WEB": {
|
||||
"taxon": "MUGS",
|
||||
"amount": 1000
|
||||
},
|
||||
"MOBILE": {
|
||||
"taxon": "CAPS",
|
||||
"amount": 2000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "contains_product",
|
||||
"configuration": {
|
||||
"product_code": "CAP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-rules\/@integer@",
|
||||
"@type": "PromotionRule",
|
||||
"id": @integer@,
|
||||
"type": "item_total",
|
||||
"configuration": {
|
||||
"WEB": {
|
||||
"amount": 333
|
||||
},
|
||||
"MOBILE": {
|
||||
"amount": 222
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
|
|
@ -37,8 +115,63 @@
|
|||
"configuration": {
|
||||
"WEB": {
|
||||
"amount": 1000
|
||||
},
|
||||
"MOBILE": {
|
||||
"amount": 2000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-actions\/@integer@",
|
||||
"@type": "PromotionAction",
|
||||
"id": @integer@,
|
||||
"type": "unit_fixed_discount",
|
||||
"configuration": {
|
||||
"WEB": {
|
||||
"amount": 3000,
|
||||
"filters": {
|
||||
"price_range_filter": {
|
||||
"min": 1000,
|
||||
"max": 10000
|
||||
}
|
||||
}
|
||||
},
|
||||
"MOBILE": {
|
||||
"amount": 4000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-actions\/@integer@",
|
||||
"@type": "PromotionAction",
|
||||
"id": @integer@,
|
||||
"type": "order_percentage_discount",
|
||||
"configuration": {
|
||||
"percentage": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-actions\/@integer@",
|
||||
"@type": "PromotionAction",
|
||||
"id": @integer@,
|
||||
"type": "unit_percentage_discount",
|
||||
"configuration": {
|
||||
"WEB": {
|
||||
"percentage": 10
|
||||
},
|
||||
"MOBILE": {
|
||||
"percentage": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@id": "\/api\/v2\/admin\/promotion-actions\/@integer@",
|
||||
"@type": "PromotionAction",
|
||||
"id": @integer@,
|
||||
"type": "shipping_percentage_discount",
|
||||
"configuration": {
|
||||
"percentage": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"appliesToDiscounted": false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/ConstraintViolationList",
|
||||
"@type": "ConstraintViolationList",
|
||||
"hydra:title": "An error occurred",
|
||||
"hydra:description": "actions[0].configuration[WEB][amount]: This value should be of type numeric.\nactions[0].configuration[MOBILE]: This field is missing.\nactions[1].configuration[WEB][amount]: This field is missing.\nactions[1].configuration[WEB][filters]: This value should be of type array.\nactions[1].configuration[MOBILE]: This field is missing.\nactions[2].configuration[percentage]: The percentage discount must be between 0% and 100%.\nactions[3].configuration[WEB][percentage]: The percentage discount must be between 0% and 100%.\nactions[3].configuration[MOBILE][percentage]: This field is missing.\nactions[4].configuration[percentage]: This field is missing.",
|
||||
"violations": [
|
||||
{
|
||||
"propertyPath": "actions[0].configuration[WEB][amount]",
|
||||
"message": "This value should be of type numeric.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[0].configuration[MOBILE]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[1].configuration[WEB][amount]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[1].configuration[WEB][filters]",
|
||||
"message": "This value should be of type array.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[1].configuration[MOBILE]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[2].configuration[percentage]",
|
||||
"message": "The percentage discount must be between 0% and 100%.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[3].configuration[WEB][percentage]",
|
||||
"message": "The percentage discount must be between 0% and 100%.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[3].configuration[MOBILE][percentage]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "actions[4].configuration[percentage]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/ConstraintViolationList",
|
||||
"@type": "ConstraintViolationList",
|
||||
"hydra:title": "An error occurred",
|
||||
"hydra:description": "rules[0].configuration[count]: This value should be of type numeric.\nrules[1].configuration[group_code]: Customer group with code wrong does not exist.\nrules[2].configuration[nth]: This value should be of type numeric.\nrules[3].configuration[country]: Country with code wrong does not exist.\nrules[4].configuration[taxons][0]: Taxon with code wrong does not exist.\nrules[5].configuration[WEB][amount]: This value should be of type numeric.\nrules[5].configuration[WEB][taxon]: Taxon with code wrong does not exist.\nrules[5].configuration[MOBILE]: This field is missing.\nrules[6].configuration[product_code]: Product with code wrong does not exist.\nrules[7].configuration[WEB]: This field is missing.\nrules[7].configuration[MOBILE][amount]: This field is missing.",
|
||||
"violations": [
|
||||
{
|
||||
"propertyPath": "rules[0].configuration[count]",
|
||||
"message": "This value should be of type numeric.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[1].configuration[group_code]",
|
||||
"message": "Customer group with code wrong does not exist.",
|
||||
"code": null
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[2].configuration[nth]",
|
||||
"message": "This value should be of type numeric.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[3].configuration[country]",
|
||||
"message": "Country with code wrong does not exist.",
|
||||
"code": null
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[4].configuration[taxons][0]",
|
||||
"message": "Taxon with code wrong does not exist.",
|
||||
"code": null
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[5].configuration[WEB][amount]",
|
||||
"message": "This value should be of type numeric.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[5].configuration[WEB][taxon]",
|
||||
"message": "Taxon with code wrong does not exist.",
|
||||
"code": null
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[5].configuration[MOBILE]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[6].configuration[product_code]",
|
||||
"message": "Product with code wrong does not exist.",
|
||||
"code": null
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[7].configuration[WEB]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
},
|
||||
{
|
||||
"propertyPath": "rules[7].configuration[MOBILE][amount]",
|
||||
"message": "This field is missing.",
|
||||
"code": @string@
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue