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):