Refactor admin_fields
This commit is contained in:
parent
8c13e75d5d
commit
06db4cd346
2
TODO.md
2
TODO.md
|
@ -65,3 +65,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
|
|
||||||
|
|
||||||
* Be consistent with dates: name_on, created ?
|
* Be consistent with dates: name_on, created ?
|
||||||
|
|
||||||
|
* backend logs with hal logo
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from functools import wraps
|
from functools import wraps, partial
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.admin import helpers
|
from django.contrib.admin import helpers
|
||||||
|
@ -7,6 +7,22 @@ from django.utils.decorators import available_attrs
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
|
||||||
|
def admin_field(method):
|
||||||
|
def admin_field_wrapper(*args, **kwargs):
|
||||||
|
""" utility function for creating admin links """
|
||||||
|
kwargs['field'] = args[0] if args else ''
|
||||||
|
kwargs['order'] = kwargs.get('order', kwargs['field'])
|
||||||
|
kwargs['popup'] = kwargs.get('popup', False)
|
||||||
|
kwargs['description'] = kwargs.get('description',
|
||||||
|
kwargs['field'].split('__')[-1].replace('_', ' ').capitalize())
|
||||||
|
admin_method = partial(method, **kwargs)
|
||||||
|
admin_method.short_description = kwargs['description']
|
||||||
|
admin_method.allow_tags = True
|
||||||
|
admin_method.admin_order_field = kwargs['order']
|
||||||
|
return admin_method
|
||||||
|
return admin_field_wrapper
|
||||||
|
|
||||||
|
|
||||||
def action_with_confirmation(action_name, extra_context={},
|
def action_with_confirmation(action_name, extra_context={},
|
||||||
template='admin/orchestra/generic_confirmation.html'):
|
template='admin/orchestra/generic_confirmation.html'):
|
||||||
"""
|
"""
|
||||||
|
@ -14,7 +30,6 @@ def action_with_confirmation(action_name, extra_context={},
|
||||||
If custom template is provided the form must contain:
|
If custom template is provided the form must contain:
|
||||||
<input type="hidden" name="post" value="generic_confirmation" />
|
<input type="hidden" name="post" value="generic_confirmation" />
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def decorator(func, extra_context=extra_context, template=template):
|
def decorator(func, extra_context=extra_context, template=template):
|
||||||
@wraps(func, assigned=available_attrs(func))
|
@wraps(func, assigned=available_attrs(func))
|
||||||
def inner(modeladmin, request, queryset):
|
def inner(modeladmin, request, queryset):
|
||||||
|
@ -53,4 +68,3 @@ def action_with_confirmation(action_name, extra_context={},
|
||||||
context, current_app=modeladmin.admin_site.name)
|
context, current_app=modeladmin.admin_site.name)
|
||||||
return inner
|
return inner
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ def get_services():
|
||||||
for model, options in services.get().iteritems():
|
for model, options in services.get().iteritems():
|
||||||
if options.get('menu', True):
|
if options.get('menu', True):
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name))
|
url = reverse('admin:{}_{}_changelist'.format(
|
||||||
|
opts.app_label, opts.model_name))
|
||||||
name = capfirst(options.get('verbose_name_plural'))
|
name = capfirst(options.get('verbose_name_plural'))
|
||||||
result.append(items.MenuItem(name, url))
|
result.append(items.MenuItem(name, url))
|
||||||
return sorted(result, key=lambda i: i.title)
|
return sorted(result, key=lambda i: i.title)
|
||||||
|
@ -40,24 +41,27 @@ def get_services():
|
||||||
|
|
||||||
def get_account_items():
|
def get_account_items():
|
||||||
childrens = [
|
childrens = [
|
||||||
items.MenuItem(_("Accounts"), reverse('admin:accounts_account_changelist'))
|
items.MenuItem(_("Accounts"),
|
||||||
|
reverse('admin:accounts_account_changelist'))
|
||||||
]
|
]
|
||||||
if isinstalled('orchestra.apps.contacts'):
|
if isinstalled('orchestra.apps.contacts'):
|
||||||
url = reverse('admin:contacts_contact_changelist')
|
url = reverse('admin:contacts_contact_changelist')
|
||||||
childrens.append(items.MenuItem(_("Contacts"), url))
|
childrens.append(items.MenuItem(_("Contacts"), url))
|
||||||
if isinstalled('orchestra.apps.users'):
|
if isinstalled('orchestra.apps.users'):
|
||||||
url = reverse('admin:users_user_changelist')
|
url = reverse('admin:users_user_changelist')
|
||||||
users = [items.MenuItem(_("Users"), url)]
|
childrens.append(items.MenuItem(_("Users"), url))
|
||||||
if isinstalled('rest_framework.authtoken'):
|
|
||||||
tokens = reverse('admin:authtoken_token_changelist')
|
|
||||||
users.append(items.MenuItem(_("Tokens"), tokens))
|
|
||||||
childrens.append(items.MenuItem(_("Users"), url, children=users))
|
|
||||||
if isinstalled('orchestra.apps.prices'):
|
if isinstalled('orchestra.apps.prices'):
|
||||||
url = reverse('admin:prices_pack_changelist')
|
url = reverse('admin:prices_pack_changelist')
|
||||||
childrens.append(items.MenuItem(_("Packs"), url))
|
childrens.append(items.MenuItem(_("Packs"), url))
|
||||||
if isinstalled('orchestra.apps.orders'):
|
if isinstalled('orchestra.apps.orders'):
|
||||||
url = reverse('admin:orders_order_changelist')
|
url = reverse('admin:orders_order_changelist')
|
||||||
childrens.append(items.MenuItem(_("Orders"), url))
|
childrens.append(items.MenuItem(_("Orders"), url))
|
||||||
|
if isinstalled('orchestra.apps.bills'):
|
||||||
|
url = reverse('admin:bills_bill_changelist')
|
||||||
|
childrens.append(items.MenuItem(_("Bills"), url))
|
||||||
|
if isinstalled('orchestra.apps.payments'):
|
||||||
|
url = reverse('admin:payments_transaction_changelist')
|
||||||
|
childrens.append(items.MenuItem(_("Transactions"), url))
|
||||||
if isinstalled('orchestra.apps.issues'):
|
if isinstalled('orchestra.apps.issues'):
|
||||||
url = reverse('admin:issues_ticket_changelist')
|
url = reverse('admin:issues_ticket_changelist')
|
||||||
childrens.append(items.MenuItem(_("Tickets"), url))
|
childrens.append(items.MenuItem(_("Tickets"), url))
|
||||||
|
@ -92,7 +96,7 @@ def get_administration_items():
|
||||||
childrens.append(items.MenuItem(_("Miscellaneous"), url))
|
childrens.append(items.MenuItem(_("Miscellaneous"), url))
|
||||||
if isinstalled('orchestra.apps.issues'):
|
if isinstalled('orchestra.apps.issues'):
|
||||||
url = reverse('admin:issues_queue_changelist')
|
url = reverse('admin:issues_queue_changelist')
|
||||||
childrens.append(items.MenuItem(_("Issue queues"), url))
|
childrens.append(items.MenuItem(_("Ticket queues"), url))
|
||||||
if isinstalled('djcelery'):
|
if isinstalled('djcelery'):
|
||||||
task = reverse('admin:djcelery_taskstate_changelist')
|
task = reverse('admin:djcelery_taskstate_changelist')
|
||||||
periodic = reverse('admin:djcelery_periodictask_changelist')
|
periodic = reverse('admin:djcelery_periodictask_changelist')
|
||||||
|
|
|
@ -12,6 +12,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from orchestra.models.utils import get_field_value
|
from orchestra.models.utils import get_field_value
|
||||||
from orchestra.utils.humanize import naturaldate
|
from orchestra.utils.humanize import naturaldate
|
||||||
|
|
||||||
|
from .decorators import admin_field
|
||||||
|
|
||||||
|
|
||||||
def get_modeladmin(model, import_module=True):
|
def get_modeladmin(model, import_module=True):
|
||||||
""" returns the modeladmin registred for model """
|
""" returns the modeladmin registred for model """
|
||||||
|
@ -44,7 +46,9 @@ def insertattr(model, name, value, weight=0):
|
||||||
weights = {}
|
weights = {}
|
||||||
if hasattr(modeladmin, 'weights') and name in modeladmin.weights:
|
if hasattr(modeladmin, 'weights') and name in modeladmin.weights:
|
||||||
weights = modeladmin.weights.get(name)
|
weights = modeladmin.weights.get(name)
|
||||||
inserted_attrs[name] = [ (attr, weights.get(attr, 0)) for attr in getattr(modeladmin, name) ]
|
inserted_attrs[name] = [
|
||||||
|
(attr, weights.get(attr, 0)) for attr in getattr(modeladmin, name)
|
||||||
|
]
|
||||||
|
|
||||||
inserted_attrs[name].append((value, weight))
|
inserted_attrs[name].append((value, weight))
|
||||||
inserted_attrs[name].sort(key=lambda a: a[1])
|
inserted_attrs[name].sort(key=lambda a: a[1])
|
||||||
|
@ -70,85 +74,40 @@ def set_default_filter(queryarg, request, value):
|
||||||
request.META['QUERY_STRING'] = request.GET.urlencode()
|
request.META['QUERY_STRING'] = request.GET.urlencode()
|
||||||
|
|
||||||
|
|
||||||
|
@admin_field
|
||||||
def admin_link(*args, **kwargs):
|
def admin_link(*args, **kwargs):
|
||||||
""" utility function for creating admin links """
|
instance = args[-1]
|
||||||
field = args[0] if args else ''
|
obj = get_field_value(instance, kwargs['field'])
|
||||||
order = kwargs.pop('order', field)
|
if not getattr(obj, 'pk', None):
|
||||||
popup = kwargs.pop('popup', False)
|
return '---'
|
||||||
|
opts = obj._meta
|
||||||
def display_link(*args):
|
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
||||||
instance = args[-1]
|
url = reverse(view_name, args=(obj.pk,))
|
||||||
obj = getattr(instance, field, instance)
|
extra = ''
|
||||||
if not getattr(obj, 'pk', None):
|
if kwargs['popup']:
|
||||||
return '---'
|
extra = 'onclick="return showAddAnotherPopup(this);"'
|
||||||
opts = obj._meta
|
return '<a href="%s" %s>%s</a>' % (url, extra, obj)
|
||||||
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
|
||||||
url = reverse(view_name, args=(obj.pk,))
|
|
||||||
extra = ''
|
|
||||||
if popup:
|
|
||||||
extra = 'onclick="return showAddAnotherPopup(this);"'
|
|
||||||
return '<a href="%s" %s>%s</a>' % (url, extra, obj)
|
|
||||||
display_link.allow_tags = True
|
|
||||||
display_link.short_description = _(field.replace('_', ' '))
|
|
||||||
display_link.admin_order_field = order
|
|
||||||
return display_link
|
|
||||||
|
|
||||||
|
|
||||||
def colored(field_name, colours, description='', verbose=False, bold=True):
|
@admin_field
|
||||||
""" returns a method that will render obj with colored html """
|
def admin_colored(*args, **kwargs):
|
||||||
def colored_field(obj, field=field_name, colors=colours, verbose=verbose):
|
instance = args[-1]
|
||||||
value = escape(get_field_value(obj, field))
|
field = kwargs['field']
|
||||||
color = colors.get(value, "black")
|
value = escape(get_field_value(instance, field))
|
||||||
if verbose:
|
color = kwargs.get('colors', {}).get(value, 'black')
|
||||||
# Get the human-readable value of a choice field
|
value = getattr(instance, 'get_%s_display' % field)().upper()
|
||||||
value = getattr(obj, 'get_%s_display' % field)()
|
colored_value = '<span style="color: %s;">%s</span>' % (color, value)
|
||||||
colored_value = '<span style="color: %s;">%s</span>' % (color, value)
|
if kwargs.get('bold', True):
|
||||||
if bold:
|
colored_value = '<b>%s</b>' % colored_value
|
||||||
colored_value = '<b>%s</b>' % colored_value
|
return mark_safe(colored_value)
|
||||||
return mark_safe(colored_value)
|
|
||||||
if not description:
|
|
||||||
description = field_name.split('__').pop().replace('_', ' ').capitalize()
|
|
||||||
colored_field.short_description = description
|
|
||||||
colored_field.allow_tags = True
|
|
||||||
colored_field.admin_order_field = field_name
|
|
||||||
return colored_field
|
|
||||||
|
|
||||||
|
|
||||||
#def display_timesince(date, double=False):
|
@admin_field
|
||||||
# """
|
def admin_date(*args, **kwargs):
|
||||||
# Format date for messages create_on: show a relative time
|
instance = args[-1]
|
||||||
# with contextual helper to show fulltime format.
|
value = get_field_value(instance, kwargs['field'])
|
||||||
# """
|
if not value:
|
||||||
# if not date:
|
return kwargs.get('default', '')
|
||||||
# return 'Never'
|
return '<span title="{0}">{1}</span>'.format(
|
||||||
# date_rel = timesince(date)
|
escape(str(value)), escape(naturaldate(value)),
|
||||||
# if not double:
|
)
|
||||||
# date_rel = date_rel.split(',')[0]
|
|
||||||
# date_rel += ' ago'
|
|
||||||
# date_abs = date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
||||||
# return mark_safe("<span title='%s'>%s</span>" % (date_abs, date_rel))
|
|
||||||
|
|
||||||
|
|
||||||
def admin_date(field, **kwargs):
|
|
||||||
""" utility function for creating admin dates """
|
|
||||||
default = kwargs.pop('default', '')
|
|
||||||
order = kwargs.pop('order', field)
|
|
||||||
|
|
||||||
def display_date(*args):
|
|
||||||
instance = args[-1]
|
|
||||||
value = get_field_value(instance, field)
|
|
||||||
if not value:
|
|
||||||
return default
|
|
||||||
return '<span title="{0}">{1}</span>'.format(
|
|
||||||
escape(str(value)), escape(naturaldate(value)),
|
|
||||||
)
|
|
||||||
display_date.short_description = _(field.replace('_', ' '))
|
|
||||||
display_date.admin_order_field = order
|
|
||||||
display_date.allow_tags = True
|
|
||||||
return display_date
|
|
||||||
|
|
||||||
|
|
||||||
#def display_timeuntil(date):
|
|
||||||
# date_rel = timeuntil(date) + ' left'
|
|
||||||
# date_abs = date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
||||||
# return mark_safe("<span title='%s'>%s</span>" % (date_abs, date_rel))
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from markdown import markdown
|
from markdown import markdown
|
||||||
|
|
||||||
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin#, ChangeViewActions
|
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin#, ChangeViewActions
|
||||||
from orchestra.admin.utils import admin_link, colored, wrap_admin_view, admin_date
|
from orchestra.admin.utils import (admin_link, admin_colored, wrap_admin_view,
|
||||||
|
admin_date)
|
||||||
from orchestra.apps.contacts import settings as contacts_settings
|
from orchestra.apps.contacts import settings as contacts_settings
|
||||||
|
|
||||||
from .actions import (reject_tickets, resolve_tickets, take_tickets, close_tickets,
|
from .actions import (reject_tickets, resolve_tickets, take_tickets, close_tickets,
|
||||||
|
@ -111,20 +112,14 @@ class TicketInline(admin.TabularInline):
|
||||||
owner_link = admin_link('owner')
|
owner_link = admin_link('owner')
|
||||||
created = admin_link('created_on')
|
created = admin_link('created_on')
|
||||||
last_modified = admin_link('last_modified_on')
|
last_modified = admin_link('last_modified_on')
|
||||||
|
colored_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||||
|
colored_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||||
|
|
||||||
def ticket_id(self, instance):
|
def ticket_id(self, instance):
|
||||||
return '<b>%s</b>' % admin_link()(instance)
|
return '<b>%s</b>' % admin_link()(instance)
|
||||||
ticket_id.short_description = '#'
|
ticket_id.short_description = '#'
|
||||||
ticket_id.allow_tags = True
|
ticket_id.allow_tags = True
|
||||||
|
|
||||||
def colored_state(self, instance):
|
|
||||||
return colored('state', STATE_COLORS, bold=False)(instance)
|
|
||||||
colored_state.short_description = _("State")
|
|
||||||
|
|
||||||
def colored_priority(self, instance):
|
|
||||||
return colored('priority', PRIORITY_COLORS, bold=False)(instance)
|
|
||||||
colored_priority.short_description = _("Priority")
|
|
||||||
|
|
||||||
|
|
||||||
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeViewActions,
|
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeViewActions,
|
||||||
list_display = [
|
list_display = [
|
||||||
|
@ -198,6 +193,8 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
|
||||||
display_queue = admin_link('queue')
|
display_queue = admin_link('queue')
|
||||||
display_owner = admin_link('owner')
|
display_owner = admin_link('owner')
|
||||||
last_modified = admin_date('last_modified_on')
|
last_modified = admin_date('last_modified_on')
|
||||||
|
display_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||||
|
display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||||
|
|
||||||
def display_summary(self, ticket):
|
def display_summary(self, ticket):
|
||||||
context = {
|
context = {
|
||||||
|
@ -216,18 +213,6 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
|
||||||
display_summary.short_description = 'Summary'
|
display_summary.short_description = 'Summary'
|
||||||
display_summary.allow_tags = True
|
display_summary.allow_tags = True
|
||||||
|
|
||||||
def display_priority(self, ticket):
|
|
||||||
""" State colored for change_form """
|
|
||||||
return colored('priority', PRIORITY_COLORS, bold=False, verbose=True)(ticket)
|
|
||||||
display_priority.short_description = _("Priority")
|
|
||||||
display_priority.admin_order_field = 'priority'
|
|
||||||
|
|
||||||
def display_state(self, ticket):
|
|
||||||
""" State colored for change_form """
|
|
||||||
return colored('state', STATE_COLORS, bold=False, verbose=True)(ticket)
|
|
||||||
display_state.short_description = _("State")
|
|
||||||
display_state.admin_order_field = 'state'
|
|
||||||
|
|
||||||
def unbold_id(self, ticket):
|
def unbold_id(self, ticket):
|
||||||
""" Unbold id if ticket is read """
|
""" Unbold id if ticket is read """
|
||||||
if ticket.is_read_by(self.user):
|
if ticket.is_read_by(self.user):
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin.html import monospace_format
|
from orchestra.admin.html import monospace_format
|
||||||
from orchestra.admin.utils import admin_link, admin_date, colored
|
from orchestra.admin.utils import admin_link, admin_date, admin_colored
|
||||||
|
|
||||||
from .models import Server, Route, BackendLog, BackendOperation
|
from .models import Server, Route, BackendLog, BackendOperation
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class BackendLogAdmin(admin.ModelAdmin):
|
||||||
server_link = admin_link('server')
|
server_link = admin_link('server')
|
||||||
display_last_update = admin_date('last_update')
|
display_last_update = admin_date('last_update')
|
||||||
display_created = admin_date('created')
|
display_created = admin_date('created')
|
||||||
display_state = colored('state', STATE_COLORS)
|
display_state = admin_colored('state', colors=STATE_COLORS)
|
||||||
|
|
||||||
def mono_script(self, log):
|
def mono_script(self, log):
|
||||||
return monospace_format(escape(log.script))
|
return monospace_format(escape(log.script))
|
||||||
|
|
|
@ -1,7 +1,30 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from orchestra.admin.utils import admin_colored, admin_link
|
||||||
|
|
||||||
from .models import PaymentSource, Transaction
|
from .models import PaymentSource, Transaction
|
||||||
|
|
||||||
|
|
||||||
|
STATE_COLORS = {
|
||||||
|
Transaction.WAITTING_PROCESSING: 'darkorange',
|
||||||
|
Transaction.WAITTING_CONFIRMATION: 'orange',
|
||||||
|
Transaction.CONFIRMED: 'green',
|
||||||
|
Transaction.REJECTED: 'red',
|
||||||
|
Transaction.LOCKED: 'magenta',
|
||||||
|
Transaction.DISCARTED: 'blue',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
'id', 'bill_link', 'account_link', 'method', 'display_state', 'amount'
|
||||||
|
)
|
||||||
|
list_filter = ('method', 'state')
|
||||||
|
|
||||||
|
bill_link = admin_link('bill')
|
||||||
|
account_link = admin_link('bill__account')
|
||||||
|
display_state = admin_colored('state', colors=STATE_COLORS)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(PaymentSource)
|
admin.site.register(PaymentSource)
|
||||||
admin.site.register(Transaction)
|
admin.site.register(Transaction, TransactionAdmin)
|
||||||
|
|
|
@ -12,6 +12,7 @@ class PaymentSource(models.Model):
|
||||||
method = models.CharField(_("method"), max_length=32,
|
method = models.CharField(_("method"), max_length=32,
|
||||||
choices=PaymentMethod.get_plugin_choices())
|
choices=PaymentMethod.get_plugin_choices())
|
||||||
data = JSONField(_("data"))
|
data = JSONField(_("data"))
|
||||||
|
is_active = models.BooleanField(_("is active"), default=True)
|
||||||
|
|
||||||
|
|
||||||
class Transaction(models.Model):
|
class Transaction(models.Model):
|
||||||
|
@ -22,14 +23,15 @@ class Transaction(models.Model):
|
||||||
LOCKED = 'LOCKED'
|
LOCKED = 'LOCKED'
|
||||||
DISCARTED = 'DISCARTED'
|
DISCARTED = 'DISCARTED'
|
||||||
STATES = (
|
STATES = (
|
||||||
(WAITTING_PROCESSING, _("Waitting for processing")),
|
(WAITTING_PROCESSING, _("Waitting processing")),
|
||||||
(WAITTING_CONFIRMATION, _("Waitting for confirmation")),
|
(WAITTING_CONFIRMATION, _("Waitting confirmation")),
|
||||||
(CONFIRMED, _("Confirmed")),
|
(CONFIRMED, _("Confirmed")),
|
||||||
(REJECTED, _("Rejected")),
|
(REJECTED, _("Rejected")),
|
||||||
(LOCKED, _("Locked")),
|
(LOCKED, _("Locked")),
|
||||||
(DISCARTED, _("Discarted")),
|
(DISCARTED, _("Discarted")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO account fk?
|
||||||
bill = models.ForeignKey('bills.bill', verbose_name=_("bill"),
|
bill = models.ForeignKey('bills.bill', verbose_name=_("bill"),
|
||||||
related_name='transactions')
|
related_name='transactions')
|
||||||
method = models.CharField(_("payment method"), max_length=32,
|
method = models.CharField(_("payment method"), max_length=32,
|
||||||
|
@ -42,3 +44,6 @@ class Transaction(models.Model):
|
||||||
created_on = models.DateTimeField(auto_now_add=True)
|
created_on = models.DateTimeField(auto_now_add=True)
|
||||||
modified_on = models.DateTimeField(auto_now=True)
|
modified_on = models.DateTimeField(auto_now=True)
|
||||||
related = models.ForeignKey('self', null=True, blank=True)
|
related = models.ForeignKey('self', null=True, blank=True)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "Transaction {}".format(self.id)
|
||||||
|
|
|
@ -15,8 +15,8 @@ from .models import Resource, ResourceData, MonitorData
|
||||||
|
|
||||||
class ResourceAdmin(ExtendedModelAdmin):
|
class ResourceAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'name', 'verbose_name', 'content_type', 'period', 'ondemand',
|
'id', 'verbose_name', 'content_type', 'period', 'ondemand',
|
||||||
'default_allocation', 'disable_trigger', 'crontab',
|
'default_allocation', 'unit', 'disable_trigger', 'crontab',
|
||||||
)
|
)
|
||||||
list_filter = (UsedContentTypeFilter, 'period', 'ondemand', 'disable_trigger')
|
list_filter = (UsedContentTypeFilter, 'period', 'ondemand', 'disable_trigger')
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
|
|
|
@ -179,7 +179,7 @@ FLUENT_DASHBOARD_APP_ICONS = {
|
||||||
'miscellaneous/miscellaneous': 'applications-other.png',
|
'miscellaneous/miscellaneous': 'applications-other.png',
|
||||||
# Accounts
|
# Accounts
|
||||||
'accounts/account': 'Face-monkey.png',
|
'accounts/account': 'Face-monkey.png',
|
||||||
'contacts/contact': 'contact.png',
|
'contacts/contact': 'contact_book.png',
|
||||||
'orders/order': 'basket.png',
|
'orders/order': 'basket.png',
|
||||||
'orders/service': 'price.png',
|
'orders/service': 'price.png',
|
||||||
'prices/pack': 'Pack.png',
|
'prices/pack': 'Pack.png',
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -15,8 +15,8 @@
|
||||||
width="48"
|
width="48"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
inkscape:version="0.48.3.1 r9886"
|
inkscape:version="0.48.3.1 r9886"
|
||||||
sodipodi:docname="TuxBox.svg"
|
sodipodi:docname="Pack.svg"
|
||||||
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/Pack.png"
|
inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Pack.png"
|
||||||
inkscape:export-xdpi="90"
|
inkscape:export-xdpi="90"
|
||||||
inkscape:export-ydpi="90">
|
inkscape:export-ydpi="90">
|
||||||
<svg:metadata
|
<svg:metadata
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
id="namedview50"
|
id="namedview50"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
inkscape:zoom="4.9166667"
|
inkscape:zoom="4.9166667"
|
||||||
inkscape:cx="75.979939"
|
inkscape:cx="75.97994"
|
||||||
inkscape:cy="-22.905943"
|
inkscape:cy="-22.905943"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="27"
|
inkscape:window-y="27"
|
||||||
|
@ -3780,19 +3780,6 @@
|
||||||
y1="7.9757"
|
y1="7.9757"
|
||||||
x2="15.464"
|
x2="15.464"
|
||||||
y2="45.042" />
|
y2="45.042" />
|
||||||
<svg:filter
|
|
||||||
color-interpolation-filters="sRGB"
|
|
||||||
id="filter3974-4"
|
|
||||||
height="2.5622675"
|
|
||||||
y="-0.78113377"
|
|
||||||
width="1.1420243"
|
|
||||||
x="-0.071012162"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<svg:feGaussianBlur
|
|
||||||
id="feGaussianBlur3976-3"
|
|
||||||
stdDeviation="0.97641723"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
</svg:filter>
|
|
||||||
<svg:linearGradient
|
<svg:linearGradient
|
||||||
gradientTransform="translate(0.01860128,-4.0163098)"
|
gradientTransform="translate(0.01860128,-4.0163098)"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
|
@ -4294,7 +4281,7 @@
|
||||||
id="path3273" />
|
id="path3273" />
|
||||||
<svg:g
|
<svg:g
|
||||||
id="g3888"
|
id="g3888"
|
||||||
transform="matrix(0.7674386,0,0,0.7674386,-7.6813433,9.7817236)">
|
transform="matrix(0.67441404,0,0,0.67441404,-1.7640493,12.799498)">
|
||||||
<svg:g
|
<svg:g
|
||||||
transform="matrix(0.91489252,0,0,0.91489252,30.720532,5.6526667)"
|
transform="matrix(0.91489252,0,0,0.91489252,30.720532,5.6526667)"
|
||||||
id="layer2">
|
id="layer2">
|
||||||
|
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 127 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
Loading…
Reference in New Issue