Added update orders confirmation page

This commit is contained in:
Marc 2014-10-20 19:22:18 +00:00
parent 0e65c65433
commit e669dcf926
10 changed files with 124 additions and 15 deletions

View File

@ -154,3 +154,7 @@ textwrap.dedent( \\)
* parmiko write to a channel instead of transfering files? http://sysadmin.circularvale.com/programming/paramiko-channel-hangs/ * parmiko write to a channel instead of transfering files? http://sysadmin.circularvale.com/programming/paramiko-channel-hangs/
* strip leading and trailing whitre spaces of most input fields
* Examples of service.match and service.metric

View File

@ -16,6 +16,7 @@ def admin_field(method):
kwargs['field'] = args[0] if args else '' kwargs['field'] = args[0] if args else ''
kwargs['order'] = kwargs.get('order', kwargs['field']) kwargs['order'] = kwargs.get('order', kwargs['field'])
kwargs['popup'] = kwargs.get('popup', False) kwargs['popup'] = kwargs.get('popup', False)
# TODO get field verbose name
kwargs['short_description'] = kwargs.get('short_description', kwargs['short_description'] = kwargs.get('short_description',
kwargs['field'].split('__')[-1].replace('_', ' ').capitalize()) kwargs['field'].split('__')[-1].replace('_', ' ').capitalize())
admin_method = partial(method, **kwargs) admin_method = partial(method, **kwargs)

View File

@ -13,7 +13,7 @@ def create_account_creation_form():
for model, key, kwargs, help_text in settings.ACCOUNTS_CREATE_RELATED: for model, key, kwargs, help_text in settings.ACCOUNTS_CREATE_RELATED:
model = get_model(model) model = get_model(model)
field_name = 'create_%s' % model._meta.model_name field_name = 'create_%s' % model._meta.model_name
label = _("Create related %s") % model._meta.verbose_name label = _("Create %s") % model._meta.verbose_name
fields[field_name] = forms.BooleanField(initial=True, required=False, label=label, fields[field_name] = forms.BooleanField(initial=True, required=False, label=label,
help_text=help_text) help_text=help_text)

View File

@ -4,6 +4,7 @@ import zipfile
from django.contrib import messages from django.contrib import messages
from django.contrib.admin import helpers from django.contrib.admin import helpers
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render from django.shortcuts import render
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -45,6 +46,7 @@ view_bill.verbose_name = _("View")
view_bill.url_name = 'view' view_bill.url_name = 'view'
@transaction.atomic
def close_bills(modeladmin, request, queryset): def close_bills(modeladmin, request, queryset):
queryset = queryset.filter(is_open=True) queryset = queryset.filter(is_open=True)
if not queryset: if not queryset:

View File

@ -59,6 +59,7 @@ class OrderQuerySet(models.QuerySet):
return self.filter(**qs) return self.filter(**qs)
def get_related(self, **options): def get_related(self, **options):
""" returns related orders that could have a pricing effect """
Service = get_model(settings.ORDERS_SERVICE_MODEL) Service = get_model(settings.ORDERS_SERVICE_MODEL)
conflictive = self.filter(service__metric='') conflictive = self.filter(service__metric='')
conflictive = conflictive.exclude(service__billing_period=Service.NEVER) conflictive = conflictive.exclude(service__billing_period=Service.NEVER)
@ -66,6 +67,8 @@ class OrderQuerySet(models.QuerySet):
qs = Q() qs = Q()
for account_id, services in conflictive.iteritems(): for account_id, services in conflictive.iteritems():
for service, orders in services.iteritems(): for service, orders in services.iteritems():
if not service.rates.exists():
continue
end = datetime.date.min end = datetime.date.min
bp = None bp = None
for order in orders: for order in orders:
@ -107,7 +110,7 @@ class Order(models.Model):
related_name='orders') related_name='orders')
registered_on = models.DateField(_("registered"), default=lambda: timezone.now()) registered_on = models.DateField(_("registered"), default=lambda: timezone.now())
cancelled_on = models.DateField(_("cancelled"), null=True, blank=True) cancelled_on = models.DateField(_("cancelled"), null=True, blank=True)
billed_on = models.DateField(_("billed on"), null=True, blank=True) billed_on = models.DateField(_("billed"), null=True, blank=True)
billed_until = models.DateField(_("billed until"), null=True, blank=True) billed_until = models.DateField(_("billed until"), null=True, blank=True)
ignore = models.BooleanField(_("ignore"), default=False) ignore = models.BooleanField(_("ignore"), default=False)
description = models.TextField(_("description"), blank=True) description = models.TextField(_("description"), blank=True)
@ -122,7 +125,8 @@ class Order(models.Model):
return str(self.service) return str(self.service)
@classmethod @classmethod
def update_orders(cls, instance, service=None): def update_orders(cls, instance, service=None, commit=True):
updates = []
if service is None: if service is None:
Service = get_model(settings.ORDERS_SERVICE_MODEL) Service = get_model(settings.ORDERS_SERVICE_MODEL)
services = Service.get_services(instance) services = Service.get_services(instance)
@ -140,14 +144,23 @@ class Order(models.Model):
account = getattr(instance, 'account', instance) account = getattr(instance, 'account', instance)
if account.is_superuser: if account.is_superuser:
ignore = service.ignore_superusers ignore = service.ignore_superusers
order = cls.objects.create(content_object=instance, service=service, order = cls(content_object=instance, service=service,
account_id=account_id, ignore=ignore) account_id=account_id, ignore=ignore)
if commit:
order.save()
updates.append((order, 'created'))
logger.info("CREATED new order id: {id}".format(id=order.id)) logger.info("CREATED new order id: {id}".format(id=order.id))
else: else:
order = orders.get() order = orders.get()
order.update() updates.append((order, 'updated'))
if commit:
order.update()
elif orders: elif orders:
orders.get().cancel() order = orders.get()
if commit:
order.cancel()
updates.append((order, 'cancelled'))
return updates
@classmethod @classmethod
def get_bill_backend(cls): def get_bill_backend(cls):

View File

@ -41,7 +41,7 @@
{% for line in lines %} {% for line in lines %}
<tr class="form-row {% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}"> <tr class="form-row {% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}">
<td> <td>
<a href="{{ line.order | admin_link }}">{{ line.order.description }}</a> <a href="{{ line.order | admin_url }}">{{ line.order.description }}</a>
{% for discount in line.discounts %} {% for discount in line.discounts %}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Discount per {{ discount.type }} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Discount per {{ discount.type }}
{% endfor %} {% endfor %}

View File

@ -1,15 +1,50 @@
from django.contrib.admin import helpers
from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import render
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.admin.utils import get_object_from_url
@transaction.atomic @transaction.atomic
def update_orders(modeladmin, request, queryset): def update_orders(modeladmin, request, queryset, extra_context=None):
if not queryset:
return
if request.POST.get('post') == 'confirmation':
num = 0
services = []
for service in queryset:
updates = service.update_orders()
num += len(updates)
services.append(str(service.pk))
modeladmin.log_change(request, service, _("Orders updated"))
if num == 1:
url = reverse('admin:orders_order_change', args=(updates[0][0].pk,))
msg = _('<a href="%s">One related order</a> has benn updated') % url
else:
url = reverse('admin:orders_order_changelist')
url += '?service__in=%s' % ','.join(services)
msg = _('<a href="%s">%s related orders</a> have been updated') % (url, num)
modeladmin.message_user(request, mark_safe(msg))
return
updates = []
for service in queryset: for service in queryset:
service.update_orders() updates += service.update_orders(commit=False)
modeladmin.log_change(request, service, 'Update orders') opts = modeladmin.model._meta
msg = _("Orders for %s selected services have been updated.") % queryset.count() context = {
modeladmin.message_user(request, msg) 'title': _("Update orders will cause the following."),
'action_name': 'Update orders',
'action_value': 'update_orders',
'updates': updates,
'queryset': queryset,
'opts': opts,
'app_label': opts.app_label,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
'obj': get_object_from_url(modeladmin, request),
}
return render(request, 'admin/services/service/update_orders.html', context)
update_orders.url_name = 'update-orders' update_orders.url_name = 'update-orders'
update_orders.verbose_name = _("Update orders") update_orders.verbose_name = _("Update orders")

View File

@ -272,11 +272,13 @@ class Service(models.Model):
def rate_method(self): def rate_method(self):
return self.RATE_METHODS[self.rate_algorithm] return self.RATE_METHODS[self.rate_algorithm]
def update_orders(self): def update_orders(self, commit=True):
order_model = get_model(settings.SERVICES_ORDER_MODEL) order_model = get_model(settings.SERVICES_ORDER_MODEL)
related_model = self.content_type.model_class() related_model = self.content_type.model_class()
updates = []
for instance in related_model.objects.all().select_related('account'): for instance in related_model.objects.all().select_related('account'):
order_model.update_orders(instance, service=self) updates += order_model.update_orders(instance, service=self, commit=commit)
return updates
accounts.register(ContractedPlan) accounts.register(ContractedPlan)

View File

@ -0,0 +1,52 @@
{% extends "admin/orchestra/generic_confirmation.html" %}
{% load i18n l10n %}
{% load url from future %}
{% load admin_urls static utils %}
{% block content %}
<div class="inline-group" id="rates-group">
<div class="tabular inline-related last-related">
<fieldset class="module">
<table id="result_list">
<thead>
<tr>
<th scope="col"><div class="text"><span>Action</span</div></th>
<th scope="col"><div class="text"><span>ID</span</div></th>
<th scope="col"><div class="text"><span>Service</span</div></th>
<th scope="col"><div class="text"><span>Account</span</div></th>
<th scope="col"><div class="text"><span>Content object</span</div></th>
<th scope="col"><div class="text"><span>Registered on</span</div></th>
<th scope="col"><div class="text"><span>Billed until</span</div></th>
<th scope="col"><div class="text"><span>Cancelled on</span</div>
</th>
</tr>
</thead>
<tbody>
{% for order, action in updates %}
<tr class="{% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}">
<th>{{ action }}</th>
<td>{% if order.pk %}<a href="{{ order | admin_url }}">{{ order.id }}</a>{% endif %}</td>
<td><a href="{{ order.service | admin_url }}">{{ order.service }}</a></td>
<td><a href="{{ order.account | admin_url }}">{{ order.account }}</a></td>
<td><a href="{{ order.content_object | admin_url }}">{{ order.content_object }}</a></td>
<td><span title="{{ order.registered_on }}">{{ order.registered_on }}</span></td>
<td><span title="{{ order.billed_unitl }}">{{ order.billed_unitl }}</span></td>
<td>{{ order.canncelled_on }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</ul>
<form action="" method="post">{% csrf_token %}
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="action" value="{{ action_value }}" />
<input type="hidden" name="post" value="confirmation" />
<input type="submit" value="{% trans "Yes, I'm sure" %}" />
</form>
{% endblock %}

View File

@ -54,5 +54,5 @@ def is_checkbox(field):
@register.filter @register.filter
def admin_link(obj): def admin_url(obj):
return change_url(obj) return change_url(obj)