Added services templates
This commit is contained in:
parent
c2b0186034
commit
e8759578b5
|
@ -112,9 +112,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
fields = ('account_link', 'email_link', 'mailboxes', 'forward')
|
||||
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
|
||||
inlines = [AutoresponseInline]
|
||||
search_fields = (
|
||||
'name', 'domain__name', 'forward', 'mailboxes__name', 'account__username', 'computed_email'
|
||||
)
|
||||
search_fields = ('forward', 'mailboxes__name', 'account__username', 'computed_email')
|
||||
readonly_fields = ('account_link', 'domain_link', 'email_link')
|
||||
filter_by_account_fields = ('domain', 'mailboxes')
|
||||
filter_horizontal = ['mailboxes']
|
||||
|
@ -148,6 +146,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
return '<br>'.join(values)
|
||||
display_forward.short_description = _("Forward")
|
||||
display_forward.allow_tags = True
|
||||
display_forward.admin_order_field = 'forward'
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
if db_field.name == 'forward':
|
||||
|
|
|
@ -78,7 +78,8 @@ class Rate(models.Model):
|
|||
service = models.ForeignKey('services.Service', verbose_name=_("service"),
|
||||
related_name='rates')
|
||||
plan = models.ForeignKey(Plan, verbose_name=_("plan"), related_name='rates')
|
||||
quantity = models.PositiveIntegerField(_("quantity"), null=True, blank=True)
|
||||
quantity = models.PositiveIntegerField(_("quantity"), null=True, blank=True,
|
||||
help_text=_("See rate algorihm help text."))
|
||||
price = models.DecimalField(_("price"), max_digits=12, decimal_places=2)
|
||||
|
||||
objects = RateQuerySet.as_manager()
|
||||
|
|
|
@ -120,7 +120,8 @@ def step_price(rates, metric):
|
|||
minimal = min(minimal, (value, result), key=lambda v: v[0])
|
||||
return minimal[1]
|
||||
step_price.verbose_name = _("Step price")
|
||||
step_price.help_text = _("All price rates with a lower metric are applied.")
|
||||
step_price.help_text = _("All rates with a quantity lower than the metric are applied. "
|
||||
"Nominal price will be used when initial block is missing.")
|
||||
|
||||
|
||||
def match_price(rates, metric):
|
||||
|
@ -149,4 +150,5 @@ def match_price(rates, metric):
|
|||
})]
|
||||
return None
|
||||
match_price.verbose_name = _("Match price")
|
||||
match_price.help_text = _("Only the rate with inmediate inferior metric is applied.")
|
||||
match_price.help_text = _("Only <b>the rate</b> with a) inmediate inferior metric and b) lower price is applied. "
|
||||
"Nominal price will be used when initial block is missing.")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "orchestra/admin/change_form.html" %}
|
||||
{% load i18n admin_urls admin_static admin_modify %}
|
||||
{% load i18n admin_urls admin_static admin_modify utils %}
|
||||
|
||||
|
||||
{% block object-tools %}
|
||||
|
@ -7,8 +7,9 @@
|
|||
<ul class="object-tools">
|
||||
<li><select name="forma" onchange="location = this.options[this.selectedIndex].value;" style="margin: -3px 0 0 0;">
|
||||
<option selected disabled>{% trans "Templates" %}</option>
|
||||
{% oneliner %}
|
||||
<option value="./?description=Mailbox&
|
||||
content_type=10&
|
||||
content_type={{ 'mailboxes.mailbox'|content_type_id }}&
|
||||
match=mailbox.active&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
|
@ -22,9 +23,27 @@
|
|||
nominal_price=28.10&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=MATCH_PRICE&
|
||||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=COMPENSATE&
|
||||
payment_style=PREPAY">Mailbox</option>
|
||||
<option value="./?description=Mailbox%20allocated%20disk&
|
||||
content_type=10&
|
||||
match=mailbox.active&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=ANUAL&
|
||||
billing_point=ON_FIXED_DATE&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=TEN_DAYS&
|
||||
metric=max(logsteps(mailbox.resources.disk.allocated%20or%200)%20-2,%200)&
|
||||
nominal_price=20.00&
|
||||
tax=21&
|
||||
pricing_period=&
|
||||
rate_algorithm=MATCH_PRICE&
|
||||
on_cancel=DISCOUNT&
|
||||
payment_style=PREPAY">Mailbox allocated disk</option>
|
||||
<option value="./?description=Database&
|
||||
content_type=19&
|
||||
match=database.account.is_active&handler_type=&
|
||||
|
@ -42,6 +61,115 @@
|
|||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=COMPENSATE&
|
||||
payment_style=PREPAY">Database</option>
|
||||
<option value="./?description=Basic%20domain&
|
||||
content_type=34&
|
||||
match=miscellaneous.active%20and%20miscellaneous.service.name%20==%20%27domain-registration%27&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=ANUAL&
|
||||
billing_point=ON_REGISTER&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=&
|
||||
metric=&
|
||||
nominal_price=19.01&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=NOTHING&
|
||||
payment_style=PREPAY">Basic domain</option>
|
||||
<option value="./?description=Domain%20.cat%20extra&
|
||||
content_type=34&
|
||||
match=miscellaneous.active%20and%20miscellaneous.service.name%20==%20%27domain-registration%27%20and%20miscellaneous.identifier.endswith(%27.cat%27)&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=ANUAL&
|
||||
billing_point=ON_REGISTER&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=&
|
||||
metric=&
|
||||
nominal_price=26.59&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=NOTHING&
|
||||
payment_style=PREPAY">Domain .cat extra</option>
|
||||
<option value="./?description=FTP%20account&
|
||||
content_type=9&
|
||||
match=systemuser.active%20and%20not%20systemuser.is_main&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=ANUAL&
|
||||
billing_point=ON_FIXED_DATE&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=TEN_DAYS&
|
||||
metric=&
|
||||
nominal_price=28.10&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=COMPENSATE&
|
||||
payment_style=PREPAY">FTP account</option>
|
||||
<option value="./?description=Traffic&
|
||||
content_type=1&
|
||||
match=True&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=MONTHLY&
|
||||
billing_point=ON_FIXED_DATE&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=TEN_DAYS&
|
||||
metric=logsteps(max((account.resources.traffic.used%20or%200)%20-%20getattr(account.miscellaneous.filter(is_active=True,%20service__name=%27traffic-prepay%27).last(),%20%27amount%27,%200),%200),%20size=0.05)&
|
||||
nominal_price=4.50&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=MATCH_PRICE&
|
||||
on_cancel=NOTHING&
|
||||
payment_style=POSTPAY">Traffic</option>
|
||||
<option value="./?description=Traffic%20prepay&
|
||||
content_type=34&
|
||||
match=miscellaneous.active%20and%20miscellaneous.service.name%20==%20%27traffic-prepay%27&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=ANUAL&
|
||||
billing_point=ON_FIXED_DATE&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=TEN_DAYS&
|
||||
metric=miscellaneous.amount&
|
||||
nominal_price=3.00&
|
||||
tax=21&
|
||||
pricing_period=MONTHLY&
|
||||
rate_algorithm=MATCH_PRICE&
|
||||
on_cancel=REFUND&
|
||||
payment_style=PREPAY">Traffic prepay</option>
|
||||
<option value="./?description=Development&
|
||||
content_type=34&
|
||||
match=miscellaneous.active%20and%20miscellaneous.service.name%20==%20%27development%27&
|
||||
handler_type=&
|
||||
is_active=True&
|
||||
ignore_superusers=True&
|
||||
billing_period=&
|
||||
billing_point=ON_FIXED_DATE&
|
||||
is_fee=&
|
||||
order_description=&
|
||||
ignore_period=TEN_DAYS&
|
||||
metric=miscellaneous.amount&
|
||||
nominal_price=40.00&
|
||||
tax=21&
|
||||
pricing_period=BILLING_PERIOD&
|
||||
rate_algorithm=STEP_PRICE&
|
||||
on_cancel=NOTHING&
|
||||
payment_style=PREPAY">Develompent</option>
|
||||
{% endoneliner %}
|
||||
</select></li>
|
||||
<li>
|
||||
<a href="./help/" class="historylink">{% trans "Help" %}</a>
|
||||
|
|
|
@ -32,13 +32,8 @@ class WebAppViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
|
|||
data = meta.get_serializer_info(app_type.serializer())
|
||||
else:
|
||||
data = {}
|
||||
options = []
|
||||
for group, option in app_type.get_options():
|
||||
options += [opt.name for opt in option]
|
||||
app_types[app_type.get_name()] = {
|
||||
'data': data,
|
||||
'options': options,
|
||||
}
|
||||
data['option_groups'] = app_type.option_groups
|
||||
app_types[app_type.get_name()] = data
|
||||
metadata.data['actions']['types'] = app_types
|
||||
# Options
|
||||
options = {}
|
||||
|
|
|
@ -74,29 +74,29 @@ class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
|||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
options_data = validated_data.pop('options')
|
||||
directives_data = validated_data.pop('directives')
|
||||
webapp = super(WebsiteSerializer, self).create(validated_data)
|
||||
for key, value in options_data.items():
|
||||
WebAppOption.objects.create(webapp=webapp, name=key, value=value)
|
||||
for key, value in directives_data.items():
|
||||
WebsiteDirective.objects.create(webapp=webapp, name=key, value=value)
|
||||
return webap
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
options_data = validated_data.pop('options')
|
||||
directives_data = validated_data.pop('directives')
|
||||
instance = super(WebsiteSerializer, self).update(instance, validated_data)
|
||||
existing = {}
|
||||
for obj in instance.options.all():
|
||||
for obj in instance.directives.all():
|
||||
existing[obj.name] = obj
|
||||
posted = set()
|
||||
for key, value in options_data.items():
|
||||
for key, value in directives_data.items():
|
||||
posted.add(key)
|
||||
try:
|
||||
option = existing[key]
|
||||
directive = existing[key]
|
||||
except KeyError:
|
||||
option = instance.options.create(name=key, value=value)
|
||||
directive = instance.directives.create(name=key, value=value)
|
||||
else:
|
||||
if option.value != value:
|
||||
option.value = value
|
||||
option.save(update_fields=('value',))
|
||||
if directive.value != value:
|
||||
directive.value = value
|
||||
directive.save(update_fields=('value',))
|
||||
for to_delete in set(existing.keys())-posted:
|
||||
existing[to_delete].delete()
|
||||
return instance
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import re
|
||||
|
||||
from django import template
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||
from django.forms import CheckboxInput
|
||||
from django.template.base import Node
|
||||
|
||||
from orchestra import get_version
|
||||
from orchestra.admin.utils import change_url
|
||||
|
@ -43,6 +47,22 @@ def rest_to_admin_url(context):
|
|||
return reverse('admin:index')
|
||||
|
||||
|
||||
class OneLinerNode(Node):
|
||||
def __init__(self, nodelist):
|
||||
self.nodelist = nodelist
|
||||
|
||||
def render(self, context):
|
||||
line = self.nodelist.render(context).replace('\n', ' ')
|
||||
return re.sub(r'\s\s+', '', line)
|
||||
|
||||
|
||||
@register.tag
|
||||
def oneliner(parser, token):
|
||||
nodelist = parser.parse(('endoneliner',))
|
||||
parser.delete_first_token()
|
||||
return OneLinerNode(nodelist)
|
||||
|
||||
|
||||
@register.filter
|
||||
def size(value, length):
|
||||
value = str(value)[:int(length)]
|
||||
|
@ -55,6 +75,12 @@ def is_checkbox(field):
|
|||
return isinstance(field.field.widget, CheckboxInput)
|
||||
|
||||
|
||||
@register.filter
|
||||
def content_type_id(label):
|
||||
app_label, model = label.split('.')
|
||||
return ContentType.objects.filter(app_label=app_label, model=model).values_list('id', flat=True)[0]
|
||||
|
||||
|
||||
@register.filter
|
||||
def admin_url(obj):
|
||||
return change_url(obj)
|
||||
|
@ -63,3 +89,4 @@ def admin_url(obj):
|
|||
@register.filter
|
||||
def isactive(obj):
|
||||
return getattr(obj, 'is_active', True)
|
||||
|
||||
|
|
Loading…
Reference in a new issue