Added update orders confirmation page
This commit is contained in:
parent
0e65c65433
commit
e669dcf926
4
TODO.md
4
TODO.md
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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()
|
||||||
|
updates.append((order, 'updated'))
|
||||||
|
if commit:
|
||||||
order.update()
|
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):
|
||||||
|
|
|
@ -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> Discount per {{ discount.type }}
|
<br> Discount per {{ discount.type }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -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:
|
for service in queryset:
|
||||||
service.update_orders()
|
updates = service.update_orders()
|
||||||
modeladmin.log_change(request, service, 'Update orders')
|
num += len(updates)
|
||||||
msg = _("Orders for %s selected services have been updated.") % queryset.count()
|
services.append(str(service.pk))
|
||||||
modeladmin.message_user(request, msg)
|
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:
|
||||||
|
updates += service.update_orders(commit=False)
|
||||||
|
opts = modeladmin.model._meta
|
||||||
|
context = {
|
||||||
|
'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")
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue