Repository: saleor/saleor

Issue:
Unify the way addresses are printed in templates
Depending on place, Saleor uses one of three templates to print addresses:

- `dashboard/includes/_address.html`
- `userprofile/snippets/address-details.html`
- `userprofile/snippets/address-short.html`

It may be worth exploring the possibilities of reducing this to single template tag that would handle printing in same way across the project.

I've taken note that our dashboard puts some icons and makes links out of the email and phone no. and storefront doesn't, but I'm unsure if doing same thing in storefront would be an issue (in address management perhaps?), and even then unifying address printing just on the storefront's side should be worth it, considered one template seems to reimplement `format_address` template tag with adding phone number and additional `data-` attributes to result, and other one just calls `{% format_address address %}` tag.


Discussion:
I'm personally not convinced that those icons are particularly useful, they are kind of legacy that's been there since the first version of the dashboard. Not sure about the links.

I'd make it as simple as possible and reduce it to single tag `format_address(address, inline=False)` where `inline` is a boolean flag determining whether the address should be rendered in a single line (which is used in few places).


Resolving patch:
diff --git a/saleor/dashboard/order/views.py b/saleor/dashboard/order/views.py
--- a/saleor/dashboard/order/views.py
+++ b/saleor/dashboard/order/views.py
@@ -257,7 +257,8 @@ def orderline_cancel(request, order_pk, line_pk):
 @staff_member_required
 @permission_required('order.edit_order')
 def ship_delivery_group(request, order_pk, group_pk):
-    order = get_object_or_404(Order, pk=order_pk)
+    order = get_object_or_404(
+        Order.objects.select_related('shipping_address'), pk=order_pk)
     group = get_object_or_404(order.groups.all(), pk=group_pk)
     form = ShipGroupForm(request.POST or None, instance=group)
     status = 200
diff --git a/saleor/userprofile/templatetags/i18n_address_tags.py b/saleor/userprofile/templatetags/i18n_address_tags.py
--- a/saleor/userprofile/templatetags/i18n_address_tags.py
+++ b/saleor/userprofile/templatetags/i18n_address_tags.py
@@ -1,5 +1,4 @@
 from django import template
-from django.utils.safestring import mark_safe
 from django.utils.translation import pgettext
 import i18naddress
 
@@ -8,8 +7,8 @@
 register = template.Library()
 
 
-@register.simple_tag
-def format_address(address, latin=False):
+@register.inclusion_tag('formatted_address.html')
+def format_address(address, include_phone=True, inline=False, latin=False):
     address_data = Address.objects.as_data(address)
     address_data['name'] = pgettext(
         'Address data', '%(first_name)s %(last_name)s') % address_data
@@ -18,5 +17,7 @@ def format_address(address, latin=False):
         'Address data',
         '%(street_address_1)s\n'
         '%(street_address_2)s' % address_data)
-    formatted_address = i18naddress.format_address(address_data, latin)
-    return mark_safe(formatted_address)
+    address_lines = i18naddress.format_address(address_data, latin).split('\n')
+    if include_phone and address.phone:
+        address_lines.append(address.phone)
+    return {'address_lines': address_lines, 'inline': inline}


Test patch:
diff --git a/tests/test_userprofile.py b/tests/test_userprofile.py
--- a/tests/test_userprofile.py
+++ b/tests/test_userprofile.py
@@ -5,9 +5,11 @@
 from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.http import QueryDict
+from django.template import Context, Template
 from django.urls import reverse
 
 from saleor.userprofile import forms, i18n, models
+from saleor.userprofile.templatetags.i18n_address_tags import format_address
 from saleor.userprofile.validators import validate_possible_number
 
 
@@ -19,7 +21,8 @@ def billing_address(db):
         street_address_1='Tęczowa 7',
         city='Wrocław',
         postal_code='53-601',
-        country='PL')
+        country='PL',
+        phone='+48713988102')
 
 
 @pytest.mark.parametrize('country', ['CN', 'PL', 'US'])
@@ -95,7 +98,6 @@ def test_get_address_form(form_data, form_valid, expected_preview, expected_coun
 
 
 def test_country_aware_form_has_only_supported_countries():
-
     default_form = i18n.COUNTRY_FORMS['US']
     instance = default_form()
     country_field = instance.fields['country']
@@ -132,3 +134,30 @@ def test_order_with_lines_pagination(admin_client, order_list):
     url = reverse('profile:details')
     response = admin_client.get(url, data)
     assert response.status_code == 200
+
+
+def test_format_address(billing_address):
+    formatted_address = format_address(billing_address)
+    address_html = '<br>'.join(map(str, formatted_address['address_lines']))
+    context = Context({'address': billing_address})
+    tpl = Template(
+        '{% load i18n_address_tags %}'
+        '{% format_address address %}')
+    rendered_html = tpl.render(context)
+    assert address_html in rendered_html
+    assert 'inline-address' not in rendered_html
+    assert str(billing_address.phone) in rendered_html
+
+
+def test_format_address_all_options(billing_address):
+    formatted_address = format_address(
+        billing_address, include_phone=False, inline=True, latin=True)
+    address_html = ', '.join(map(str, formatted_address['address_lines']))
+    context = Context({'address': billing_address})
+    tpl = Template(
+        '{% load i18n_address_tags %}'
+        '{% format_address address include_phone=False inline=True latin=True %}')
+    rendered_html = tpl.render(context)
+    assert address_html in rendered_html
+    assert 'inline-address' in rendered_html
+    assert str(billing_address.phone) not in rendered_html