diff --git a/TODO.md b/TODO.md
index 6dd5925e..f89c550e 100644
--- a/TODO.md
+++ b/TODO.md
@@ -408,4 +408,8 @@ touch /tmp/somefile
-# Pending vs bill(): get_billing_point() returns the next billing point, no matter if nbp > now(). pending filter filters by billed_until < now()
+# Change zone ttl
+# batch zone edditing
+# inherit registers from parent?
+
+# Bill metric disk 5 GB: unialber
diff --git a/orchestra/contrib/bills/models.py b/orchestra/contrib/bills/models.py
index f83a4db2..15d9ef5c 100644
--- a/orchestra/contrib/bills/models.py
+++ b/orchestra/contrib/bills/models.py
@@ -117,7 +117,7 @@ class Bill(models.Model):
def payment_state(self):
if self.is_open or self.get_type() == self.PROFORMA:
return self.OPEN
- secured = self.transactions.secured().amount()
+ secured = self.transactions.secured().amount() or 0
if secured >= self.total:
return self.PAID
elif self.transactions.exclude_rejected().exists():
@@ -140,6 +140,7 @@ class Bill(models.Model):
bill_type = self.get_type()
if bill_type == self.BILL:
raise TypeError('This method can not be used on BILL instances')
+ bill_type = bill_type.replace('AMENDMENT', 'AMENDMENT_')
prefix = getattr(settings, 'BILLS_%s_NUMBER_PREFIX' % bill_type)
if self.is_open:
prefix = 'O{}'.format(prefix)
diff --git a/orchestra/contrib/bills/settings.py b/orchestra/contrib/bills/settings.py
index 611a749a..cf880098 100644
--- a/orchestra/contrib/bills/settings.py
+++ b/orchestra/contrib/bills/settings.py
@@ -23,7 +23,6 @@ BILLS_FEE_NUMBER_PREFIX = Setting('BILLS_FEE_NUMBER_PREFIX',
'F'
)
-
BILLS_AMENDMENT_FEE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_FEE_NUMBER_PREFIX',
'B'
)
diff --git a/orchestra/contrib/domains/forms.py b/orchestra/contrib/domains/forms.py
index dad20233..59c0fa67 100644
--- a/orchestra/contrib/domains/forms.py
+++ b/orchestra/contrib/domains/forms.py
@@ -15,10 +15,15 @@ class BatchDomainCreationAdminForm(forms.ModelForm):
def clean_name(self):
self.extra_names = []
target = None
+ existing = set(Domain.objects.values_list('name', flat=True))
+ errors = []
for name in self.cleaned_data['name'].strip().splitlines():
name = name.strip()
if not name:
continue
+ if name in existing:
+ errors.append(ValidationError(_("%s domain name already exists.") % name))
+ existing.add(name)
if target is None:
target = name
else:
@@ -28,6 +33,8 @@ class BatchDomainCreationAdminForm(forms.ModelForm):
except ValidationError as e:
raise ValidationError(e.error_dict['name'])
self.extra_names.append(name)
+ if errors:
+ raise ValidationError(errors)
return target
def clean(self):
diff --git a/orchestra/contrib/mailer/admin.py b/orchestra/contrib/mailer/admin.py
index 17938e0a..78483270 100644
--- a/orchestra/contrib/mailer/admin.py
+++ b/orchestra/contrib/mailer/admin.py
@@ -1,3 +1,4 @@
+from django import forms
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.db.models import Count
@@ -23,8 +24,8 @@ COLORS = {
class MessageAdmin(admin.ModelAdmin):
list_display = (
- 'display_subject', 'colored_state', 'priority', 'to_address', 'from_address', 'created_at_delta',
- 'retries', 'last_retry_delta', 'num_logs',
+ 'display_subject', 'colored_state', 'priority', 'to_address', 'from_address',
+ 'created_at_delta', 'retries', 'last_retry_delta', 'num_logs',
)
list_filter = ('state', 'priority', 'retries')
list_prefetch_related = ('logs__id')
@@ -56,7 +57,9 @@ class MessageAdmin(admin.ModelAdmin):
urls = super(MessageAdmin, self).get_urls()
info = self.model._meta.app_label, self.model._meta.model_name
urls.insert(0,
- url(r'^send-pending/$', wrap_admin_view(self, self.send_pending_view), name='%s_%s_send_pending' % info)
+ url(r'^send-pending/$',
+ wrap_admin_view(self, self.send_pending_view),
+ name='%s_%s_send_pending' % info)
)
return urls
@@ -68,7 +71,11 @@ class MessageAdmin(admin.ModelAdmin):
task(send_pending).apply_async()
self.message_user(request, _("Pending messages are being sent on the background."))
return redirect('..')
-
+
+ def formfield_for_dbfield(self, db_field, **kwargs):
+ if db_field.name == 'subject':
+ kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
+ return super(MessageAdmin, self).formfield_for_dbfield(db_field, **kwargs)
class SMTPLogAdmin(admin.ModelAdmin):
list_display = (
diff --git a/orchestra/contrib/orders/forms.py b/orchestra/contrib/orders/forms.py
index c0d436bf..2376e612 100644
--- a/orchestra/contrib/orders/forms.py
+++ b/orchestra/contrib/orders/forms.py
@@ -31,6 +31,8 @@ def selected_related_choices(queryset):
for order in queryset:
verbose = '{description} '
verbose += '{account}'
+ if order.ignore:
+ verbose += ' (ignored)'
verbose = verbose.format(
order_url=change_url(order), description=order.description,
account_url=change_url(order.account), account=str(order.account)
diff --git a/orchestra/contrib/orders/models.py b/orchestra/contrib/orders/models.py
index 6d20672f..dcb46c9f 100644
--- a/orchestra/contrib/orders/models.py
+++ b/orchestra/contrib/orders/models.py
@@ -3,7 +3,7 @@ import decimal
import logging
from django.db import models
-from django.db.models import F, Q
+from django.db.models import F, Q, Sum
from django.apps import apps
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
@@ -58,11 +58,11 @@ class OrderQuerySet(models.QuerySet):
def get_related(self, **options):
""" returns related orders that could have a pricing effect """
- # TODO for performance reasons get missing from queryset:
- # TODO optimize this shit, don't get related if all objects are here
Service = apps.get_model(settings.ORDERS_SERVICE_MODEL)
conflictive = self.filter(service__metric='')
- conflictive = conflictive.exclude(service__billing_period=Service.NEVER).exclude(service__rates__isnull=True)
+ conflictive = conflictive.exclude(service__billing_period=Service.NEVER)
+ # Exclude rates null or all rates with quantity 0
+ conflictive = conflictive.annotate(quantity_sum=Sum('service__rates__quantity')).exclude(quantity_sum=0)
conflictive = conflictive.select_related('service').distinct().group_by('account_id', 'service')
qs = Q()
for account_id, services in conflictive.items():
diff --git a/orchestra/contrib/services/handlers.py b/orchestra/contrib/services/handlers.py
index ab1645f4..72868c3e 100644
--- a/orchestra/contrib/services/handlers.py
+++ b/orchestra/contrib/services/handlers.py
@@ -23,7 +23,7 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
Relax and enjoy the journey.
"""
- _VOLUME = 'volume'
+ _PLAN = 'plan'
_COMPENSATION = 'compensation'
model = None
@@ -276,7 +276,7 @@ class ServiceHandler(plugins.Plugin, metaclass=plugins.PluginMount):
discounted += dprice
subtotal += discounted
if subtotal > price:
- self.generate_discount(line, self._VOLUME, price-subtotal)
+ self.generate_discount(line, self._PLAN, price-subtotal)
return line
def assign_compensations(self, givers, receivers, **options):