Repository: saleor/saleor

Issue:
Bug: [Simple Taxes] It is possible to set negative value on tax rate.
### What are you trying to achieve?

Create new tax rate 

### Steps to reproduce the problem

1. go to taxes in configuration 
2. set in countries - in e.g US -default rate eq to "-20"
3. create checkout 

### What did you expect to happen?

It should be not possible to set tax rate as a negative value.

### Logs

![image](https://user-images.githubusercontent.com/29308910/196620931-4295f736-73d7-45d0-b05c-48221b2f5fd7.png)
![image](https://user-images.githubusercontent.com/29308910/196621315-b0aa20bd-cd63-4601-bfe7-1790b4408df1.png)
![image](https://user-images.githubusercontent.com/29308910/196622979-dc4f8a69-2d8b-458c-92f3-5eb357e5421c.png)



### Environment

Saleor version: …
OS and version: …



Discussion:

Resolving patch:
diff --git a/saleor/graphql/tax/mutations/tax_country_configuration_update.py b/saleor/graphql/tax/mutations/tax_country_configuration_update.py
--- a/saleor/graphql/tax/mutations/tax_country_configuration_update.py
+++ b/saleor/graphql/tax/mutations/tax_country_configuration_update.py
@@ -122,9 +122,38 @@ def _clean_tax_class_ids(tax_rate_items):
 
         return cleaned_data
 
+    @classmethod
+    def _clean_rate_values(cls, tax_rate_items):
+        invalid_rates = []
+        for item in tax_rate_items:
+            rate = item.get("rate")
+            if rate is not None and rate < 0:
+                invalid_rates.append(item)
+
+        if invalid_rates:
+            code = (
+                error_codes.TaxCountryConfigurationUpdateErrorCode.CANNOT_CREATE_NEGATIVE_RATE  # noqa: E501
+            )
+            message = "Cannot create rates with negative values."
+            params = {
+                "tax_class_ids": [
+                    item["tax_class_id"]
+                    for item in invalid_rates
+                    if item.get("tax_class_id")
+                ]
+            }
+            raise ValidationError(
+                {
+                    "update_tax_class_rates": ValidationError(
+                        code=code, message=message, params=params
+                    )
+                }
+            )
+
     @classmethod
     def clean_input(cls, **data):
         update_tax_class_rates = data.get("update_tax_class_rates", [])
+        cls._clean_rate_values(update_tax_class_rates)
         cls._clean_default_rates(update_tax_class_rates)
         return cls._clean_tax_class_ids(update_tax_class_rates)
 
diff --git a/saleor/tax/error_codes.py b/saleor/tax/error_codes.py
--- a/saleor/tax/error_codes.py
+++ b/saleor/tax/error_codes.py
@@ -40,6 +40,7 @@ class TaxCountryConfigurationUpdateErrorCode(Enum):
     NOT_FOUND = "not_found"
     ONLY_ONE_DEFAULT_COUNTRY_RATE_ALLOWED = "only_one_default_country_rate_allowed"
     CANNOT_CREATE_WITH_NULL_RATE = "cannot_create_with_null_rate"
+    CANNOT_CREATE_NEGATIVE_RATE = "cannot_create_negative_rate"
 
 
 class TaxCountryConfigurationDeleteErrorCode(Enum):


Test patch:
diff --git a/saleor/graphql/tax/tests/mutations/test_tax_country_configuration_update.py b/saleor/graphql/tax/tests/mutations/test_tax_country_configuration_update.py
--- a/saleor/graphql/tax/tests/mutations/test_tax_country_configuration_update.py
+++ b/saleor/graphql/tax/tests/mutations/test_tax_country_configuration_update.py
@@ -247,3 +247,34 @@ def test_update_default_country_rate_throws_error_with_multiple_rates(
     assert data["errors"]
     code = TaxCountryConfigurationUpdateErrorCode.ONLY_ONE_DEFAULT_COUNTRY_RATE_ALLOWED
     assert data["errors"][0]["code"] == code.name
+
+
+def test_validate_negative_rates(staff_api_client, permission_manage_taxes):
+    # given
+    tax_class_1 = TaxClass.objects.create(name="Books")
+    tax_class_2 = TaxClass.objects.create(name="Accessories")
+
+    id_1 = graphene.Node.to_global_id("TaxClass", tax_class_1.pk)
+    id_2 = graphene.Node.to_global_id("TaxClass", tax_class_2.pk)
+
+    # when
+    variables = {
+        "countryCode": "PL",
+        "updateTaxClassRates": [
+            {"rate": -1},
+            {"taxClassId": id_1, "rate": -1},
+            {"taxClassId": id_2, "rate": 0},
+        ],
+    }
+    response = staff_api_client.post_graphql(
+        MUTATION, variables, permissions=[permission_manage_taxes]
+    )
+
+    # then
+    content = get_graphql_content(response)
+    data = content["data"]["taxCountryConfigurationUpdate"]
+    assert data["errors"]
+    code = TaxCountryConfigurationUpdateErrorCode.CANNOT_CREATE_NEGATIVE_RATE
+    assert data["errors"][0]["code"] == code.name
+    assert len(data["errors"][0]["taxClassIds"]) == 1
+    assert id_1 in data["errors"][0]["taxClassIds"]