Random fixes
This commit is contained in:
parent
a0dbf96c8a
commit
2490ff83c8
6
TODO.md
6
TODO.md
|
@ -430,7 +430,6 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
||||||
# Automatically re-run backends until success? only timedout executions?
|
# Automatically re-run backends until success? only timedout executions?
|
||||||
# TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects
|
# TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects
|
||||||
|
|
||||||
# upgrade to django 1.9 and make margins wider
|
|
||||||
# lets encrypt: DNS vs HTTP challange
|
# lets encrypt: DNS vs HTTP challange
|
||||||
# lets enctypt: autorenew
|
# lets enctypt: autorenew
|
||||||
|
|
||||||
|
@ -459,8 +458,7 @@ with open(file) as handler:
|
||||||
os.unlink(file)
|
os.unlink(file)
|
||||||
|
|
||||||
|
|
||||||
# change filter By PHP version: by detail
|
|
||||||
|
|
||||||
# Mark transaction process as executed should not override higher transaction states
|
# Mark transaction process as executed should not override higher transaction states
|
||||||
|
# Bill amend and related transaction, what to do? allow edit transaction ammount of amends when their are pending execution
|
||||||
|
|
||||||
# mailbox.addresses get_Queryset SQL contact @ with mailboxes and forwards
|
# DASHBOARD: Show owned tickets, scheduled actions, maintenance operations (diff domains)
|
||||||
|
|
|
@ -142,6 +142,7 @@ class ChangeViewActionsMixin(object):
|
||||||
view.tool_description = tool_description
|
view.tool_description = tool_description
|
||||||
view.css_class = getattr(action, 'css_class', 'historylink')
|
view.css_class = getattr(action, 'css_class', 'historylink')
|
||||||
view.help_text = getattr(action, 'help_text', '')
|
view.help_text = getattr(action, 'help_text', '')
|
||||||
|
view.hidden = getattr(action, 'hidden', False)
|
||||||
views.append(view)
|
views.append(view)
|
||||||
return views
|
return views
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ class ChangeViewActionsMixin(object):
|
||||||
kwargs['extra_context'] = {}
|
kwargs['extra_context'] = {}
|
||||||
obj = self.get_object(request, unquote(object_id))
|
obj = self.get_object(request, unquote(object_id))
|
||||||
kwargs['extra_context']['object_tools_items'] = [
|
kwargs['extra_context']['object_tools_items'] = [
|
||||||
action.__dict__ for action in self.get_change_view_actions(obj)
|
action.__dict__ for action in self.get_change_view_actions(obj) if not action.hidden
|
||||||
]
|
]
|
||||||
return super().change_view(request, object_id, **kwargs)
|
return super().change_view(request, object_id, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ def view_bill(modeladmin, request, queryset):
|
||||||
return HttpResponse(html)
|
return HttpResponse(html)
|
||||||
view_bill.tool_description = _("View")
|
view_bill.tool_description = _("View")
|
||||||
view_bill.url_name = 'view'
|
view_bill.url_name = 'view'
|
||||||
|
view_bill.hidden = True
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
|
|
@ -102,6 +102,7 @@ class ClosedBillLineInline(BillLineInline):
|
||||||
'display_subtotal', 'display_total'
|
'display_subtotal', 'display_total'
|
||||||
)
|
)
|
||||||
readonly_fields = fields
|
readonly_fields = fields
|
||||||
|
can_delete = False
|
||||||
|
|
||||||
def display_description(self, line):
|
def display_description(self, line):
|
||||||
descriptions = [line.description]
|
descriptions = [line.description]
|
||||||
|
@ -127,9 +128,6 @@ class ClosedBillLineInline(BillLineInline):
|
||||||
|
|
||||||
def has_add_permission(self, request):
|
def has_add_permission(self, request):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def has_delete_permission(self, request, obj=None):
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class BillLineAdmin(admin.ModelAdmin):
|
class BillLineAdmin(admin.ModelAdmin):
|
||||||
|
@ -243,7 +241,77 @@ class BillLineManagerAdmin(BillLineAdmin):
|
||||||
return super().changelist_view(request, context)
|
return super().changelist_view(request, context)
|
||||||
|
|
||||||
|
|
||||||
class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class BillAdminMixin(AccountAdminMixin):
|
||||||
|
def display_total_with_subtotals(self, bill):
|
||||||
|
if bill.pk:
|
||||||
|
currency = settings.BILLS_CURRENCY.lower()
|
||||||
|
subtotals = []
|
||||||
|
for tax, subtotal in bill.compute_subtotals().items():
|
||||||
|
subtotals.append(_("Subtotal %s%% VAT %s &%s;") % (tax, subtotal[0], currency))
|
||||||
|
subtotals.append(_("Taxes %s%% VAT %s &%s;") % (tax, subtotal[1], currency))
|
||||||
|
subtotals = '\n'.join(subtotals)
|
||||||
|
return '<span title="%s">%s &%s;</span>' % (subtotals, bill.compute_total(), currency)
|
||||||
|
display_total_with_subtotals.allow_tags = True
|
||||||
|
display_total_with_subtotals.short_description = _("total")
|
||||||
|
display_total_with_subtotals.admin_order_field = 'approx_total'
|
||||||
|
|
||||||
|
def display_payment_state(self, bill):
|
||||||
|
if bill.pk:
|
||||||
|
t_opts = bill.transactions.model._meta
|
||||||
|
if bill.get_type() == bill.PROFORMA:
|
||||||
|
return '<span title="Pro forma">---</span>'
|
||||||
|
transactions = bill.transactions.all()
|
||||||
|
if len(transactions) == 1:
|
||||||
|
args = (transactions[0].pk,)
|
||||||
|
view = 'admin:%s_%s_change' % (t_opts.app_label, t_opts.model_name)
|
||||||
|
url = reverse(view, args=args)
|
||||||
|
else:
|
||||||
|
url = reverse('admin:%s_%s_changelist' % (t_opts.app_label, t_opts.model_name))
|
||||||
|
url += '?bill=%i' % bill.pk
|
||||||
|
state = bill.get_payment_state_display().upper()
|
||||||
|
title = ''
|
||||||
|
if bill.closed_amends:
|
||||||
|
state = '<strike>%s*</strike>' % state
|
||||||
|
title = _("This bill has been amended, this value may not be valid.")
|
||||||
|
color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey')
|
||||||
|
return '<a href="{url}" style="color:{color}" title="{title}">{name}</a>'.format(
|
||||||
|
url=url, color=color, name=state, title=title)
|
||||||
|
display_payment_state.allow_tags = True
|
||||||
|
display_payment_state.short_description = _("Payment")
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
qs = qs.annotate(
|
||||||
|
models.Count('lines'),
|
||||||
|
# FIXME https://code.djangoproject.com/ticket/10060
|
||||||
|
approx_total=Coalesce(Sum(
|
||||||
|
(F('lines__subtotal') + Coalesce('lines__sublines__total', 0)) * (1+F('lines__tax')/100),
|
||||||
|
), 0),
|
||||||
|
)
|
||||||
|
qs = qs.prefetch_related(
|
||||||
|
Prefetch('amends', queryset=Bill.objects.filter(is_open=False), to_attr='closed_amends')
|
||||||
|
)
|
||||||
|
return qs.defer('html')
|
||||||
|
|
||||||
|
|
||||||
|
class AmendInline(BillAdminMixin, admin.TabularInline):
|
||||||
|
model = Bill
|
||||||
|
fields = (
|
||||||
|
'self_link', 'type', 'display_total_with_subtotals', 'display_payment_state', 'is_open',
|
||||||
|
'is_sent'
|
||||||
|
)
|
||||||
|
readonly_fields = fields
|
||||||
|
verbose_name_plural = _("Amends")
|
||||||
|
can_delete = False
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
self_link = admin_link('__str__')
|
||||||
|
|
||||||
|
def has_add_permission(self, *args, **kwargs):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'number', 'type_link', 'account_link', 'closed_on_display', 'updated_on_display',
|
'number', 'type_link', 'account_link', 'closed_on_display', 'updated_on_display',
|
||||||
'num_lines', 'display_total', 'display_payment_state', 'is_sent'
|
'num_lines', 'display_total', 'display_payment_state', 'is_sent'
|
||||||
|
@ -256,9 +324,8 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
change_list_template = 'admin/bills/bill/change_list.html'
|
change_list_template = 'admin/bills/bill/change_list.html'
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'fields': ['number', 'type', 'amend_of_link', 'account_link',
|
'fields': ['number', 'type', (), 'account_link', 'display_total_with_subtotals',
|
||||||
'display_total_with_subtotals', 'display_payment_state',
|
'display_payment_state', 'is_sent', 'comments'],
|
||||||
'is_sent', 'comments'],
|
|
||||||
}),
|
}),
|
||||||
(_("Dates"), {
|
(_("Dates"), {
|
||||||
'classes': ('collapse',),
|
'classes': ('collapse',),
|
||||||
|
@ -281,31 +348,26 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
actions.amend_bills, actions.bill_report, actions.service_report,
|
actions.amend_bills, actions.bill_report, actions.service_report,
|
||||||
actions.close_send_download_bills, list_accounts,
|
actions.close_send_download_bills, list_accounts,
|
||||||
]
|
]
|
||||||
change_readonly_fields = (
|
change_readonly_fields = ('account_link', 'type', 'is_open', 'amend_of_link')
|
||||||
'account_link', 'type', 'is_open', 'amend_of_link', 'amend_links'
|
|
||||||
)
|
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
'number', 'display_total', 'is_sent', 'display_payment_state', 'created_on_display',
|
'number', 'display_total', 'is_sent', 'display_payment_state', 'created_on_display',
|
||||||
'closed_on_display', 'updated_on_display', 'display_total_with_subtotals',
|
'closed_on_display', 'updated_on_display', 'display_total_with_subtotals',
|
||||||
)
|
)
|
||||||
inlines = [BillLineInline, ClosedBillLineInline]
|
|
||||||
date_hierarchy = 'closed_on'
|
date_hierarchy = 'closed_on'
|
||||||
# TODO when merged https://github.com/django/django/pull/5213
|
|
||||||
#approximate_date_hierarchy = admin.ApproximateWith.MONTHS
|
|
||||||
|
|
||||||
created_on_display = admin_date('created_on', short_description=_("Created"))
|
created_on_display = admin_date('created_on', short_description=_("Created"))
|
||||||
closed_on_display = admin_date('closed_on', short_description=_("Closed"))
|
closed_on_display = admin_date('closed_on', short_description=_("Closed"))
|
||||||
updated_on_display = admin_date('updated_on', short_description=_("Updated"))
|
updated_on_display = admin_date('updated_on', short_description=_("Updated"))
|
||||||
amend_of_link = admin_link('amend_of')
|
amend_of_link = admin_link('amend_of')
|
||||||
|
|
||||||
def amend_links(self, bill):
|
# def amend_links(self, bill):
|
||||||
links = []
|
# links = []
|
||||||
for amend in bill.amends.all():
|
# for amend in bill.amends.all():
|
||||||
url = reverse('admin:bills_bill_change', args=(amend.id,))
|
# url = reverse('admin:bills_bill_change', args=(amend.id,))
|
||||||
links.append('<a href="{url}">{num}</a>'.format(url=url, num=amend.number))
|
# links.append('<a href="{url}">{num}</a>'.format(url=url, num=amend.number))
|
||||||
return '<br>'.join(links)
|
# return '<br>'.join(links)
|
||||||
amend_links.short_description = _("Amends")
|
# amend_links.short_description = _("Amends")
|
||||||
amend_links.allow_tags = True
|
# amend_links.allow_tags = True
|
||||||
|
|
||||||
def num_lines(self, bill):
|
def num_lines(self, bill):
|
||||||
return bill.lines__count
|
return bill.lines__count
|
||||||
|
@ -319,18 +381,6 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
display_total.short_description = _("total")
|
display_total.short_description = _("total")
|
||||||
display_total.admin_order_field = 'approx_total'
|
display_total.admin_order_field = 'approx_total'
|
||||||
|
|
||||||
def display_total_with_subtotals(self, bill):
|
|
||||||
currency = settings.BILLS_CURRENCY.lower()
|
|
||||||
subtotals = []
|
|
||||||
for tax, subtotal in bill.compute_subtotals().items():
|
|
||||||
subtotals.append(_("Subtotal %s%% VAT %s &%s;") % (tax, subtotal[0], currency))
|
|
||||||
subtotals.append(_("Taxes %s%% VAT %s &%s;") % (tax, subtotal[1], currency))
|
|
||||||
subtotals = '\n'.join(subtotals)
|
|
||||||
return '<span title="%s">%s &%s;</span>' % (subtotals, bill.compute_total(), currency)
|
|
||||||
display_total_with_subtotals.allow_tags = True
|
|
||||||
display_total_with_subtotals.short_description = _("total")
|
|
||||||
display_total_with_subtotals.admin_order_field = 'approx_total'
|
|
||||||
|
|
||||||
def type_link(self, bill):
|
def type_link(self, bill):
|
||||||
bill_type = bill.type.lower()
|
bill_type = bill.type.lower()
|
||||||
url = reverse('admin:bills_%s_changelist' % bill_type)
|
url = reverse('admin:bills_%s_changelist' % bill_type)
|
||||||
|
@ -339,27 +389,6 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
type_link.short_description = _("type")
|
type_link.short_description = _("type")
|
||||||
type_link.admin_order_field = 'type'
|
type_link.admin_order_field = 'type'
|
||||||
|
|
||||||
def display_payment_state(self, bill):
|
|
||||||
t_opts = bill.transactions.model._meta
|
|
||||||
transactions = bill.transactions.all()
|
|
||||||
if len(transactions) == 1:
|
|
||||||
args = (transactions[0].pk,)
|
|
||||||
view = 'admin:%s_%s_change' % (t_opts.app_label, t_opts.model_name)
|
|
||||||
url = reverse(view, args=args)
|
|
||||||
else:
|
|
||||||
url = reverse('admin:%s_%s_changelist' % (t_opts.app_label, t_opts.model_name))
|
|
||||||
url += '?bill=%i' % bill.pk
|
|
||||||
state = bill.get_payment_state_display().upper()
|
|
||||||
title = ''
|
|
||||||
if bill.closed_amends:
|
|
||||||
state = '<strike>%s*</strike>' % state
|
|
||||||
title = _("This bill has been amended, this value may not be valid.")
|
|
||||||
color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey')
|
|
||||||
return '<a href="{url}" style="color:{color}" title="{title}">{name}</a>'.format(
|
|
||||||
url=url, color=color, name=state, title=title)
|
|
||||||
display_payment_state.allow_tags = True
|
|
||||||
display_payment_state.short_description = _("Payment")
|
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
""" Hook bill lines management URLs on bill admin """
|
""" Hook bill lines management URLs on bill admin """
|
||||||
urls = super().get_urls()
|
urls = super().get_urls()
|
||||||
|
@ -381,10 +410,11 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
fieldsets = super().get_fieldsets(request, obj)
|
fieldsets = super().get_fieldsets(request, obj)
|
||||||
if obj:
|
if obj:
|
||||||
# Switches between amend_of_link and amend_links fields
|
# Switches between amend_of_link and amend_links fields
|
||||||
|
fields = fieldsets[0][1]['fields']
|
||||||
if obj.amend_of_id:
|
if obj.amend_of_id:
|
||||||
fieldsets[0][1]['fields'][2] = 'amend_of_link'
|
fields[2] = 'amend_of_link'
|
||||||
else:
|
else:
|
||||||
fieldsets[0][1]['fields'][2] = 'amend_links'
|
fields[2] = ()
|
||||||
if obj.is_open:
|
if obj.is_open:
|
||||||
fieldsets = fieldsets[0:-1]
|
fieldsets = fieldsets[0:-1]
|
||||||
return fieldsets
|
return fieldsets
|
||||||
|
@ -400,10 +430,15 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
return [action for action in actions if action.__name__ not in exclude]
|
return [action for action in actions if action.__name__ not in exclude]
|
||||||
|
|
||||||
def get_inline_instances(self, request, obj=None):
|
def get_inline_instances(self, request, obj=None):
|
||||||
inlines = super().get_inline_instances(request, obj)
|
cls = type(self)
|
||||||
if obj and not obj.is_open:
|
if obj and not obj.is_open:
|
||||||
return [inline for inline in inlines if type(inline) != BillLineInline]
|
if obj.amends.all():
|
||||||
return [inline for inline in inlines if type(inline) != ClosedBillLineInline]
|
cls.inlines = [AmendInline, ClosedBillLineInline]
|
||||||
|
else:
|
||||||
|
cls.inlines = [ClosedBillLineInline]
|
||||||
|
else:
|
||||||
|
cls.inlines = [BillLineInline]
|
||||||
|
return super().get_inline_instances(request, obj)
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -416,20 +451,6 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
formfield.queryset = formfield.queryset.filter(is_open=False)
|
formfield.queryset = formfield.queryset.filter(is_open=False)
|
||||||
return formfield
|
return formfield
|
||||||
|
|
||||||
def get_queryset(self, request):
|
|
||||||
qs = super().get_queryset(request)
|
|
||||||
qs = qs.annotate(
|
|
||||||
models.Count('lines'),
|
|
||||||
# FIXME https://code.djangoproject.com/ticket/10060
|
|
||||||
approx_total=Coalesce(Sum(
|
|
||||||
(F('lines__subtotal') + Coalesce('lines__sublines__total', 0)) * (1+F('lines__tax')/100),
|
|
||||||
), 0),
|
|
||||||
)
|
|
||||||
qs = qs.prefetch_related(
|
|
||||||
Prefetch('amends', queryset=Bill.objects.filter(is_open=False), to_attr='closed_amends')
|
|
||||||
)
|
|
||||||
return qs.defer('html')
|
|
||||||
|
|
||||||
def change_view(self, request, object_id, **kwargs):
|
def change_view(self, request, object_id, **kwargs):
|
||||||
# TODO raise404, here and everywhere
|
# TODO raise404, here and everywhere
|
||||||
bill = self.get_object(request, unquote(object_id))
|
bill = self.get_object(request, unquote(object_id))
|
||||||
|
|
|
@ -140,20 +140,21 @@ class AmendedListFilter(SimpleListFilter):
|
||||||
|
|
||||||
def lookups(self, request, model_admin):
|
def lookups(self, request, model_admin):
|
||||||
return (
|
return (
|
||||||
('1', _("Closed amends")),
|
('1', _("Amended")),
|
||||||
('-1', _("Open or closed amends")),
|
('2', _("Open amends")),
|
||||||
('0', _("No closed amends")),
|
('3', _("Closed amends")),
|
||||||
('-0', _("No amends")),
|
('0', _("No amends")),
|
||||||
)
|
)
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
def queryset(self, request, queryset):
|
||||||
if self.value() is None:
|
if self.value() is None:
|
||||||
return queryset
|
return queryset
|
||||||
amended = queryset.filter(type__in=Bill.AMEND_MAP.values(), amend_of__isnull=False)
|
amended = queryset.filter(amends__isnull=False)
|
||||||
if not self.value().startswith('-'):
|
if self.value() == '1':
|
||||||
amended = amended.filter(is_open=False)
|
return amended.distinct()
|
||||||
amended_ids = amended.distinct().values_list('amend_of_id', flat=True)
|
elif self.value() == '2':
|
||||||
if self.value().endswith('1'):
|
return amended.filter(amends__is_open=True).distinct()
|
||||||
return queryset.filter(id__in=amended_ids)
|
elif self.value() == '3':
|
||||||
else:
|
return amended.filter(amends__is_open=False).distinct()
|
||||||
return queryset.exclude(id__in=amended_ids)
|
elif self.value() == '0':
|
||||||
|
return queryset.filter(amends__isnull=True).distinct()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
from django.core.validators import ValidationError, RegexValidator
|
from django.core.validators import ValidationError, RegexValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import F, Sum
|
from django.db.models import F, Sum
|
||||||
|
@ -254,6 +255,9 @@ class Bill(models.Model):
|
||||||
return now + payment.get_due_delta()
|
return now + payment.get_due_delta()
|
||||||
return now + relativedelta(months=1)
|
return now + relativedelta(months=1)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('admin:bills_bill_view', args=(self.pk,))
|
||||||
|
|
||||||
def close(self, payment=False):
|
def close(self, payment=False):
|
||||||
if not self.is_open:
|
if not self.is_open:
|
||||||
raise TypeError("Bill not in Open state.")
|
raise TypeError("Bill not in Open state.")
|
||||||
|
|
|
@ -7,3 +7,7 @@
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block payment %}
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer-column-2">
|
<div id="footer-column-2">
|
||||||
|
{% block payment %}
|
||||||
<div id="payment">
|
<div id="payment">
|
||||||
<span class="title">{% trans "PAYMENT" %}</span>
|
<span class="title">{% trans "PAYMENT" %}</span>
|
||||||
{% if payment.message %}
|
{% if payment.message %}
|
||||||
|
@ -153,6 +154,8 @@
|
||||||
<strong>{{ seller_info.bank_account }}</strong>
|
<strong>{{ seller_info.bank_account }}</strong>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block questions %}
|
||||||
<div id="questions">
|
<div id="questions">
|
||||||
<span class="title">{% trans "QUESTIONS" %}</span>
|
<span class="title">{% trans "QUESTIONS" %}</span>
|
||||||
{% blocktrans with type=bill.get_type_display.lower email=seller_info.email %}
|
{% blocktrans with type=bill.get_type_display.lower email=seller_info.email %}
|
||||||
|
@ -161,6 +164,7 @@
|
||||||
your message.
|
your message.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -109,7 +109,6 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
search_fields = ('bill__number', 'bill__account__username', 'id')
|
search_fields = ('bill__number', 'bill__account__username', 'id')
|
||||||
actions = change_view_actions + (actions.report, list_accounts,)
|
actions = change_view_actions + (actions.report, list_accounts,)
|
||||||
filter_by_account_fields = ('bill', 'source')
|
filter_by_account_fields = ('bill', 'source')
|
||||||
change_readonly_fields = ('amount', 'currency')
|
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
'bill_link', 'display_state', 'process_link', 'account_link', 'source_link',
|
'bill_link', 'display_state', 'process_link', 'account_link', 'source_link',
|
||||||
'display_created_at', 'display_modified_at'
|
'display_created_at', 'display_modified_at'
|
||||||
|
@ -133,6 +132,11 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
del actions['delete_selected']
|
del actions['delete_selected']
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
def get_change_readonly_fields(self, request, obj):
|
||||||
|
if obj.state in (Transaction.WAITTING_PROCESSING, Transaction.WAITTING_EXECUTION):
|
||||||
|
return ()
|
||||||
|
return ('amount', 'currency')
|
||||||
|
|
||||||
def get_change_view_actions(self, obj=None):
|
def get_change_view_actions(self, obj=None):
|
||||||
actions = super(TransactionAdmin, self).get_change_view_actions()
|
actions = super(TransactionAdmin, self).get_change_view_actions()
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
|
@ -10,21 +10,21 @@
|
||||||
<table id="result_list">
|
<table id="result_list">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col"><div class="text"><span>Action</span</div></th>
|
<th scope="col"><div class="text">Action</div></th>
|
||||||
<th scope="col"><div class="text"><span>ID</span</div></th>
|
<th scope="col"><div class="text">ID</div></th>
|
||||||
<th scope="col"><div class="text"><span>Service</span</div></th>
|
<th scope="col"><div class="text">Service</div></th>
|
||||||
<th scope="col"><div class="text"><span>Account</span</div></th>
|
<th scope="col"><div class="text">Account</div></th>
|
||||||
<th scope="col"><div class="text"><span>Content object</span</div></th>
|
<th scope="col"><div class="text">Content object</div></th>
|
||||||
<th scope="col"><div class="text"><span>Registered on</span</div></th>
|
<th scope="col"><div class="text">Registered on</div></th>
|
||||||
<th scope="col"><div class="text"><span>Billed until</span</div></th>
|
<th scope="col"><div class="text">Billed until</div></th>
|
||||||
<th scope="col"><div class="text"><span>Cancelled on</span</div>
|
<th scope="col"><div class="text">Cancelled on</div></th>
|
||||||
</th>
|
<th scope="col"><div class="text">Ignored</div></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for order, action in updates %}
|
{% for order, action in updates %}
|
||||||
<tr class="{% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}">
|
<tr class="{% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}">
|
||||||
<th>{{ action }}</th>
|
<th>{{ action.capitalize }}</th>
|
||||||
<td>{% if order.pk %}<a href="{{ order | admin_url }}">{{ order.id }}</a>{% endif %}</td>
|
<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.service | admin_url }}">{{ order.service }}</a></td>
|
||||||
<td><a href="{{ order.account | admin_url }}">{{ order.account }}</a></td>
|
<td><a href="{{ order.account | admin_url }}">{{ order.account }}</a></td>
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
<td><span title="{{ order.registered_on }}">{{ order.registered_on }}</span></td>
|
<td><span title="{{ order.registered_on }}">{{ order.registered_on }}</span></td>
|
||||||
<td><span title="{{ order.billed_unitl }}">{{ order.billed_unitl }}</span></td>
|
<td><span title="{{ order.billed_unitl }}">{{ order.billed_unitl }}</span></td>
|
||||||
<td>{{ order.canncelled_on }}</td>
|
<td>{{ order.canncelled_on }}</td>
|
||||||
|
<td><img src="/static/admin/img/icon-{% if order.ignore %}yes{% else %}no{% endif %}.svg"></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -262,7 +262,7 @@ class UNIXUserDisk(ServiceMonitor):
|
||||||
super(UNIXUserDisk, self).prepare()
|
super(UNIXUserDisk, self).prepare()
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
function monitor () {
|
function monitor () {
|
||||||
{ du -bs "$1" || echo 0; } | awk {'print $1'}
|
{ SIZE=$(du -bs "$1") && echo $SIZE || echo 0; } | awk {'print $1'}
|
||||||
}"""
|
}"""
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class DetailListFilter(SimpleListFilter):
|
||||||
parameter_name = 'detail'
|
parameter_name = 'detail'
|
||||||
|
|
||||||
def lookups(self, request, model_admin):
|
def lookups(self, request, model_admin):
|
||||||
ret = set()
|
ret = set([('empty', _("Empty"))])
|
||||||
lookup_map = {}
|
lookup_map = {}
|
||||||
for apptype in AppType.get_plugins():
|
for apptype in AppType.get_plugins():
|
||||||
for field, values in apptype.get_detail_lookups().items():
|
for field, values in apptype.get_detail_lookups().items():
|
||||||
|
@ -35,11 +35,13 @@ class DetailListFilter(SimpleListFilter):
|
||||||
lookup_map[value[0]] = field
|
lookup_map[value[0]] = field
|
||||||
ret.add(value)
|
ret.add(value)
|
||||||
self.lookup_map = lookup_map
|
self.lookup_map = lookup_map
|
||||||
return sorted(list(ret))
|
return sorted(list(ret), key=lambda e: e[1])
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
def queryset(self, request, queryset):
|
||||||
value = self.value()
|
value = self.value()
|
||||||
if value:
|
if value:
|
||||||
|
if value == 'empty':
|
||||||
|
return queryset.filter(data={})
|
||||||
try:
|
try:
|
||||||
field = self.lookup_map[value]
|
field = self.lookup_map[value]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
Loading…
Reference in New Issue