Skip to content

Commit

Permalink
Merge pull request saleor#5839 from mirumee/fix-payment-tracking-in-c…
Browse files Browse the repository at this point in the history
…heckout

Fix payment tracking in checkout
  • Loading branch information
maarcingebala authored Jul 3, 2020
2 parents fbaaf6d + b20b6fc commit a6c056e
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 68 deletions.
87 changes: 87 additions & 0 deletions saleor/checkout/tests/test_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ...discount.models import NotApplicable, Voucher
from ...order import OrderEvents, OrderEventsEmails
from ...order.models import OrderEvent
from ...payment.models import Payment
from ...plugins.manager import get_plugins_manager
from ...shipping.models import ShippingZone
from ...tests.utils import flush_post_commit_hooks
Expand All @@ -26,12 +27,14 @@
from ..utils import (
add_variant_to_checkout,
add_voucher_to_checkout,
cancel_active_payments,
change_billing_address_in_checkout,
change_shipping_address_in_checkout,
clear_shipping_method,
create_order,
get_voucher_discount_for_checkout,
get_voucher_for_checkout,
is_fully_paid,
is_valid_shipping_method,
prepare_order_data,
recalculate_checkout_discount,
Expand Down Expand Up @@ -1404,3 +1407,87 @@ def test_store_user_address_create_new_address_if_not_associated(address):

assert user.addresses.count() == expected_user_addresses_count
assert user.default_billing_address_id != address.pk


def test_get_last_active_payment(checkout_with_payments):
# given
payment = Payment.objects.create(
gateway="mirumee.payments.dummy",
is_active=True,
checkout=checkout_with_payments,
)

# when
last_payment = checkout_with_payments.get_last_active_payment()

# then
assert last_payment.pk == payment.pk


def test_is_fully_paid(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert is_paid


def test_is_fully_paid_many_payments(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount - 1
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
payment2 = payment_dummy
payment2.pk = None
payment2.is_active = True
payment2.order = None
payment2.total = 1
payment2.currency = total.gross.currency
payment2.checkout = checkout
payment2.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert is_paid


def test_is_fully_paid_partially_paid(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount - 1
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert not is_paid


def test_is_fully_paid_no_payment(checkout_with_item):
checkout = checkout_with_item
is_paid = is_fully_paid(checkout, list(checkout), None)
assert not is_paid


def test_cancel_active_payments(checkout_with_payments):
# given
checkout = checkout_with_payments
count_active = checkout.payments.filter(is_active=True).count()
assert count_active != 0

# when
cancel_active_payments(checkout)

# then
assert checkout.payments.filter(is_active=True).count() == 0
4 changes: 4 additions & 0 deletions saleor/checkout/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,3 +804,7 @@ def clean_checkout(
"Provided payment methods can not cover the checkout's total amount",
code=CheckoutErrorCode.CHECKOUT_NOT_FULLY_PAID.value,
)


def cancel_active_payments(checkout: Checkout):
checkout.payments.filter(is_active=True).update(is_active=False)
58 changes: 1 addition & 57 deletions saleor/graphql/checkout/tests/test_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ....checkout import calculations
from ....checkout.error_codes import CheckoutErrorCode
from ....checkout.models import Checkout
from ....checkout.utils import add_variant_to_checkout, is_fully_paid
from ....checkout.utils import add_variant_to_checkout
from ....core.payments import PaymentInterface
from ....core.taxes import zero_money
from ....order.models import Order
Expand Down Expand Up @@ -2703,59 +2703,3 @@ def test_clean_checkout_no_payment(checkout_with_item, shipping_method, address)

msg = "Provided payment methods can not cover the checkout's total amount"
assert e.value.error_list[0].message == msg


def test_is_fully_paid(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert is_paid


def test_is_fully_paid_many_payments(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount - 1
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
payment2 = payment_dummy
payment2.pk = None
payment2.is_active = True
payment2.order = None
payment2.total = 1
payment2.currency = total.gross.currency
payment2.checkout = checkout
payment2.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert is_paid


def test_is_fully_paid_partially_paid(checkout_with_item, payment_dummy):
checkout = checkout_with_item
total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
payment = payment_dummy
payment.is_active = True
payment.order = None
payment.total = total.gross.amount - 1
payment.currency = total.gross.currency
payment.checkout = checkout
payment.save()
is_paid = is_fully_paid(checkout, list(checkout), None)
assert not is_paid


def test_is_fully_paid_no_payment(checkout_with_item):
checkout = checkout_with_item
is_paid = is_fully_paid(checkout, list(checkout), None)
assert not is_paid
5 changes: 4 additions & 1 deletion saleor/graphql/payment/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.core.exceptions import ValidationError

from ...checkout import calculations
from ...checkout.utils import cancel_active_payments
from ...core.permissions import OrderPermissions
from ...core.taxes import zero_taxed_money
from ...core.utils import get_client_ip
Expand Down Expand Up @@ -140,6 +141,8 @@ def perform_mutation(cls, _root, info, checkout_id, **data):
cls.clean_payment_amount(info, checkout_total, amount)
extra_data = {"customer_user_agent": info.context.META.get("HTTP_USER_AGENT")}

cancel_active_payments(checkout)

payment = create_payment(
gateway=gateway,
payment_token=data["token"],
Expand All @@ -150,7 +153,7 @@ def perform_mutation(cls, _root, info, checkout_id, **data):
customer_ip_address=get_client_ip(info.context),
checkout=checkout,
)
return CheckoutPaymentCreate(payment=payment)
return CheckoutPaymentCreate(payment=payment, checkout=checkout)


class PaymentCapture(BaseMutation):
Expand Down
63 changes: 53 additions & 10 deletions saleor/graphql/payment/tests/test_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_payment_void_gateway_error(
assert not txn.is_success


CREATE_QUERY = """
CREATE_PAYMENT_MUTATION = """
mutation CheckoutPaymentCreate($checkoutId: ID!, $input: PaymentInput!) {
checkoutPaymentCreate(checkoutId: $checkoutId, input: $input) {
payment {
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_checkout_add_payment_without_shipping_method_and_not_shipping_required(
"amount": total.gross.amount,
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]
assert not data["paymentErrors"]
Expand Down Expand Up @@ -145,7 +145,7 @@ def test_checkout_add_payment_without_shipping_method_with_shipping_required(
"amount": total.gross.amount,
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]

Expand All @@ -172,7 +172,7 @@ def test_checkout_add_payment_with_shipping_method_and_shipping_required(
"amount": total.gross.amount,
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]

Expand Down Expand Up @@ -208,7 +208,7 @@ def test_checkout_add_payment(
"amount": total.gross.amount,
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]

Expand Down Expand Up @@ -241,7 +241,7 @@ def test_checkout_add_payment_default_amount(
"checkoutId": checkout_id,
"input": {"gateway": DUMMY_GATEWAY, "token": "sample-token"},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]
assert not data["paymentErrors"]
Expand Down Expand Up @@ -277,7 +277,7 @@ def test_checkout_add_payment_bad_amount(
),
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]
assert (
Expand All @@ -299,7 +299,7 @@ def test_checkout_add_payment_not_supported_gateways(
"checkoutId": checkout_id,
"input": {"gateway": DUMMY_GATEWAY, "token": "sample-token", "amount": "10.0"},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]
assert (
Expand All @@ -322,7 +322,7 @@ def test_use_checkout_billing_address_as_payment_billing(
"amount": total.gross.amount,
},
}
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)
data = content["data"]["checkoutPaymentCreate"]

Expand All @@ -338,7 +338,7 @@ def test_use_checkout_billing_address_as_payment_billing(
address.save()
checkout.billing_address = address
checkout.save()
response = user_api_client.post_graphql(CREATE_QUERY, variables)
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
get_graphql_content(response)

checkout.refresh_from_db()
Expand All @@ -347,6 +347,49 @@ def test_use_checkout_billing_address_as_payment_billing(
assert payment.billing_address_1 == address.street_address_1


def test_create_payment_for_checkout_with_active_payments(
checkout_with_payments, user_api_client, address
):
# given
checkout = checkout_with_payments
address.street_address_1 = "spanish-inqusition"
address.save()
checkout.billing_address = address
checkout.save()

total = calculations.checkout_total(checkout=checkout, lines=list(checkout))
checkout_id = graphene.Node.to_global_id("Checkout", checkout.pk)
variables = {
"checkoutId": checkout_id,
"input": {
"gateway": DUMMY_GATEWAY,
"token": "sample-token",
"amount": total.gross.amount,
},
}

payments_count = checkout.payments.count()
previous_active_payments = checkout.payments.filter(is_active=True)
previous_active_payments_ids = list(
previous_active_payments.values_list("pk", flat=True)
)
assert len(previous_active_payments_ids) > 0

# when
response = user_api_client.post_graphql(CREATE_PAYMENT_MUTATION, variables)
content = get_graphql_content(response)

# then
data = content["data"]["checkoutPaymentCreate"]

assert not data["paymentErrors"]
checkout.refresh_from_db()
assert checkout.payments.all().count() == payments_count + 1
active_payments = checkout.payments.all().filter(is_active=True)
assert active_payments.count() == 1
assert active_payments.first().pk not in previous_active_payments_ids


CAPTURE_QUERY = """
mutation PaymentCapture($paymentId: ID!, $amount: Decimal!) {
paymentCapture(paymentId: $paymentId, amount: $amount) {
Expand Down
15 changes: 15 additions & 0 deletions saleor/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,21 @@ def checkout_with_voucher_percentage_and_shipping(
return checkout


@pytest.fixture
def checkout_with_payments(checkout):
Payment.objects.bulk_create(
[
Payment(
gateway="mirumee.payments.dummy", is_active=True, checkout=checkout
),
Payment(
gateway="mirumee.payments.dummy", is_active=False, checkout=checkout
),
]
)
return checkout


@pytest.fixture
def address(db): # pylint: disable=W0613
return Address.objects.create(
Expand Down

0 comments on commit a6c056e

Please sign in to comment.