Improvements in Admin UI
This commit is contained in:
parent
ed0e51b73f
commit
147c1d0dd6
|
@ -1,4 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
|
from urlparse import parse_qs
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
@ -25,19 +26,22 @@ class AutoresponseInline(admin.StackedInline):
|
||||||
return super(AutoresponseInline, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(AutoresponseInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class MailboxAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'name', 'account_link', 'filtering', 'display_addresses'
|
'name', 'account_link', 'filtering', 'display_addresses'
|
||||||
)
|
)
|
||||||
list_filter = (HasAddressListFilter, 'filtering')
|
list_filter = (HasAddressListFilter, 'filtering')
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'fields': ('account', 'name', 'password1', 'password2', 'filtering'),
|
'fields': ('account_link', 'name', 'password1', 'password2', 'filtering'),
|
||||||
}),
|
}),
|
||||||
(_("Custom filtering"), {
|
(_("Custom filtering"), {
|
||||||
'classes': ('collapse',),
|
'classes': ('collapse',),
|
||||||
'fields': ('custom_filtering',),
|
'fields': ('custom_filtering',),
|
||||||
}),
|
}),
|
||||||
|
(_("Addresses"), {
|
||||||
|
'fields': ('addresses',)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
|
@ -48,10 +52,10 @@ class MailboxAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdm
|
||||||
'fields': ('custom_filtering',),
|
'fields': ('custom_filtering',),
|
||||||
}),
|
}),
|
||||||
(_("Addresses"), {
|
(_("Addresses"), {
|
||||||
'fields': ('addresses_field',)
|
'fields': ('addresses',)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
readonly_fields = ('account_link', 'display_addresses', 'addresses_field')
|
readonly_fields = ('account_link', 'display_addresses')
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
add_form = MailboxCreationForm
|
add_form = MailboxCreationForm
|
||||||
form = MailboxChangeForm
|
form = MailboxChangeForm
|
||||||
|
@ -73,24 +77,15 @@ class MailboxAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdm
|
||||||
fieldsets[1][1]['classes'] = fieldsets[0][1]['fields'] + ('open',)
|
fieldsets[1][1]['classes'] = fieldsets[0][1]['fields'] + ('open',)
|
||||||
return fieldsets
|
return fieldsets
|
||||||
|
|
||||||
def addresses_field(self, mailbox):
|
def get_form(self, *args, **kwargs):
|
||||||
""" Address form field with "Add address" button """
|
form = super(MailboxAdmin, self).get_form(*args, **kwargs)
|
||||||
account = mailbox.account
|
form.modeladmin = self
|
||||||
add_url = reverse('admin:mailboxes_address_add')
|
return form
|
||||||
add_url += '?account=%d&mailboxes=%s' % (account.pk, mailbox.pk)
|
|
||||||
img = '<img src="/static/admin/img/icon_addlink.gif" width="10" height="10" alt="Add Another">'
|
def save_model(self, request, obj, form, change):
|
||||||
onclick = 'onclick="return showAddAnotherPopup(this);"'
|
""" save hacky mailbox.addresses """
|
||||||
add_link = '<a href="{add_url}" {onclick}>{img} Add address</a>'.format(
|
super(MailboxAdmin, self).save_model(request, obj, form, change)
|
||||||
add_url=add_url, onclick=onclick, img=img)
|
obj.addresses = form.cleaned_data['addresses']
|
||||||
value = '%s<br><br>' % add_link
|
|
||||||
for pk, name, domain in mailbox.addresses.values_list('pk', 'name', 'domain__name'):
|
|
||||||
url = reverse('admin:mailboxes_address_change', args=(pk,))
|
|
||||||
name = '%s@%s' % (name, domain)
|
|
||||||
value += '<li><a href="%s">%s</a></li>' % (url, name)
|
|
||||||
value = '<ul>%s</ul>' % value
|
|
||||||
return mark_safe('<div style="padding-left: 10px;">%s</div>' % value)
|
|
||||||
addresses_field.short_description = _("Addresses")
|
|
||||||
addresses_field.allow_tags = True
|
|
||||||
|
|
||||||
|
|
||||||
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
@ -138,6 +133,15 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
""" Select related for performance """
|
""" Select related for performance """
|
||||||
qs = super(AddressAdmin, self).get_queryset(request)
|
qs = super(AddressAdmin, self).get_queryset(request)
|
||||||
return qs.select_related('domain')
|
return qs.select_related('domain')
|
||||||
|
|
||||||
|
def get_fields(self, request, obj=None):
|
||||||
|
""" Remove mailboxes field when creating address from a popup i.e. from mailbox add form """
|
||||||
|
fields = super(AddressAdmin, self).get_fields(request, obj=obj)
|
||||||
|
if '_to_field' in parse_qs(request.META['QUERY_STRING']):
|
||||||
|
# Add address popup
|
||||||
|
fields = list(fields)
|
||||||
|
fields.remove('mailboxes')
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Mailbox, MailboxAdmin)
|
admin.site.register(Mailbox, MailboxAdmin)
|
||||||
|
|
|
@ -1,10 +1,41 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.contrib.admin import widgets
|
||||||
|
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.forms import UserCreationForm, UserChangeForm
|
from orchestra.forms import UserCreationForm, UserChangeForm
|
||||||
|
from orchestra.utils.python import AttrDict
|
||||||
|
|
||||||
|
from .models import Address, Mailbox
|
||||||
|
|
||||||
|
|
||||||
class CleanCustomFilteringMixin(object):
|
class MailboxForm(forms.ModelForm):
|
||||||
|
""" hacky form for adding reverse M2M form field for Mailbox.addresses """
|
||||||
|
addresses = forms.ModelMultipleChoiceField(queryset=Address.objects, required=False,
|
||||||
|
widget=widgets.FilteredSelectMultiple(verbose_name=_('Pizzas'), is_stacked=False))
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(MailboxForm, self).__init__(*args, **kwargs)
|
||||||
|
field = AttrDict(**{
|
||||||
|
'to': Address,
|
||||||
|
'get_related_field': lambda: AttrDict(name='id'),
|
||||||
|
})
|
||||||
|
widget = self.fields['addresses'].widget
|
||||||
|
self.fields['addresses'].widget = widgets.RelatedFieldWidgetWrapper(widget, field,
|
||||||
|
self.modeladmin.admin_site, can_add_related=True)
|
||||||
|
old_render = self.fields['addresses'].widget.render
|
||||||
|
def render(*args, **kwargs):
|
||||||
|
output = old_render(*args, **kwargs)
|
||||||
|
args = 'account=%i' % self.modeladmin.account.pk
|
||||||
|
output = output.replace('/add/?', '/add/?%s&' % args)
|
||||||
|
return mark_safe(output)
|
||||||
|
self.fields['addresses'].widget.render = render
|
||||||
|
queryset = self.fields['addresses'].queryset
|
||||||
|
self.fields['addresses'].queryset = queryset.filter(account=self.modeladmin.account.pk)
|
||||||
|
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
self.fields['addresses'].initial = self.instance.addresses.all()
|
||||||
|
|
||||||
def clean_custom_filtering(self):
|
def clean_custom_filtering(self):
|
||||||
filtering = self.cleaned_data['filtering']
|
filtering = self.cleaned_data['filtering']
|
||||||
custom_filtering = self.cleaned_data['custom_filtering']
|
custom_filtering = self.cleaned_data['custom_filtering']
|
||||||
|
@ -13,11 +44,12 @@ class CleanCustomFilteringMixin(object):
|
||||||
return custom_filtering
|
return custom_filtering
|
||||||
|
|
||||||
|
|
||||||
class MailboxChangeForm(CleanCustomFilteringMixin, UserChangeForm):
|
|
||||||
|
class MailboxChangeForm(UserChangeForm, MailboxForm):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MailboxCreationForm(CleanCustomFilteringMixin, UserCreationForm):
|
class MailboxCreationForm(UserCreationForm, MailboxForm):
|
||||||
def clean_name(self):
|
def clean_name(self):
|
||||||
# Since model.clean() will check this, this is redundant,
|
# Since model.clean() will check this, this is redundant,
|
||||||
# but it sets a nicer error message than the ORM and avoids conflicts with contrib.auth
|
# but it sets a nicer error message than the ORM and avoids conflicts with contrib.auth
|
||||||
|
@ -26,11 +58,12 @@ class MailboxCreationForm(CleanCustomFilteringMixin, UserCreationForm):
|
||||||
self._meta.model._default_manager.get(name=name)
|
self._meta.model._default_manager.get(name=name)
|
||||||
except self._meta.model.DoesNotExist:
|
except self._meta.model.DoesNotExist:
|
||||||
return name
|
return name
|
||||||
raise forms.ValidationError(self.error_messages['duplicate_name'])
|
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||||
|
|
||||||
|
|
||||||
class AddressForm(forms.ModelForm):
|
class AddressForm(forms.ModelForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(AddressForm, self).clean()
|
cleaned_data = super(AddressForm, self).clean()
|
||||||
if not cleaned_data['mailboxes'] and not cleaned_data['forward']:
|
if not cleaned_data.get('mailboxes', True) and not cleaned_data['forward']:
|
||||||
raise forms.ValidationError(_("Mailboxes or forward address should be provided"))
|
raise forms.ValidationError(_("Mailboxes or forward address should be provided"))
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,6 @@ class Mailbox(models.Model):
|
||||||
help_text=_("Arbitrary email filtering in sieve language. "
|
help_text=_("Arbitrary email filtering in sieve language. "
|
||||||
"This overrides any automatic junk email filtering"))
|
"This overrides any automatic junk email filtering"))
|
||||||
is_active = models.BooleanField(_("active"), default=True)
|
is_active = models.BooleanField(_("active"), default=True)
|
||||||
# addresses = models.ManyToManyField('mailboxes.Address',
|
|
||||||
# verbose_name=_("addresses"),
|
|
||||||
# related_name='mailboxes', blank=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name_plural = _("mailboxes")
|
verbose_name_plural = _("mailboxes")
|
||||||
|
|
|
@ -15,10 +15,9 @@ from .models import Order, MetricStorage
|
||||||
|
|
||||||
class OrderAdmin(ChangeListDefaultFilter, AccountAdminMixin, admin.ModelAdmin):
|
class OrderAdmin(ChangeListDefaultFilter, AccountAdminMixin, admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'service', 'account_link', 'content_object_link',
|
'id', 'service_link', 'account_link', 'content_object_link',
|
||||||
'display_registered_on', 'display_billed_until', 'display_cancelled_on'
|
'display_registered_on', 'display_billed_until', 'display_cancelled_on'
|
||||||
)
|
)
|
||||||
list_display_links = ('id', 'service')
|
|
||||||
list_filter = (ActiveOrderListFilter, BilledOrderListFilter, IgnoreOrderListFilter, 'service',)
|
list_filter = (ActiveOrderListFilter, BilledOrderListFilter, IgnoreOrderListFilter, 'service',)
|
||||||
default_changelist_filters = (
|
default_changelist_filters = (
|
||||||
('ignore', '0'),
|
('ignore', '0'),
|
||||||
|
@ -26,6 +25,7 @@ class OrderAdmin(ChangeListDefaultFilter, AccountAdminMixin, admin.ModelAdmin):
|
||||||
actions = (BillSelectedOrders(), mark_as_ignored, mark_as_not_ignored)
|
actions = (BillSelectedOrders(), mark_as_ignored, mark_as_not_ignored)
|
||||||
date_hierarchy = 'registered_on'
|
date_hierarchy = 'registered_on'
|
||||||
|
|
||||||
|
service_link = admin_link('service')
|
||||||
content_object_link = admin_link('content_object', order=False)
|
content_object_link = admin_link('content_object', order=False)
|
||||||
display_registered_on = admin_date('registered_on')
|
display_registered_on = admin_date('registered_on')
|
||||||
display_cancelled_on = admin_date('cancelled_on')
|
display_cancelled_on = admin_date('cancelled_on')
|
||||||
|
|
|
@ -69,18 +69,24 @@ class OrderQuerySet(models.QuerySet):
|
||||||
for service, orders in services.iteritems():
|
for service, orders in services.iteritems():
|
||||||
if not service.rates.exists():
|
if not service.rates.exists():
|
||||||
continue
|
continue
|
||||||
|
ini = datetime.date.max
|
||||||
end = datetime.date.min
|
end = datetime.date.min
|
||||||
bp = None
|
bp = None
|
||||||
for order in orders:
|
for order in orders:
|
||||||
bp = service.handler.get_billing_point(order, **options)
|
bp = service.handler.get_billing_point(order, **options)
|
||||||
end = max(end, bp)
|
end = max(end, bp)
|
||||||
# FIXME exclude cancelled except cancelled and billed > ini
|
ini = min(ini, order.billed_until or order.registered_on)
|
||||||
qs = qs | Q(
|
qs |= Q(
|
||||||
Q(service=service, account=account_id, registered_on__lt=end) &
|
Q(service=service, account=account_id, registered_on__lt=end) & Q(
|
||||||
Q(Q(billed_until__isnull=True) | Q(billed_until__lt=end))
|
Q(billed_until__isnull=True) | Q(billed_until__lt=end)
|
||||||
|
) & Q(
|
||||||
|
Q(cancelled_on__isnull=True) | Q(cancelled_on__gt=ini)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
if not qs:
|
||||||
|
return self.model.objects.none()
|
||||||
ids = self.values_list('id', flat=True)
|
ids = self.values_list('id', flat=True)
|
||||||
return self.model.objects.filter(qs).exclude(id__in=ids, ignore=True)
|
return self.model.objects.filter(qs).exclude(id__in=ids)
|
||||||
|
|
||||||
def pricing_orders(self, ini, end):
|
def pricing_orders(self, ini, end):
|
||||||
return self.filter(billed_until__isnull=False, billed_until__gt=ini,
|
return self.filter(billed_until__isnull=False, billed_until__gt=ini,
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.db import transaction
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin.decorators import action_with_confirmation
|
from orchestra.admin.decorators import action_with_confirmation
|
||||||
from orchestra.admin.utils import change_url
|
from orchestra.admin.utils import change_url
|
||||||
|
@ -47,7 +47,11 @@ def mark_as_executed(modeladmin, request, queryset, extra_context={}):
|
||||||
for trans in queryset:
|
for trans in queryset:
|
||||||
trans.mark_as_executed()
|
trans.mark_as_executed()
|
||||||
modeladmin.log_change(request, trans, _("Executed"))
|
modeladmin.log_change(request, trans, _("Executed"))
|
||||||
msg = _("%s selected transactions have been marked as executed.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected transaction has been marked as executed."),
|
||||||
|
_("%s selected transactions have been marked as executed.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
mark_as_executed.url_name = 'execute'
|
mark_as_executed.url_name = 'execute'
|
||||||
mark_as_executed.verbose_name = _("Mark as executed")
|
mark_as_executed.verbose_name = _("Mark as executed")
|
||||||
|
@ -59,7 +63,11 @@ def mark_as_secured(modeladmin, request, queryset):
|
||||||
for trans in queryset:
|
for trans in queryset:
|
||||||
trans.mark_as_secured()
|
trans.mark_as_secured()
|
||||||
modeladmin.log_change(request, trans, _("Secured"))
|
modeladmin.log_change(request, trans, _("Secured"))
|
||||||
msg = _("%s selected transactions have been marked as secured.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected transaction has been marked as secured."),
|
||||||
|
_("%s selected transactions have been marked as secured.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
mark_as_secured.url_name = 'secure'
|
mark_as_secured.url_name = 'secure'
|
||||||
mark_as_secured.verbose_name = _("Mark as secured")
|
mark_as_secured.verbose_name = _("Mark as secured")
|
||||||
|
@ -71,7 +79,11 @@ def mark_as_rejected(modeladmin, request, queryset):
|
||||||
for trans in queryset:
|
for trans in queryset:
|
||||||
trans.mark_as_rejected()
|
trans.mark_as_rejected()
|
||||||
modeladmin.log_change(request, trans, _("Rejected"))
|
modeladmin.log_change(request, trans, _("Rejected"))
|
||||||
msg = _("%s selected transactions have been marked as rejected.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected transaction has been marked as rejected."),
|
||||||
|
_("%s selected transactions have been marked as rejected.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
mark_as_rejected.url_name = 'reject'
|
mark_as_rejected.url_name = 'reject'
|
||||||
mark_as_rejected.verbose_name = _("Mark as rejected")
|
mark_as_rejected.verbose_name = _("Mark as rejected")
|
||||||
|
@ -89,8 +101,8 @@ def _format_display_objects(modeladmin, request, queryset, related):
|
||||||
attr, verb = related
|
attr, verb = related
|
||||||
for related in getattr(obj.transactions, attr)():
|
for related in getattr(obj.transactions, attr)():
|
||||||
subobjects.append(
|
subobjects.append(
|
||||||
mark_safe('{0}: <a href="{1}">{2}</a> will be marked as {3}'.format(
|
mark_safe('Transaction: <a href="{}">{}</a> will be marked as {}'.format(
|
||||||
capfirst(related.get_type().lower()), change_url(related), related, verb))
|
change_url(related), related, verb))
|
||||||
)
|
)
|
||||||
objects.append(subobjects)
|
objects.append(subobjects)
|
||||||
return {'display_objects': objects}
|
return {'display_objects': objects}
|
||||||
|
@ -106,7 +118,11 @@ def mark_process_as_executed(modeladmin, request, queryset):
|
||||||
for process in queryset:
|
for process in queryset:
|
||||||
process.mark_as_executed()
|
process.mark_as_executed()
|
||||||
modeladmin.log_change(request, process, _("Executed"))
|
modeladmin.log_change(request, process, _("Executed"))
|
||||||
msg = _("%s selected processes have been marked as executed.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected process has been marked as executed."),
|
||||||
|
_("%s selected processes have been marked as executed.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
mark_process_as_executed.url_name = 'executed'
|
mark_process_as_executed.url_name = 'executed'
|
||||||
mark_process_as_executed.verbose_name = _("Mark as executed")
|
mark_process_as_executed.verbose_name = _("Mark as executed")
|
||||||
|
@ -118,7 +134,11 @@ def abort(modeladmin, request, queryset):
|
||||||
for process in queryset:
|
for process in queryset:
|
||||||
process.abort()
|
process.abort()
|
||||||
modeladmin.log_change(request, process, _("Aborted"))
|
modeladmin.log_change(request, process, _("Aborted"))
|
||||||
msg = _("%s selected processes have been aborted.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected process has been aborted."),
|
||||||
|
_("%s selected processes have been aborted.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
abort.url_name = 'abort'
|
abort.url_name = 'abort'
|
||||||
abort.verbose_name = _("Abort")
|
abort.verbose_name = _("Abort")
|
||||||
|
@ -130,7 +150,11 @@ def commit(modeladmin, request, queryset):
|
||||||
for trans in queryset:
|
for trans in queryset:
|
||||||
trans.mark_as_rejected()
|
trans.mark_as_rejected()
|
||||||
modeladmin.log_change(request, trans, _("Rejected"))
|
modeladmin.log_change(request, trans, _("Rejected"))
|
||||||
msg = _("%s selected transactions have been marked as rejected.") % queryset.count()
|
num = len(queryset)
|
||||||
|
msg = ungettext(
|
||||||
|
_("One selected transaction has been marked as rejected."),
|
||||||
|
_("%s selected transactions have been marked as rejected.") % num,
|
||||||
|
num)
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
commit.url_name = 'commit'
|
commit.url_name = 'commit'
|
||||||
commit.verbose_name = _("Commit")
|
commit.verbose_name = _("Commit")
|
||||||
|
|
|
@ -2,9 +2,9 @@ from django.contrib import admin
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ChangeViewActionsMixin, SelectPluginAdminMixin
|
from orchestra.admin import ChangeViewActionsMixin, SelectPluginAdminMixin, ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import admin_colored, admin_link
|
from orchestra.admin.utils import admin_colored, admin_link
|
||||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||||
|
|
||||||
from . import actions
|
from . import actions
|
||||||
from .methods import PaymentMethod
|
from .methods import PaymentMethod
|
||||||
|
@ -51,19 +51,47 @@ class TransactionInline(admin.TabularInline):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class TransactionAdmin(ChangeViewActionsMixin, AccountAdminMixin, admin.ModelAdmin):
|
class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'bill_link', 'account_link', 'source_link', 'display_state',
|
'id', 'bill_link', 'account_link', 'source_link', 'display_state',
|
||||||
'amount', 'process_link'
|
'amount', 'process_link'
|
||||||
)
|
)
|
||||||
list_filter = ('source__method', 'state')
|
list_filter = ('source__method', 'state')
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': (
|
||||||
|
'account_link',
|
||||||
|
'bill_link',
|
||||||
|
'source_link',
|
||||||
|
'display_state',
|
||||||
|
'amount',
|
||||||
|
'currency',
|
||||||
|
'process_link'
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
add_fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': (
|
||||||
|
'bill',
|
||||||
|
'source',
|
||||||
|
'display_state',
|
||||||
|
'amount',
|
||||||
|
'currency',
|
||||||
|
'process'
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
actions = (
|
actions = (
|
||||||
actions.process_transactions, actions.mark_as_executed,
|
actions.process_transactions, actions.mark_as_executed,
|
||||||
actions.mark_as_secured, actions.mark_as_rejected
|
actions.mark_as_secured, actions.mark_as_rejected
|
||||||
)
|
)
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
filter_by_account_fields = ['source']
|
filter_by_account_fields = ('bill', 'source')
|
||||||
readonly_fields = ('bill_link', 'display_state', 'process_link', 'account_link')
|
change_readonly_fields = ('amount', 'currency')
|
||||||
|
readonly_fields = ('bill_link', 'display_state', 'process_link', 'account_link', 'source_link')
|
||||||
|
|
||||||
bill_link = admin_link('bill')
|
bill_link = admin_link('bill')
|
||||||
source_link = admin_link('source')
|
source_link = admin_link('source')
|
||||||
|
@ -93,7 +121,7 @@ class TransactionAdmin(ChangeViewActionsMixin, AccountAdminMixin, admin.ModelAdm
|
||||||
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
list_display = ('id', 'file_url', 'display_transactions', 'created_at')
|
list_display = ('id', 'file_url', 'display_transactions', 'created_at')
|
||||||
fields = ('data', 'file_url', 'created_at')
|
fields = ('data', 'file_url', 'created_at')
|
||||||
readonly_fields = ('file_url', 'display_transactions', 'created_at')
|
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
|
||||||
inlines = [TransactionInline]
|
inlines = [TransactionInline]
|
||||||
actions = (actions.mark_process_as_executed, actions.abort, actions.commit)
|
actions = (actions.mark_process_as_executed, actions.abort, actions.commit)
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
|
|
|
@ -41,7 +41,7 @@ class ContractedPlan(models.Model):
|
||||||
return str(self.plan)
|
return str(self.plan)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if not self.pk and not self.plan.allow_multipls:
|
if not self.pk and not self.plan.allow_multiples:
|
||||||
if ContractedPlan.objects.filter(plan=self.plan, account=self.account).exists():
|
if ContractedPlan.objects.filter(plan=self.plan, account=self.account).exists():
|
||||||
raise ValidationError("A contracted plan for this account already exists")
|
raise ValidationError("A contracted plan for this account already exists")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue