Repository: saleor/saleor

Issue:
Saleor will authorize and charge more than the order's total if allowed
### What I'm trying to achieve
I'm using the GraphQL API to create a checkout session and pay for it using Locust. Due to a copy-and-paste bug in my stress test suite, the total amount passed to `checkoutPaymentCreate` is higher than the order's total.

### Steps to reproduce the problem
1. Create a checkout session with `checkoutCreate`
2. Prepare the checkout sessions as needed (add billing and shipping addresses etc.)
3. Use the `checkoutPaymentCreate` mutation and pass a much higher `amount` that what the checkout object returns as total
4. Call `checkoutComplete` and observe that the store proceeds to capture more than the order's total

### What I expected to happen
Either get an error when attempting to create a payment object for the checkout or have the store automatically adjust the total down when capturing the payment.

### Screenshots
![image](https://user-images.githubusercontent.com/81205/58415794-dc7ea500-807f-11e9-8a52-271b94e0bc1b.png)


Discussion:
Hi @maarcingebala , is this one related to some PR already opened ? 😄 

@iflare3g no, it's free to take
> @iflare3g no, it's free to take

Ok thanks, because before I've already opened a PR that was covered by an existing one.
So now it's better to ask you before working on it.

Resolving patch:
diff --git a/saleor/graphql/payment/mutations.py b/saleor/graphql/payment/mutations.py
--- a/saleor/graphql/payment/mutations.py
+++ b/saleor/graphql/payment/mutations.py
@@ -92,7 +92,7 @@ def perform_mutation(cls, _root, info, checkout_id, **data):
         )
         checkout_total = max(checkout_total, zero_taxed_money(checkout_total.currency))
         amount = data.get("amount", checkout_total.gross.amount)
-        if amount < checkout_total.gross.amount:
+        if amount != checkout_total.gross.amount:
             raise ValidationError(
                 {
                     "amount": ValidationError(


Test patch:
diff --git a/tests/api/test_payment.py b/tests/api/test_payment.py
--- a/tests/api/test_payment.py
+++ b/tests/api/test_payment.py
@@ -120,6 +120,58 @@ def test_checkout_add_payment(
     assert payment.charge_status == ChargeStatus.NOT_CHARGED
 
 
+def test_checkout_add_payment_default_amount(
+    user_api_client, checkout_with_item, graphql_address_data
+):
+    checkout = checkout_with_item
+    checkout_id = graphene.Node.to_global_id("Checkout", checkout.pk)
+    total = checkout.get_total()
+    total = TaxedMoney(net=total, gross=total)
+
+    variables = {
+        "checkoutId": checkout_id,
+        "input": {
+            "gateway": "DUMMY",
+            "token": "sample-token",
+            "billingAddress": graphql_address_data,
+        },
+    }
+    response = user_api_client.post_graphql(CREATE_QUERY, variables)
+    content = get_graphql_content(response)
+    data = content["data"]["checkoutPaymentCreate"]
+    assert not data["errors"]
+    transactions = data["payment"]["transactions"]
+    assert not transactions
+    payment = Payment.objects.get()
+    assert payment.checkout == checkout
+    assert payment.is_active
+    assert payment.token == "sample-token"
+    assert payment.total == total.gross.amount
+    assert payment.currency == total.gross.currency
+    assert payment.charge_status == ChargeStatus.NOT_CHARGED
+
+
+def test_checkout_add_payment_bad_amount(
+    user_api_client, checkout_with_item, graphql_address_data
+):
+    checkout = checkout_with_item
+    checkout_id = graphene.Node.to_global_id("Checkout", checkout.pk)
+
+    variables = {
+        "checkoutId": checkout_id,
+        "input": {
+            "gateway": "DUMMY",
+            "token": "sample-token",
+            "amount": str(checkout.get_total().amount + Decimal(1)),
+            "billingAddress": graphql_address_data,
+        },
+    }
+    response = user_api_client.post_graphql(CREATE_QUERY, variables)
+    content = get_graphql_content(response)
+    data = content["data"]["checkoutPaymentCreate"]
+    assert data["errors"]
+
+
 def test_use_checkout_billing_address_as_payment_billing(
     user_api_client, checkout_with_item, address
 ):