Repository: saleor/saleor

Issue:
Checkout should be assigned to the logged in customer
When we create checkout as a logged in customer it should be assigned to him.

### Steps to reproduce the problem
1. Login to GraphQL API 
2. Create checkout
3. Check user assigned to checkout 



Discussion:

Resolving patch:
diff --git a/saleor/graphql/checkout/mutations.py b/saleor/graphql/checkout/mutations.py
--- a/saleor/graphql/checkout/mutations.py
+++ b/saleor/graphql/checkout/mutations.py
@@ -94,6 +94,8 @@ class CheckoutCreateInput(graphene.InputObjectType):
     shipping_address = AddressInput(
         description=(
             'The mailling address to where the checkout will be shipped.'))
+    billing_address = AddressInput(
+        description=('Billing address of the customer.'))
 
 
 class CheckoutCreate(ModelMutation, I18nMixin):
@@ -109,6 +111,7 @@ class Meta:
     @classmethod
     def clean_input(cls, info, instance, input, errors):
         cleaned_input = super().clean_input(info, instance, input, errors)
+        user = info.context.user
         lines = input.pop('lines', None)
         if lines:
             variant_ids = [line.get('variant_id') for line in lines]
@@ -124,21 +127,50 @@ def clean_input(cls, info, instance, input, errors):
                 cleaned_input['variants'] = variants
                 cleaned_input['quantities'] = quantities
 
+        default_shipping_address = None
+        default_billing_address = None
+        if not user.is_anonymous:
+            default_billing_address = user.default_billing_address
+            default_shipping_address = user.default_shipping_address
+
         shipping_address_data = input.pop('shipping_address', None)
         if shipping_address_data:
             shipping_address, errors = cls.validate_address(
                 shipping_address_data, errors)
             cleaned_input['shipping_address'] = shipping_address
+        else:
+            cleaned_input['shipping_address'] = default_shipping_address
+
+        billing_address_data = input.pop('billing_address', None)
+        if billing_address_data:
+            billing_address, errors = cls.validate_address(
+                billing_address_data, errors)
+            cleaned_input['billing_address'] = billing_address
+        else:
+            cleaned_input['billing_address'] = default_billing_address
+
         return cleaned_input
 
     @classmethod
     def save(cls, info, instance, cleaned_input):
         shipping_address = cleaned_input.get('shipping_address')
+        billing_address = cleaned_input.get('billing_address')
+        update_fields = []
         if shipping_address:
             shipping_address.save()
             instance.shipping_address = shipping_address
+            update_fields.append('shipping_address')
+        if billing_address:
+            billing_address.save()
+            instance.billing_address = billing_address
+            update_fields.append('billing_address')
         super().save(info, instance, cleaned_input)
-        instance.save(update_fields=['shipping_address'])
+        user = info.context.user
+        if not user.is_anonymous:
+            instance.user = user
+            update_fields.append('user')
+        instance.save(update_fields=update_fields)
+
         variants = cleaned_input.get('variants')
         quantities = cleaned_input.get('quantities')
         if variants and quantities:


Test patch:
diff --git a/tests/api/test_checkout.py b/tests/api/test_checkout.py
--- a/tests/api/test_checkout.py
+++ b/tests/api/test_checkout.py
@@ -25,7 +25,7 @@
     """
 
 
-def test_checkout_create(user_api_client, variant, graphql_address_data):
+def test_checkout_create(api_client, variant, graphql_address_data):
     """Create checkout object using GraphQL API."""
     variant_id = graphene.Node.to_global_id('ProductVariant', variant.id)
     test_email = 'test@example.com'
@@ -38,7 +38,7 @@ def test_checkout_create(user_api_client, variant, graphql_address_data):
             'email': test_email,
             'shippingAddress': shipping_address}}
     assert not Cart.objects.exists()
-    response = user_api_client.post_graphql(
+    response = api_client.post_graphql(
         MUTATION_CHECKOUT_CREATE, variables)
     content = get_graphql_content(response)
 
@@ -64,6 +64,83 @@ def test_checkout_create(user_api_client, variant, graphql_address_data):
     assert new_cart.shipping_address.city == shipping_address['city']
 
 
+def test_checkout_create_logged_in_customer(
+        user_api_client, variant):
+    variant_id = graphene.Node.to_global_id('ProductVariant', variant.id)
+    variables = {
+        'checkoutInput': {
+            'lines': [{
+                'quantity': 1,
+                'variantId': variant_id}]}}
+    assert not Cart.objects.exists()
+    response = user_api_client.post_graphql(
+        MUTATION_CHECKOUT_CREATE, variables)
+    content = get_graphql_content(response)
+    new_cart = Cart.objects.first()
+    assert new_cart is not None
+    checkout_data = content['data']['checkoutCreate']['checkout']
+    assert checkout_data['token'] == str(new_cart.token)
+    cart_user = new_cart.user
+    customer = user_api_client.user
+    assert customer.id == cart_user.id
+    assert customer.default_shipping_address_id == new_cart.shipping_address_id
+    assert customer.default_billing_address_id == new_cart.billing_address_id
+
+
+def test_checkout_create_logged_in_customer_custom_email(
+        user_api_client, variant):
+    variant_id = graphene.Node.to_global_id('ProductVariant', variant.id)
+    customer = user_api_client.user
+    custom_email = 'custom@example.com'
+    variables = {
+        'checkoutInput': {
+            'lines': [{
+                'quantity': 1,
+                'variantId': variant_id}],
+            'email': custom_email}}
+    assert not Cart.objects.exists()
+    assert not custom_email == customer.email
+    response = user_api_client.post_graphql(
+        MUTATION_CHECKOUT_CREATE, variables)
+    content = get_graphql_content(response)
+    new_cart = Cart.objects.first()
+    assert new_cart is not None
+    checkout_data = content['data']['checkoutCreate']['checkout']
+    assert checkout_data['token'] == str(new_cart.token)
+    cart_user = new_cart.user
+    assert customer.id == cart_user.id
+    assert new_cart.email == custom_email
+
+
+def test_checkout_create_logged_in_customer_custom_addresses(
+        user_api_client, variant, graphql_address_data):
+    variant_id = graphene.Node.to_global_id('ProductVariant', variant.id)
+    shipping_address = graphql_address_data
+    billing_address = graphql_address_data
+    variables = {
+        'checkoutInput': {
+            'lines': [{
+                'quantity': 1,
+                'variantId': variant_id}],
+            'shippingAddress': shipping_address,
+            'billingAddress': billing_address}}
+    assert not Cart.objects.exists()
+    response = user_api_client.post_graphql(
+        MUTATION_CHECKOUT_CREATE, variables)
+    content = get_graphql_content(response)
+    new_cart = Cart.objects.first()
+    assert new_cart is not None
+    checkout_data = content['data']['checkoutCreate']['checkout']
+    assert checkout_data['token'] == str(new_cart.token)
+    cart_user = new_cart.user
+    customer = user_api_client.user
+    assert customer.id == cart_user.id
+    assert not customer.default_shipping_address_id == new_cart.shipping_address_id
+    assert not customer.default_billing_address_id == new_cart.billing_address_id
+    assert new_cart.shipping_address.first_name == shipping_address['firstName']
+    assert new_cart.billing_address.first_name == billing_address['firstName']
+
+
 def test_checkout_create_check_lines_quantity(
         user_api_client, variant, graphql_address_data):
     variant_id = graphene.Node.to_global_id('ProductVariant', variant.id)
@@ -76,6 +153,7 @@ def test_checkout_create_check_lines_quantity(
                 'variantId': variant_id}],
             'email': test_email,
             'shippingAddress': shipping_address}}
+    assert not Cart.objects.exists()
     response = user_api_client.post_graphql(
         MUTATION_CHECKOUT_CREATE, variables)
     content = get_graphql_content(response)