Fixes on billing and mailman traffic backend

This commit is contained in:
Marc Aymerich 2015-09-07 13:07:04 +00:00
parent 8753b94b8c
commit 332ad49b64
5 changed files with 35 additions and 27 deletions

18
TODO.md
View File

@ -156,7 +156,6 @@ require_once(/etc/moodles/.$moodle_host.config.php);``` moodle/drupl
# * add ini, end dates on bill lines and breakup quanity into size(defaut:1) and metric # * add ini, end dates on bill lines and breakup quanity into size(defaut:1) and metric
# * threshold for significative metric accountancy on services.handler # * threshold for significative metric accountancy on services.handler
# * http://orchestra.pangea.org/admin/orders/order/6418/ # * http://orchestra.pangea.org/admin/orders/order/6418/
# * http://orchestra.pangea.org/admin/orders/order/6495/bill_selected_orders/
* move normurlpath to orchestra.utils from websites.utils * move normurlpath to orchestra.utils from websites.utils
@ -183,22 +182,11 @@ ugettext("Description")
* saas validate_creation generic approach, for all backends. standard output * saas validate_creation generic approach, for all backends. standard output
* html code x: × for bill line verbose quantity * periodic task to cleanup metricstorage
# create orchestrate databases.Database pk=1 -n --dry-run | --noinput --action save (default)|delete --backend name (limit to this backend) --help
* periodic task to cleanup backendlogs, monitor data and metricstorage
* create orchestrate databases.Database pk=1 -n --dry-run | --noinput --action save (default)|delete --backend name (limit to this backend) --help
* uwsgi --max-requests=5000 \ # respawn processes after serving 5000 requests and
celery max-tasks-per-child
* generate settings.py more like django (installed_apps, middlewares, etc,,,)
* postupgradeorchestra send signals in order to hook custom stuff * postupgradeorchestra send signals in order to hook custom stuff
* autoscale celery workers http://docs.celeryproject.org/en/latest/userguide/workers.html#autoscaling
glic3rinu's django-fluent-dashboard
* gevent is not ported to python3 :'( * gevent is not ported to python3 :'(
# FIXME account deletion generates an integrity error # FIXME account deletion generates an integrity error
@ -248,8 +236,6 @@ https://code.djangoproject.com/ticket/24576
# Determine the difference between data serializer used for validation and used for the rest API! # Determine the difference between data serializer used for validation and used for the rest API!
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support # Make PluginApiView that fills metadata and other stuff like modeladmin plugin support
# TODO orchestra related services code reload: celery/uwsgi reloading find aonther way without root and implement reload
# reset setting button # reset setting button
# admin edit relevant djanog settings # admin edit relevant djanog settings

View File

@ -271,6 +271,7 @@ class MailmanTraffic(ServiceMonitor):
'Nov': '11', 'Nov': '11',
'Dec': '12', 'Dec': '12',
}} }}
mailman_addr = re.compile(r'.*-(admin|bounces|confirm|join|leave|owner|request|subscribe|unsubscribe)@.*')
def prepare(object_id, list_name, ini_date): def prepare(object_id, list_name, ini_date):
global lists global lists
@ -283,12 +284,15 @@ class MailmanTraffic(ServiceMonitor):
try: try:
with open(postlog, 'r') as postlog: with open(postlog, 'r') as postlog:
for line in postlog.readlines(): for line in postlog.readlines():
month, day, time, year, __, __, __, list_name, __, __, size = line.split()[:11] month, day, time, year, __, __, __, list_name, __, addr, size = line.split()[:11]
try: try:
list = lists[list_name] list = lists[list_name]
except KeyError: except KeyError:
continue continue
else: else:
# discard mailman messages because of inconsistent POST logging
if mailman_addr.match(addr):
continue
date = year + months[month] + day + time.replace(':', '') date = year + months[month] + day + time.replace(':', '')
if list[0] < int(date) < end_date: if list[0] < int(date) < end_date:
size = size[5:-1] size = size[5:-1]

View File

@ -202,6 +202,7 @@ class MonitorDataAdmin(ExtendedModelAdmin):
change_readonly_fields = fields change_readonly_fields = fields
list_select_related = ('content_type',) list_select_related = ('content_type',)
search_fields = ('content_object_repr',) search_fields = ('content_object_repr',)
date_hierarchy = 'created_at'
display_created = admin_date('created_at', short_description=_("Created")) display_created = admin_date('created_at', short_description=_("Created"))

View File

@ -189,7 +189,11 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
def get_price_size(self, ini, end): def get_price_size(self, ini, end):
rdelta = relativedelta.relativedelta(end, ini) rdelta = relativedelta.relativedelta(end, ini)
if self.billing_period == self.MONTHLY: anual_prepay_of_monthly_pricing = bool(
self.billing_period == self.ANUAL and
self.payment_style == self.PREPAY and
self.get_pricing_period() == self.MONTHLY)
if self.billing_period == self.MONTHLY or anual_prepay_of_monthly_pricing:
size = rdelta.years * 12 size = rdelta.years * 12
size += rdelta.months size += rdelta.months
days = calendar.monthrange(end.year, end.month)[1] days = calendar.monthrange(end.year, end.month)[1]
@ -508,7 +512,9 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
recharges = [] recharges = []
rini = order.billed_on rini = order.billed_on
rend = min(bp, order.billed_until) rend = min(bp, order.billed_until)
bmetric = order.billed_metric or 0 bmetric = order.billed_metric
if bmetric is None:
bmetric = order.get_metric(order.billed_on)
bsize = self.get_price_size(rini, order.billed_until) bsize = self.get_price_size(rini, order.billed_until)
prepay_discount = self.get_price(account, bmetric) * bsize prepay_discount = self.get_price(account, bmetric) * bsize
prepay_discount = round(prepay_discount, 2) prepay_discount = round(prepay_discount, 2)
@ -580,6 +586,17 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
line = self.generate_line(order, price, cini, cend, metric=metric, line = self.generate_line(order, price, cini, cend, metric=metric,
discounts=discounts) discounts=discounts)
lines.append(line) lines.append(line)
elif self.get_pricing_period() in (self.MONTHLY, self.ANUAL):
if self.payment_style == self.PREPAY:
# Traffic Prepay
metric = order.get_metric(timezone.now().date())
if metric > 0:
price = self.get_price(account, metric)
for cini, cend in self.get_pricing_slots(ini, bp):
line = self.generate_line(order, price, cini, cend, metric=metric)
lines.append(line)
else:
raise NotImplementedError
else: else:
raise NotImplementedError raise NotImplementedError
else: else:

View File

@ -1,3 +1,4 @@
import calendar
import decimal import decimal
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -70,9 +71,8 @@ class Service(models.Model):
"<tt>&nbsp;contractedplan.plan.name == 'association_fee''</tt><br>" "<tt>&nbsp;contractedplan.plan.name == 'association_fee''</tt><br>"
"<tt>&nbsp;instance.active</tt>")) "<tt>&nbsp;instance.active</tt>"))
handler_type = models.CharField(_("handler"), max_length=256, blank=True, handler_type = models.CharField(_("handler"), max_length=256, blank=True,
help_text=_("Handler used for processing this Service. A handler " help_text=_("Handler used for processing this Service. A handler enables customized "
"enables customized behaviour far beyond what options " "behaviour far beyond what options here allow to."),
"here allow to."),
choices=ServiceHandler.get_choices()) choices=ServiceHandler.get_choices())
is_active = models.BooleanField(_("active"), default=True) is_active = models.BooleanField(_("active"), default=True)
ignore_superusers = models.BooleanField(_("ignore %s") % _ignore_types, default=True, ignore_superusers = models.BooleanField(_("ignore %s") % _ignore_types, default=True,
@ -87,16 +87,16 @@ class Service(models.Model):
), ),
default=ANUAL, blank=True) default=ANUAL, blank=True)
billing_point = models.CharField(_("billing point"), max_length=16, billing_point = models.CharField(_("billing point"), max_length=16,
help_text=_("Reference point for calculating the renewal date " help_text=_("Reference point for calculating the renewal date on recurring invoices"),
"on recurring invoices"),
choices=( choices=(
(ON_REGISTER, _("Registration date")), (ON_REGISTER, _("Registration date")),
(FIXED_DATE, _("Fixed billing date")), (FIXED_DATE, _("Every %(month)s") % {
'month': calendar.month_name[settings.SERVICES_SERVICE_ANUAL_BILLING_MONTH]
}),
), ),
default=FIXED_DATE) default=FIXED_DATE)
is_fee = models.BooleanField(_("fee"), default=False, is_fee = models.BooleanField(_("fee"), default=False,
help_text=_("Designates whether this service should be billed as " help_text=_("Designates whether this service should be billed as membership fee or not"))
" membership fee or not"))
order_description = models.CharField(_("Order description"), max_length=128, blank=True, order_description = models.CharField(_("Order description"), max_length=128, blank=True,
help_text=_( help_text=_(
"Python <a href='https://docs.python.org/2/library/functions.html#eval'>expression</a> " "Python <a href='https://docs.python.org/2/library/functions.html#eval'>expression</a> "