Added support for order ignoring
This commit is contained in:
parent
0417d18961
commit
0dcdb4ba79
10
TODO.md
10
TODO.md
|
@ -42,8 +42,6 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
* passlib; nano /usr/local/lib/python2.7/dist-packages/passlib/ext/django/utils.py SortedDict -> collections.OrderedDict
|
||||
* pip install pyinotify
|
||||
|
||||
* create custom field that returns backend python objects
|
||||
|
||||
* Timezone awareness on monitoring system (reading server-side logs with different TZ than orchestra) maybe a settings value? (use UTC internally, timezone.localtime() when interacting with servers)
|
||||
|
||||
* EMAIL backend operations which contain stderr messages (because under certain failures status code is still 0)
|
||||
|
@ -90,8 +88,6 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
|
||||
* mail backend related_models = ('resources__content_type') ??
|
||||
|
||||
* ignore orders (mark orders as ignored), ignore orchestra related orders by default (or do not generate them on the first place) ignore superuser orders?
|
||||
|
||||
* Domain backend PowerDNS Bind validation support?
|
||||
|
||||
* Maildir billing tests/ webdisk billing tests (avg metric)
|
||||
|
@ -121,12 +117,6 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
|
||||
* DOC: Complitely decouples scripts execution, billing, service definition
|
||||
|
||||
* Create SystemUser on account creation. username=username, is_main=True,
|
||||
* Exclude is_main=True from queryset filter default is_main=False
|
||||
* self referencing group.
|
||||
* Unify all users
|
||||
|
||||
|
||||
* delete main user -> delete account or prevent delete main user
|
||||
|
||||
* https://blog.flameeyes.eu/2011/01/mostly-unknown-openssh-tricks
|
||||
|
|
|
@ -2,7 +2,7 @@ import sys
|
|||
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
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
|
||||
|
||||
|
@ -99,7 +99,11 @@ def mark_as_unread(modeladmin, request, queryset):
|
|||
for ticket in queryset:
|
||||
ticket.mark_as_unread_by(request.user)
|
||||
modeladmin.log_change(request, ticket, 'Marked as unread')
|
||||
msg = _("%s selected tickets have been marked as unread.") % queryset.count()
|
||||
num = len(queryset)
|
||||
msg = ungettext(
|
||||
_("Selected ticket has been marked as unread."),
|
||||
_("%i selected tickets have been marked as unread.") % num,
|
||||
num)
|
||||
modeladmin.message_user(request, msg)
|
||||
|
||||
|
||||
|
@ -109,7 +113,11 @@ def mark_as_read(modeladmin, request, queryset):
|
|||
for ticket in queryset:
|
||||
ticket.mark_as_read_by(request.user)
|
||||
modeladmin.log_change(request, ticket, 'Marked as read')
|
||||
msg = _("%s selected tickets have been marked as read.") % queryset.count()
|
||||
num = len(queryset)
|
||||
msg = ungettext(
|
||||
_("Selected ticket has been marked as read."),
|
||||
_("%i selected tickets have been marked as read.") % num,
|
||||
num)
|
||||
modeladmin.message_user(request, msg)
|
||||
|
||||
|
||||
|
|
|
@ -107,3 +107,32 @@ class BillSelectedOrders(object):
|
|||
'bills': bills,
|
||||
})
|
||||
return render(request, self.template, self.context)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def mark_as_ignored(modeladmin, request, queryset):
|
||||
""" Mark orders as ignored """
|
||||
for order in queryset:
|
||||
order.mark_as_ignored()
|
||||
modeladmin.log_change(request, order, 'Marked as ignored')
|
||||
num = len(queryset)
|
||||
msg = ungettext(
|
||||
_("Selected order has been marked as ignored."),
|
||||
_("%i selected orders have been marked as ignored.") % num,
|
||||
num)
|
||||
modeladmin.message_user(request, msg)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def mark_as_not_ignored(modeladmin, request, queryset):
|
||||
""" Mark orders as ignored """
|
||||
for order in queryset:
|
||||
order.mark_as_not_ignored()
|
||||
modeladmin.log_change(request, order, 'Marked as not ignored')
|
||||
num = len(queryset)
|
||||
msg = ungettext(
|
||||
_("Selected order has been marked as not ignored."),
|
||||
_("%i selected orders have been marked as not ignored.") % num,
|
||||
num)
|
||||
modeladmin.message_user(request, msg)
|
||||
|
||||
|
|
|
@ -3,23 +3,27 @@ from django.utils import timezone
|
|||
from django.utils.html import escape
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeListDefaultFilter
|
||||
from orchestra.admin.utils import admin_link, admin_date
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.utils.humanize import naturaldate
|
||||
|
||||
from .actions import BillSelectedOrders
|
||||
from .filters import ActiveOrderListFilter, BilledOrderListFilter
|
||||
from .actions import BillSelectedOrders, mark_as_ignored, mark_as_not_ignored
|
||||
from .filters import IgnoreOrderListFilter, ActiveOrderListFilter, BilledOrderListFilter
|
||||
from .models import Order, MetricStorage
|
||||
|
||||
|
||||
class OrderAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
class OrderAdmin(ChangeListDefaultFilter, AccountAdminMixin, admin.ModelAdmin):
|
||||
list_display = (
|
||||
'id', 'service', 'account_link', 'content_object_link',
|
||||
'display_registered_on', 'display_billed_until', 'display_cancelled_on'
|
||||
)
|
||||
list_display_links = ('id', 'service')
|
||||
list_filter = (ActiveOrderListFilter, BilledOrderListFilter, 'service',)
|
||||
actions = (BillSelectedOrders(),)
|
||||
list_filter = (ActiveOrderListFilter, BilledOrderListFilter, IgnoreOrderListFilter, 'service',)
|
||||
default_changelist_filters = (
|
||||
('ignore', '0'),
|
||||
)
|
||||
actions = (BillSelectedOrders(), mark_as_ignored, mark_as_not_ignored)
|
||||
date_hierarchy = 'registered_on'
|
||||
|
||||
content_object_link = admin_link('content_object', order=False)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib.admin import SimpleListFilter
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
|
@ -47,3 +48,40 @@ class BilledOrderListFilter(SimpleListFilter):
|
|||
Q(billed_until__lt=timezone.now())
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
class IgnoreOrderListFilter(SimpleListFilter):
|
||||
""" Filter Nodes by group according to request.user """
|
||||
title = _("Ignore")
|
||||
parameter_name = 'ignore'
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
return (
|
||||
('0', _("Not ignored")),
|
||||
('1', _("Ignored")),
|
||||
('2', _("All")),
|
||||
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() == '0':
|
||||
return queryset.filter(ignore=False)
|
||||
elif self.value() == '1':
|
||||
return queryset.filter(ignore=True)
|
||||
return queryset
|
||||
|
||||
def choices(self, cl):
|
||||
""" Enable default selection different than All """
|
||||
for lookup, title in self.lookup_choices:
|
||||
title = title._proxy____args[0]
|
||||
selected = self.value() == force_text(lookup)
|
||||
if not selected and title == "Not ignored" and self.value() is None:
|
||||
selected = True
|
||||
# end of workaround
|
||||
yield {
|
||||
'selected': selected,
|
||||
'query_string': cl.get_query_string({
|
||||
self.parameter_name: lookup,
|
||||
}, []),
|
||||
'display': title,
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ class OrderQuerySet(models.QuerySet):
|
|||
Q(Q(billed_until__isnull=True) | Q(billed_until__lt=end))
|
||||
)
|
||||
ids = self.values_list('id', flat=True)
|
||||
return self.model.objects.filter(qs).exclude(id__in=ids)
|
||||
return self.model.objects.filter(qs).exclude(id__in=ids, ignore=True)
|
||||
|
||||
def pricing_orders(self, ini, end):
|
||||
return self.filter(billed_until__isnull=False, billed_until__gt=ini,
|
||||
|
@ -136,8 +136,12 @@ class Order(models.Model):
|
|||
if account_id is None:
|
||||
# New account workaround -> user.account_id == None
|
||||
continue
|
||||
order = cls.objects.create(content_object=instance,
|
||||
service=service, account_id=account_id)
|
||||
ignore = False
|
||||
account = getattr(instance, 'account', instance)
|
||||
if account.is_superuser:
|
||||
ignore = service.ignore_superusers
|
||||
order = cls.objects.create(content_object=instance, service=service,
|
||||
account_id=account_id, ignore=ignore)
|
||||
logger.info("CREATED new order id: {id}".format(id=order.id))
|
||||
else:
|
||||
order = orders.get()
|
||||
|
@ -170,6 +174,14 @@ class Order(models.Model):
|
|||
self.save(update_fields=['cancelled_on'])
|
||||
logger.info("CANCELLED order id: {id}".format(id=self.id))
|
||||
|
||||
def mark_as_ignored(self):
|
||||
self.ignore = True
|
||||
self.save(update_fields=['ignore'])
|
||||
|
||||
def mark_as_not_ignored(self):
|
||||
self.ignore = False
|
||||
self.save(update_fields=['ignore'])
|
||||
|
||||
def get_metric(self, *args, **kwargs):
|
||||
if kwargs.pop('changes', False):
|
||||
ini, end = args
|
||||
|
|
|
@ -38,7 +38,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
|||
(None, {
|
||||
'classes': ('wide',),
|
||||
'fields': ('description', 'content_type', 'match', 'handler_type',
|
||||
'is_active')
|
||||
'ignore_superusers', 'is_active')
|
||||
}),
|
||||
(_("Billing options"), {
|
||||
'classes': ('wide',),
|
||||
|
|
|
@ -109,6 +109,8 @@ class Service(models.Model):
|
|||
"here allow to."),
|
||||
choices=ServiceHandler.get_plugin_choices())
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
ignore_superusers = models.BooleanField(_("ignore superusers"), default=True,
|
||||
help_text=_("Designates whether superuser orders are marked as ignored by default or not"))
|
||||
# Billing
|
||||
billing_period = models.CharField(_("billing period"), max_length=16,
|
||||
help_text=_("Renewal period for recurring invoicing"),
|
||||
|
@ -126,14 +128,6 @@ class Service(models.Model):
|
|||
(FIXED_DATE, _("Fixed billing date")),
|
||||
),
|
||||
default=FIXED_DATE)
|
||||
# delayed_billing = models.CharField(_("delayed billing"), max_length=16,
|
||||
# help_text=_("Period in which this service will be ignored for billing"),
|
||||
# choices=(
|
||||
# (NEVER, _("No delay (inmediate billing)")),
|
||||
# (TEN_DAYS, _("Ten days")),
|
||||
# (ONE_MONTH, _("One month")),
|
||||
# ),
|
||||
# default=ONE_MONTH, blank=True)
|
||||
is_fee = models.BooleanField(_("fee"), default=False,
|
||||
help_text=_("Designates whether this service should be billed as "
|
||||
" membership fee or not"))
|
||||
|
@ -161,14 +155,6 @@ class Service(models.Model):
|
|||
(MATCH_PRICE, _("Match price")),
|
||||
),
|
||||
default=STEP_PRICE)
|
||||
# orders_effect = models.CharField(_("orders effect"), max_length=16,
|
||||
# help_text=_("Defines the lookup behaviour when using orders for "
|
||||
# "the pricing rate computation of this service."),
|
||||
# choices=(
|
||||
# (REGISTER_OR_RENEW, _("Register or renew events")),
|
||||
# (CONCURRENT, _("Active at every given time")),
|
||||
# ),
|
||||
# default=CONCURRENT)
|
||||
on_cancel = models.CharField(_("on cancel"), max_length=16,
|
||||
help_text=_("Defines the cancellation behaviour of this service"),
|
||||
choices=(
|
||||
|
@ -178,24 +164,6 @@ class Service(models.Model):
|
|||
(REFUND, _("Refund")),
|
||||
),
|
||||
default=DISCOUNT)
|
||||
# on_broken_period = models.CharField(_("on broken period", max_length=16,
|
||||
# help_text=_("Defines the billing behaviour when periods are incomplete on register and on cancel"),
|
||||
# choices=(
|
||||
# (NOTHING, _("Nothing, period is atomic")),
|
||||
# (DISCOUNT, _("Bill partially")),
|
||||
# (COMPENSATE, _("Compensate on cancel")),
|
||||
# (REFUND, _("Refund on cancel")),
|
||||
# ),
|
||||
# default=DISCOUNT)
|
||||
# granularity = models.CharField(_("granularity"), max_length=16,
|
||||
# help_text=_("Defines the minimum size a period can be broken into"),
|
||||
# choices=(
|
||||
# (DAILY, _("One day")),
|
||||
# (MONTHLY, _("One month")),
|
||||
# (ANUAL, _("One year")),
|
||||
# ),
|
||||
# default=DAILY,
|
||||
# )
|
||||
payment_style = models.CharField(_("payment style"), max_length=16,
|
||||
help_text=_("Designates whether this service should be paid after "
|
||||
"consumtion (postpay/on demand) or prepaid"),
|
||||
|
@ -204,24 +172,6 @@ class Service(models.Model):
|
|||
(POSTPAY, _("Postpay (on demand)")),
|
||||
),
|
||||
default=PREPAY)
|
||||
# trial_period = models.CharField(_("trial period"), max_length=16, blank=True,
|
||||
# help_text=_("Period in which no charge will be issued"),
|
||||
# choices=(
|
||||
# (NEVER, _("No trial")),
|
||||
# (TEN_DAYS, _("Ten days")),
|
||||
# (ONE_MONTH, _("One month")),
|
||||
# ),
|
||||
# default=NEVER)
|
||||
# refund_period = models.CharField(_("refund period"), max_length=16,
|
||||
# help_text=_("Period in which automatic refund will be performed on "
|
||||
# "service cancellation"),
|
||||
# choices=(
|
||||
# (NEVER, _("Never refund")),
|
||||
# (TEN_DAYS, _("Ten days")),
|
||||
# (ONE_MONTH, _("One month")),
|
||||
# (ALWAYS, _("Always refund")),
|
||||
# ),
|
||||
# default=NEVER, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.description
|
||||
|
|
|
@ -180,10 +180,6 @@ function install_requirements () {
|
|||
update-locale LANG=en_US.UTF-8
|
||||
fi
|
||||
|
||||
run apt-get update
|
||||
run apt-get install -y $APT
|
||||
run pip install $PIP
|
||||
|
||||
# Install ca certificates
|
||||
if [[ ! -e /usr/local/share/ca-certificates/cacert.org ]]; then
|
||||
mkdir -p /usr/local/share/ca-certificates/cacert.org
|
||||
|
@ -192,6 +188,11 @@ function install_requirements () {
|
|||
http://www.cacert.org/certs/class3.crt
|
||||
update-ca-certificates
|
||||
fi
|
||||
|
||||
run apt-get update
|
||||
run apt-get install -y $APT
|
||||
run pip install $PIP
|
||||
|
||||
# Some versions of rabbitmq-server will not start automatically by default unless ...
|
||||
sed -i "s/# Default-Start:.*/# Default-Start: 2 3 4 5/" /etc/init.d/rabbitmq-server
|
||||
sed -i "s/# Default-Stop:.*/# Default-Stop: 0 1 6/" /etc/init.d/rabbitmq-server
|
||||
|
|
Loading…
Reference in a new issue