Added preliminar implementation of admin billing
This commit is contained in:
parent
06db4cd346
commit
b88689864f
7
TODO.md
7
TODO.md
|
@ -64,6 +64,11 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
dependency collector with max_recursion that matches the number of dots on service.match and service.metric
|
||||
|
||||
|
||||
* Be consistent with dates: name_on, created ?
|
||||
* Be consistent with dates:
|
||||
* created_on date
|
||||
* created_at datetime
|
||||
|
||||
at + clock time, midnight, noon- At 3:30 p.m., At 4:01, At noon
|
||||
|
||||
|
||||
* backend logs with hal logo
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.utils.encoding import force_text
|
|||
|
||||
|
||||
def admin_field(method):
|
||||
""" Wraps a function to be used as a ModelAdmin method field """
|
||||
def admin_field_wrapper(*args, **kwargs):
|
||||
""" utility function for creating admin links """
|
||||
kwargs['field'] = args[0] if args else ''
|
||||
|
|
18
orchestra/admin/forms.py
Normal file
18
orchestra/admin/forms.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from django.template import Template, Context
|
||||
from django.contrib.admin.helpers import AdminForm
|
||||
|
||||
|
||||
class AdminFormMixin(object):
|
||||
""" Provides a method for rendering a form just like in Django Admin """
|
||||
def as_admin(self):
|
||||
prepopulated_fields = {}
|
||||
fieldsets = [
|
||||
(None, {'fields': self.fields.keys()})
|
||||
]
|
||||
adminform = AdminForm(self, fieldsets, prepopulated_fields)
|
||||
template = Template(
|
||||
'{% for fieldset in adminform %}'
|
||||
'{% include "admin/includes/fieldset.html" %}'
|
||||
'{% endfor %}'
|
||||
)
|
||||
return template.render(Context({'adminform': adminform}))
|
90
orchestra/apps/orders/actions.py
Normal file
90
orchestra/apps/orders/actions.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
from django.contrib import admin, messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import render
|
||||
|
||||
from .forms import (BillSelectedOptionsForm, BillSelectConfirmationForm,
|
||||
BillSelectRelatedForm)
|
||||
|
||||
|
||||
class BillSelectedOrders(object):
|
||||
""" Form wizard for billing orders admin action """
|
||||
short_description = _("Bill selected orders")
|
||||
template = 'admin/orders/order/bill_selected_options.html'
|
||||
__name__ = 'bill_selected_orders'
|
||||
|
||||
def __call__(self, modeladmin, request, queryset):
|
||||
""" make this monster behave like a function """
|
||||
self.modeladmin = modeladmin
|
||||
self.queryset = queryset
|
||||
opts = modeladmin.model._meta
|
||||
app_label = opts.app_label
|
||||
self.context = {
|
||||
'opts': opts,
|
||||
'app_label': app_label,
|
||||
'queryset': queryset,
|
||||
'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
|
||||
}
|
||||
return self.set_options(request)
|
||||
|
||||
def set_options(self, request):
|
||||
form = BillSelectedOptionsForm()
|
||||
if request.POST.get('step'):
|
||||
form = BillSelectedOptionsForm(request.POST)
|
||||
if form.is_valid():
|
||||
self.options = dict(
|
||||
billing_point=form.cleaned_data['billing_point'],
|
||||
fixed_point=form.cleaned_data['fixed_point'],
|
||||
create_new_open=form.cleaned_data['create_new_open'],
|
||||
)
|
||||
return self.select_related(request)
|
||||
self.context.update({
|
||||
'title': _("Options for billing selected orders, step 1 / 3"),
|
||||
'step': 'one',
|
||||
'form': form,
|
||||
})
|
||||
return render(request, self.template, self.context)
|
||||
|
||||
def select_related(self, request):
|
||||
self.options['related_queryset'] = self.queryset.all() #get_related(**options)
|
||||
form = BillSelectRelatedForm(initial=self.options)
|
||||
if request.POST.get('step') == 'two':
|
||||
form = BillSelectRelatedForm(request.POST, initial=self.options)
|
||||
if form.is_valid():
|
||||
select_related = form.cleaned_data['selected_related']
|
||||
self.options['selected_related'] = select_related
|
||||
return self.confirmation(request)
|
||||
self.context.update({
|
||||
'title': _("Select related order for billing, step 2 / 3"),
|
||||
'step': 'two',
|
||||
'form': form,
|
||||
})
|
||||
return render(request, self.template, self.context)
|
||||
|
||||
def confirmation(self, request):
|
||||
form = BillSelectConfirmationForm(initial=self.options)
|
||||
if request.POST:
|
||||
bills = Order.bill(queryset, commit=True, **self.options)
|
||||
if not bills:
|
||||
msg = _("Selected orders do not have pending billing")
|
||||
self.modeladmin.message_user(request, msg, messages.WARNING)
|
||||
else:
|
||||
ids = ','.join([bill.id for bill in bills])
|
||||
url = reverse('admin:bills_bill_changelist')
|
||||
context = {
|
||||
'url': url + '?id=%s' % ids,
|
||||
'num': len(bills),
|
||||
'bills': _("bills"),
|
||||
'msg': _("have been generated"),
|
||||
}
|
||||
msg = '<a href="%(url)s">%(num)s %(bills)s</a> %(msg)s' % context
|
||||
msg = mark_safe(msg)
|
||||
self.modeladmin.message_user(request, msg, messages.INFO)
|
||||
return
|
||||
self.context.update({
|
||||
'title': _("Confirmation for billing selected orders"),
|
||||
'step': 'three',
|
||||
'form': form,
|
||||
})
|
||||
return render(request, self.template, self.context)
|
|
@ -11,6 +11,7 @@ from orchestra.admin.utils import admin_link, admin_date
|
|||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.core import services
|
||||
|
||||
from .actions import BillSelectedOrders
|
||||
from .filters import ActiveOrderListFilter
|
||||
from .models import Service, Order, MetricStorage
|
||||
|
||||
|
@ -81,6 +82,7 @@ class OrderAdmin(AccountAdminMixin, ChangeListDefaultFilter, admin.ModelAdmin):
|
|||
)
|
||||
list_display_link = ('id', 'service')
|
||||
list_filter = (ActiveOrderListFilter, 'service',)
|
||||
actions = (BillSelectedOrders(),)
|
||||
date_hierarchy = 'registered_on'
|
||||
default_changelist_filters = (
|
||||
('is_active', 'True'),
|
||||
|
|
43
orchestra/apps/orders/forms.py
Normal file
43
orchestra/apps/orders/forms.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from django import forms
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin.forms import AdminFormMixin
|
||||
|
||||
from .models import Order
|
||||
|
||||
|
||||
class BillSelectedOptionsForm(AdminFormMixin, forms.Form):
|
||||
billing_point = forms.DateField(initial=timezone.now,
|
||||
label=_("Billing point"),
|
||||
help_text=_("Date you want to bill selected orders"))
|
||||
fixed_point = forms.BooleanField(initial=False, required=False,
|
||||
label=_("fixed point"),
|
||||
help_text=_("Deisgnates whether you want the billing point to be an "
|
||||
"exact date, or adapt it to the billing period."))
|
||||
create_new_open = forms.BooleanField(initial=False, required=False,
|
||||
label=_("Create a new open bill"),
|
||||
help_text=_("Deisgnates whether you want to put this orders on a new "
|
||||
"open bill, or allow to reuse an existing one."))
|
||||
|
||||
|
||||
class BillSelectRelatedForm(AdminFormMixin, forms.Form):
|
||||
selected_related = forms.ModelMultipleChoiceField(queryset=Order.objects.none(),
|
||||
required=False)
|
||||
billing_point = forms.DateField(widget=forms.HiddenInput())
|
||||
fixed_point = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
||||
create_new_open = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BillSelectRelatedForm, self).__init__(*args, **kwargs)
|
||||
queryset = kwargs['initial'].get('related_queryset', None)
|
||||
if queryset:
|
||||
self.fields['selected_related'].queryset = queryset
|
||||
|
||||
|
||||
class BillSelectConfirmationForm(forms.Form):
|
||||
selected_related = forms.ModelMultipleChoiceField(queryset=Order.objects.none(),
|
||||
widget=forms.HiddenInput(), required=False)
|
||||
billing_point = forms.DateField(widget=forms.HiddenInput())
|
||||
fixed_point = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
||||
create_new_open = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
|
@ -0,0 +1,36 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n l10n staticfiles admin_urls %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
› <a href="{% url 'admin:app_list' app_label='orders' %}">Slices</a>
|
||||
› <a href="{% url 'admin:orders_order_changelist' %}">Slices</a>
|
||||
› {{ title }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
<div>
|
||||
|
||||
<div style="margin:20px;">
|
||||
{{ form.as_admin }}
|
||||
</div>
|
||||
{% for obj in queryset %}
|
||||
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
|
||||
{% endfor %}
|
||||
<input type="hidden" name="action" value="bill_selected_orders" />
|
||||
<input type="hidden" name="step" value="{{ step }}" />
|
||||
<input type="submit" value="{% trans "Yes, create slivers" %}" />
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
Loading…
Reference in a new issue