Repository: saleor/saleor

Issue:
Address instances are not copied in GraphQL checkout/order mutations
Address model defines a `get_copy` method which is used by checkout functions in the static storefront to copy user addresses (`user.default_shipping_address`, `user.default_billing_address`) and always assign new address instances to checkouts/orders. The idea behind that is to make sure that we don't lose address instances in orders when users remove them from their accounts.

This logic isn't however used in our checkout/order mutations such as:
- `checkoutCreate`
- `draftOrderCreate`

Other mutations that deal with addresses such as `checkoutShippingAddressUpdate`, `checkoutBillingAddressUpdate` shouldn't be affected as they always create a new address instance from the mutation input.

We have to make sure that we always copy user addresses when we assign them from address book to orders/checkouts. 


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
@@ -168,10 +168,10 @@ def save(cls, info, instance, cleaned_input):
         billing_address = cleaned_input.get('billing_address')
         if shipping_address:
             shipping_address.save()
-            instance.shipping_address = shipping_address
+            instance.shipping_address = shipping_address.get_copy()
         if billing_address:
             billing_address.save()
-            instance.billing_address = billing_address
+            instance.billing_address = billing_address.get_copy()
 
         instance.save()
 
diff --git a/saleor/graphql/order/mutations/draft_orders.py b/saleor/graphql/order/mutations/draft_orders.py
--- a/saleor/graphql/order/mutations/draft_orders.py
+++ b/saleor/graphql/order/mutations/draft_orders.py
@@ -111,11 +111,11 @@ def save(cls, info, instance, cleaned_input):
         shipping_address = cleaned_input.get('shipping_address')
         if shipping_address:
             shipping_address.save()
-            instance.shipping_address = shipping_address
+            instance.shipping_address = shipping_address.get_copy()
         billing_address = cleaned_input.get('billing_address')
         if billing_address:
             billing_address.save()
-            instance.billing_address = billing_address
+            instance.billing_address = billing_address.get_copy()
         super().save(info, instance, cleaned_input)
         instance.save(update_fields=['billing_address', 'shipping_address'])
         variants = cleaned_input.get('variants')


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
@@ -148,8 +148,10 @@ def test_checkout_create_logged_in_customer(user_api_client, variant):
     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
+    assert customer.default_shipping_address_id != new_cart.shipping_address_id
+    assert customer.default_shipping_address.as_data() == new_cart.shipping_address.as_data()
+    assert customer.default_billing_address_id != new_cart.billing_address_id
+    assert customer.default_billing_address.as_data() == new_cart.billing_address.as_data()
     assert customer.email == new_cart.email
 
 
diff --git a/tests/api/test_order.py b/tests/api/test_order.py
--- a/tests/api/test_order.py
+++ b/tests/api/test_order.py
@@ -374,7 +374,9 @@ def test_draft_order_create(
 
     order = Order.objects.first()
     assert order.user == customer_user
-    assert order.billing_address == customer_user.default_billing_address
+    # billing address should be copied
+    assert order.billing_address.pk != customer_user.default_billing_address.pk
+    assert order.billing_address.as_data() == customer_user.default_billing_address.as_data()
     assert order.shipping_method == shipping_method
     assert order.shipping_address.first_name == graphql_address_data['firstName']