Commit b785489d by Clinton Blackburn Committed by Clinton Blackburn

Updated Order Detail view to enable refund creation

Users can now select line items to refund from the dashboard's order detail view.

XCOM-357
parent 13e80d5a
default_app_config = 'ecommerce.extensions.dashboard.orders.config.OrdersDashboardConfig'
from oscar.apps.dashboard.orders import config
class OrdersDashboardConfig(config.OrdersDashboardConfig):
name = 'ecommerce.extensions.dashboard.orders'
from django.contrib.messages import constants as MSG
from django.core.urlresolvers import reverse
from django.test import TestCase
from oscar.core.loading import get_model
from ecommerce.extensions.refund.tests.mixins import RefundTestMixin
from ecommerce.tests.mixins import UserMixin
Refund = get_model('refund', 'Refund')
class OrderDetailViewTests(UserMixin, RefundTestMixin, TestCase):
def setUp(self):
super(OrderDetailViewTests, self).setUp()
# Staff permissions are required for this view
self.user = self.create_user(is_staff=True)
def assert_message_equals(self, response, msg, level): # pylint: disable=unused-argument
""" Verify the latest message matches the expected value. """
messages = []
for context in response.context:
messages += context.get('messages', [])
message = messages[0]
self.assertEqual(message.level, level)
self.assertEqual(message.message, msg)
def _request_refund(self, order):
"""POST to the view."""
# Login
self.client.login(username=self.user.username, password=self.password)
# POST to the view, creating the Refund
data = {
'line_action': 'create_refund',
'selected_line': order.lines.values_list('id', flat=True)
}
for line in order.lines.all():
data['selected_line_qty_{}'.format(line.id)] = line.quantity
response = self.client.post(reverse('dashboard:order-detail', kwargs={'number': order.number}), data=data,
follow=True)
self.assertEqual(response.status_code, 200)
return response
def test_create_refund(self):
"""Verify the view creates a Refund for the Order and selected Lines."""
# Create Order and Lines
order = self.create_order(user=self.user)
self.assertFalse(order.refunds.exists())
# Validate the Refund
response = self._request_refund(order)
refund = Refund.objects.latest()
self.assert_refund_matches_order(refund, order)
# Verify a message was passed for display
data = {
'link_start': '<a href="{}" target="_blank">'.format(
reverse('dashboard:refunds:detail', kwargs={'pk': refund.pk})),
'link_end': '</a>',
'refund_id': refund.pk
}
expected = '{link_start}Refund #{refund_id}{link_end} created! ' \
'Click {link_start}here{link_end} to view it.'.format(**data)
self.assert_message_equals(response, expected, MSG.SUCCESS)
def test_create_refund_error(self):
"""Verify the view does not create a Refund if the selected Lines have already been refunded."""
refund = self.create_refund()
order = refund.order
for line in order.lines.all():
self.assertTrue(line.refund_lines.exists())
# No new refunds should be created
self.assertEqual(Refund.objects.count(), 1)
response = self._request_refund(order)
self.assertEqual(Refund.objects.count(), 1)
# An error message should be displayed.
self.assert_message_equals(response,
'A refund cannot be created for these lines. They may have already been refunded.',
MSG.ERROR)
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from oscar.apps.dashboard.orders.views import OrderDetailView as CoreOrderDetailView
from oscar.core.loading import get_model
Refund = get_model('refund', 'Refund')
class OrderDetailView(CoreOrderDetailView):
line_actions = ('change_line_statuses', 'create_shipping_event', 'create_payment_event', 'create_refund')
def create_refund(self, request, order, lines, _quantities): # pylint: disable=unused-argument
refund = Refund.create_with_lines(order, lines)
if refund:
data = {
'link_start': '<a href="{}" target="_blank">'.format(
reverse('dashboard:refunds:detail', kwargs={'pk': refund.pk})),
'link_end': '</a>',
'refund_id': refund.pk
}
message = _('{link_start}Refund #{refund_id}{link_end} created! '
'Click {link_start}here{link_end} to view it.').format(**data)
messages.success(request, mark_safe(message))
else:
message = _('A refund cannot be created for these lines. They may have already been refunded.')
messages.error(request, message)
return self.reload_page()
...@@ -30,8 +30,8 @@ class RefundFactory(factory.DjangoModelFactory): ...@@ -30,8 +30,8 @@ class RefundFactory(factory.DjangoModelFactory):
if not create: if not create:
return return
for __ in range(2): for line in self.order.lines.all():
RefundLineFactory.create(refund=self) RefundLineFactory.create(refund=self, order_line=line)
self.total_credit_excl_tax = sum([line.line_credit_excl_tax for line in self.lines.all()]) self.total_credit_excl_tax = sum([line.line_credit_excl_tax for line in self.lines.all()])
self.save() self.save()
......
...@@ -64,10 +64,10 @@ class RefundTests(RefundTestMixin, StatusTestsMixin, TestCase): ...@@ -64,10 +64,10 @@ class RefundTests(RefundTestMixin, StatusTestsMixin, TestCase):
def test_num_items(self): def test_num_items(self):
""" The method should return the total number of items being refunded. """ """ The method should return the total number of items being refunded. """
refund = RefundFactory() refund = RefundFactory()
self.assertEqual(refund.num_items, 2) self.assertEqual(refund.num_items, 1)
RefundLineFactory(quantity=3, refund=refund) RefundLineFactory(quantity=3, refund=refund)
self.assertEqual(refund.num_items, 5) self.assertEqual(refund.num_items, 4)
def test_all_statuses(self): def test_all_statuses(self):
""" Refund.all_statuses should return all possible statuses for a refund. """ """ Refund.all_statuses should return all possible statuses for a refund. """
......
...@@ -27,6 +27,7 @@ OSCAR_APPS = [ ...@@ -27,6 +27,7 @@ OSCAR_APPS = [
'ecommerce.extensions.catalogue', 'ecommerce.extensions.catalogue',
'ecommerce.extensions.checkout', 'ecommerce.extensions.checkout',
'ecommerce.extensions.dashboard', 'ecommerce.extensions.dashboard',
'ecommerce.extensions.dashboard.orders',
'ecommerce.extensions.order', 'ecommerce.extensions.order',
'ecommerce.extensions.partner', 'ecommerce.extensions.partner',
'ecommerce.extensions.payment', 'ecommerce.extensions.payment',
......
...@@ -348,6 +348,14 @@ ...@@ -348,6 +348,14 @@
</label> </label>
</div> </div>
</div> </div>
<div class="control-group">
<div class="controls">
<label class="radio inline">
<input type="radio" name="line_action"
value="create_refund"/> {% trans "Create refund" %}
</label>
</div>
</div>
<input type="submit" value="{% trans "Go!" %}" class="btn btn-primary"/> <input type="submit" value="{% trans "Go!" %}" class="btn btn-primary"/>
</div> </div>
{% endblock line_actions %} {% endblock line_actions %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment