Use freezegun for test time mockup
This commit is contained in:
parent
c0e8e9f85d
commit
0de534f4e2
1
TODO.md
1
TODO.md
|
@ -109,3 +109,4 @@ at + clock time, midnight, noon- At 3:30 p.m., At 4:01, At noon
|
||||||
|
|
||||||
|
|
||||||
* latest by 'id' *always*
|
* latest by 'id' *always*
|
||||||
|
* replace add_now by default=lambda: timezone.now()
|
||||||
|
|
|
@ -35,17 +35,21 @@ class Bill(models.Model):
|
||||||
(PENDING, _("Pending")),
|
(PENDING, _("Pending")),
|
||||||
(BAD_DEBT, _("Bad debt")),
|
(BAD_DEBT, _("Bad debt")),
|
||||||
)
|
)
|
||||||
|
BILL = 'BILL'
|
||||||
|
INVOICE = 'INVOICE'
|
||||||
|
AMENDMENTINVOICE = 'AMENDMENTINVOICE'
|
||||||
|
FEE = 'FEE'
|
||||||
|
AMENDMENTFEE = 'AMENDMENTFEE'
|
||||||
|
PROFORMA = 'PROFORMA'
|
||||||
TYPES = (
|
TYPES = (
|
||||||
('INVOICE', _("Invoice")),
|
(INVOICE, _("Invoice")),
|
||||||
('AMENDMENTINVOICE', _("Amendment invoice")),
|
(AMENDMENTINVOICE, _("Amendment invoice")),
|
||||||
('FEE', _("Fee")),
|
(FEE, _("Fee")),
|
||||||
('AMENDMENTFEE', _("Amendment Fee")),
|
(AMENDMENTFEE, _("Amendment Fee")),
|
||||||
('PROFORMA', _("Pro forma")),
|
(PROFORMA, _("Pro forma")),
|
||||||
)
|
)
|
||||||
|
|
||||||
number = models.CharField(_("number"), max_length=16, unique=True,
|
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
|
||||||
blank=True)
|
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||||
related_name='%(class)s')
|
related_name='%(class)s')
|
||||||
type = models.CharField(_("type"), max_length=16, choices=TYPES)
|
type = models.CharField(_("type"), max_length=16, choices=TYPES)
|
||||||
|
@ -63,7 +67,7 @@ class Bill(models.Model):
|
||||||
objects = BillManager()
|
objects = BillManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = 'created_on'
|
get_latest_by = 'id'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.number
|
return self.number
|
||||||
|
@ -101,8 +105,8 @@ class Bill(models.Model):
|
||||||
def set_number(self):
|
def set_number(self):
|
||||||
cls = type(self)
|
cls = type(self)
|
||||||
bill_type = self.get_type()
|
bill_type = self.get_type()
|
||||||
if bill_type == 'BILL':
|
if bill_type == self.BILL:
|
||||||
raise TypeError("get_new_number() can not be used on a Bill class")
|
raise TypeError('This method can not be used on BILL instances')
|
||||||
prefix = getattr(settings, 'BILLS_%s_NUMBER_PREFIX' % bill_type)
|
prefix = getattr(settings, 'BILLS_%s_NUMBER_PREFIX' % bill_type)
|
||||||
if self.is_open:
|
if self.is_open:
|
||||||
prefix = 'O{}'.format(prefix)
|
prefix = 'O{}'.format(prefix)
|
||||||
|
@ -117,8 +121,7 @@ class Bill(models.Model):
|
||||||
number_length = settings.BILLS_NUMBER_LENGTH
|
number_length = settings.BILLS_NUMBER_LENGTH
|
||||||
zeros = (number_length - len(str(number))) * '0'
|
zeros = (number_length - len(str(number))) * '0'
|
||||||
number = zeros + str(number)
|
number = zeros + str(number)
|
||||||
self.number = '{prefix}{year}{number}'.format(
|
self.number = '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number)
|
||||||
prefix=prefix, year=year, number=number)
|
|
||||||
|
|
||||||
def get_due_date(self, payment=None):
|
def get_due_date(self, payment=None):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
@ -134,7 +137,7 @@ class Bill(models.Model):
|
||||||
self.due_on = self.get_due_date(payment=payment)
|
self.due_on = self.get_due_date(payment=payment)
|
||||||
self.total = self.get_total()
|
self.total = self.get_total()
|
||||||
self.html = self.render(payment=payment)
|
self.html = self.render(payment=payment)
|
||||||
if self.get_type() != 'PROFORMA':
|
if self.get_type() != self.PROFORMA:
|
||||||
self.transactions.create(bill=self, source=payment, amount=self.total)
|
self.transactions.create(bill=self, source=payment, amount=self.total)
|
||||||
self.closed_on = timezone.now()
|
self.closed_on = timezone.now()
|
||||||
self.is_open = False
|
self.is_open = False
|
||||||
|
@ -175,8 +178,8 @@ class Bill(models.Model):
|
||||||
'default_due_date': self.get_due_date(payment=payment),
|
'default_due_date': self.get_due_date(payment=payment),
|
||||||
'now': timezone.now(),
|
'now': timezone.now(),
|
||||||
})
|
})
|
||||||
template = getattr(settings, 'BILLS_%s_TEMPLATE' % self.get_type(),
|
template_name = 'BILLS_%s_TEMPLATE' % self.get_type()
|
||||||
settings.BILLS_DEFAULT_TEMPLATE)
|
template = getattr(settings, template_name, settings.BILLS_DEFAULT_TEMPLATE)
|
||||||
bill_template = loader.get_template(template)
|
bill_template = loader.get_template(template)
|
||||||
html = bill_template.render(context)
|
html = bill_template.render(context)
|
||||||
html = html.replace('-pageskip-', '<pdf:nextpage />')
|
html = html.replace('-pageskip-', '<pdf:nextpage />')
|
||||||
|
@ -234,8 +237,7 @@ class BillLine(models.Model):
|
||||||
""" Base model for bill item representation """
|
""" Base model for bill item representation """
|
||||||
bill = models.ForeignKey(Bill, verbose_name=_("bill"), related_name='lines')
|
bill = models.ForeignKey(Bill, verbose_name=_("bill"), related_name='lines')
|
||||||
description = models.CharField(_("description"), max_length=256)
|
description = models.CharField(_("description"), max_length=256)
|
||||||
rate = models.DecimalField(_("rate"), blank=True, null=True,
|
rate = models.DecimalField(_("rate"), blank=True, null=True, max_digits=12, decimal_places=2)
|
||||||
max_digits=12, decimal_places=2)
|
|
||||||
quantity = models.DecimalField(_("quantity"), max_digits=12, decimal_places=2)
|
quantity = models.DecimalField(_("quantity"), max_digits=12, decimal_places=2)
|
||||||
subtotal = models.DecimalField(_("subtotal"), max_digits=12, decimal_places=2)
|
subtotal = models.DecimalField(_("subtotal"), max_digits=12, decimal_places=2)
|
||||||
tax = models.PositiveIntegerField(_("tax"))
|
tax = models.PositiveIntegerField(_("tax"))
|
||||||
|
@ -261,7 +263,7 @@ class BillLine(models.Model):
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# TODO cost of this shit
|
# TODO cost and consistency of this shit
|
||||||
super(BillLine, self).save(*args, **kwargs)
|
super(BillLine, self).save(*args, **kwargs)
|
||||||
if self.bill.is_open:
|
if self.bill.is_open:
|
||||||
self.bill.total = self.bill.get_total()
|
self.bill.total = self.bill.get_total()
|
||||||
|
@ -270,8 +272,7 @@ class BillLine(models.Model):
|
||||||
|
|
||||||
class BillSubline(models.Model):
|
class BillSubline(models.Model):
|
||||||
""" Subline used for describing an item discount """
|
""" Subline used for describing an item discount """
|
||||||
line = models.ForeignKey(BillLine, verbose_name=_("bill line"),
|
line = models.ForeignKey(BillLine, verbose_name=_("bill line"), related_name='sublines')
|
||||||
related_name='sublines')
|
|
||||||
description = models.CharField(_("description"), max_length=256)
|
description = models.CharField(_("description"), max_length=256)
|
||||||
total = models.DecimalField(max_digits=12, decimal_places=2)
|
total = models.DecimalField(max_digits=12, decimal_places=2)
|
||||||
# TODO type ? Volume and Compensation
|
# TODO type ? Volume and Compensation
|
||||||
|
|
|
@ -57,7 +57,9 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
|
||||||
list_filter = [TopDomainListFilter]
|
list_filter = [TopDomainListFilter]
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
search_fields = ['name', 'account__user__username']
|
search_fields = ['name', 'account__user__username']
|
||||||
default_changelist_filters = (('top_domain', 'True'),)
|
default_changelist_filters = (
|
||||||
|
('top_domain', 'True'),
|
||||||
|
)
|
||||||
form = DomainAdminForm
|
form = DomainAdminForm
|
||||||
|
|
||||||
def structured_name(self, domain):
|
def structured_name(self, domain):
|
||||||
|
|
|
@ -74,7 +74,9 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
|
|
||||||
class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
verbose_name = _("Bind9 slave domain")
|
verbose_name = _("Bind9 slave domain")
|
||||||
related_models = (('domains.Domain', 'origin'),)
|
related_models = (
|
||||||
|
('domains.Domain', 'origin'),
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, domain):
|
def save(self, domain):
|
||||||
context = self.get_context(domain)
|
context = self.get_context(domain)
|
||||||
|
|
|
@ -161,7 +161,7 @@ class Message(models.Model):
|
||||||
created_on = models.DateTimeField(_("created on"), auto_now_add=True)
|
created_on = models.DateTimeField(_("created on"), auto_now_add=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = "created_on"
|
get_latest_by = 'id'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"#%i" % self.id
|
return u"#%i" % self.id
|
||||||
|
@ -188,4 +188,6 @@ class TicketTracker(models.Model):
|
||||||
related_name='ticket_trackers')
|
related_name='ticket_trackers')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (('ticket', 'user'),)
|
unique_together = (
|
||||||
|
('ticket', 'user'),
|
||||||
|
)
|
||||||
|
|
|
@ -66,7 +66,7 @@ class BackendLog(models.Model):
|
||||||
last_update = models.DateTimeField(_("last update"), auto_now=True)
|
last_update = models.DateTimeField(_("last update"), auto_now=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = 'created'
|
get_latest_by = 'id'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def execution_time(self):
|
def execution_time(self):
|
||||||
|
|
|
@ -81,9 +81,9 @@ class Order(models.Model):
|
||||||
related_name='orders')
|
related_name='orders')
|
||||||
content_type = models.ForeignKey(ContentType)
|
content_type = models.ForeignKey(ContentType)
|
||||||
object_id = models.PositiveIntegerField(null=True)
|
object_id = models.PositiveIntegerField(null=True)
|
||||||
service = models.ForeignKey(settings.ORDERS_SERVICE_MODEL,
|
service = models.ForeignKey(settings.ORDERS_SERVICE_MODEL, verbose_name=_("service"),
|
||||||
verbose_name=_("service"), related_name='orders')
|
related_name='orders')
|
||||||
registered_on = models.DateField(_("registered"), auto_now_add=True) # TODO datetime field?
|
registered_on = models.DateField(_("registered"), default=lambda: timezone.now())
|
||||||
cancelled_on = models.DateField(_("cancelled"), null=True, blank=True)
|
cancelled_on = models.DateField(_("cancelled"), null=True, blank=True)
|
||||||
billed_on = models.DateField(_("billed on"), null=True, blank=True)
|
billed_on = models.DateField(_("billed on"), null=True, blank=True)
|
||||||
billed_until = models.DateField(_("billed until"), null=True, blank=True)
|
billed_until = models.DateField(_("billed until"), null=True, blank=True)
|
||||||
|
@ -93,6 +93,9 @@ class Order(models.Model):
|
||||||
content_object = generic.GenericForeignKey()
|
content_object = generic.GenericForeignKey()
|
||||||
objects = OrderQuerySet.as_manager()
|
objects = OrderQuerySet.as_manager()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
get_latest_by = 'id'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return str(self.service)
|
return str(self.service)
|
||||||
|
|
||||||
|
@ -180,6 +183,7 @@ class MetricStorage(models.Model):
|
||||||
order = models.ForeignKey(Order, verbose_name=_("order"), related_name='metrics')
|
order = models.ForeignKey(Order, verbose_name=_("order"), related_name='metrics')
|
||||||
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
|
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
|
||||||
created_on = models.DateField(_("created"), auto_now_add=True)
|
created_on = models.DateField(_("created"), auto_now_add=True)
|
||||||
|
# default=lambda: timezone.now())
|
||||||
updated_on = models.DateTimeField(_("updated"))
|
updated_on = models.DateTimeField(_("updated"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -203,9 +207,11 @@ class MetricStorage(models.Model):
|
||||||
metric.save()
|
metric.save()
|
||||||
|
|
||||||
|
|
||||||
_excluded_models = (MetricStorage, LogEntry, Order, ContentType, MigrationRecorder.Migration)
|
accounts.register(Order)
|
||||||
|
|
||||||
|
|
||||||
|
_excluded_models = (MetricStorage, LogEntry, Order, ContentType, MigrationRecorder.Migration)
|
||||||
|
|
||||||
@receiver(post_delete, dispatch_uid="orders.cancel_orders")
|
@receiver(post_delete, dispatch_uid="orders.cancel_orders")
|
||||||
def cancel_orders(sender, **kwargs):
|
def cancel_orders(sender, **kwargs):
|
||||||
if sender not in _excluded_models:
|
if sender not in _excluded_models:
|
||||||
|
@ -218,7 +224,6 @@ def cancel_orders(sender, **kwargs):
|
||||||
if related and related != instance:
|
if related and related != instance:
|
||||||
Order.update_orders(related)
|
Order.update_orders(related)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, dispatch_uid="orders.update_orders")
|
@receiver(post_save, dispatch_uid="orders.update_orders")
|
||||||
def update_orders(sender, **kwargs):
|
def update_orders(sender, **kwargs):
|
||||||
if sender not in _excluded_models:
|
if sender not in _excluded_models:
|
||||||
|
@ -229,7 +234,3 @@ def update_orders(sender, **kwargs):
|
||||||
related = helpers.get_related_objects(instance)
|
related = helpers.get_related_objects(instance)
|
||||||
if related and related != instance:
|
if related and related != instance:
|
||||||
Order.update_orders(related)
|
Order.update_orders(related)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
accounts.register(Order)
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ import datetime
|
||||||
import decimal
|
import decimal
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from dateutil import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from orchestra.apps.accounts.models import Account
|
from orchestra.apps.accounts.models import Account
|
||||||
from orchestra.apps.mails.models import Mailbox
|
from orchestra.apps.mails.models import Mailbox
|
||||||
|
@ -56,21 +57,21 @@ class FTPBillingTest(BaseBillingTest):
|
||||||
def test_ftp_account_1_year_fiexed(self):
|
def test_ftp_account_1_year_fiexed(self):
|
||||||
service = self.create_ftp_service()
|
service = self.create_ftp_service()
|
||||||
user = self.create_ftp()
|
user = self.create_ftp()
|
||||||
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
|
bp = timezone.now().date() + relativedelta(years=1)
|
||||||
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
||||||
self.assertEqual(10, bills[0].get_total())
|
self.assertEqual(10, bills[0].get_total())
|
||||||
|
|
||||||
def test_ftp_account_2_year_fiexed(self):
|
def test_ftp_account_2_year_fiexed(self):
|
||||||
service = self.create_ftp_service()
|
service = self.create_ftp_service()
|
||||||
user = self.create_ftp()
|
user = self.create_ftp()
|
||||||
bp = timezone.now().date() + relativedelta.relativedelta(years=2)
|
bp = timezone.now().date() + relativedelta(years=2)
|
||||||
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
||||||
self.assertEqual(20, bills[0].get_total())
|
self.assertEqual(20, bills[0].get_total())
|
||||||
|
|
||||||
def test_ftp_account_6_month_fixed(self):
|
def test_ftp_account_6_month_fixed(self):
|
||||||
service = self.create_ftp_service()
|
service = self.create_ftp_service()
|
||||||
self.create_ftp()
|
self.create_ftp()
|
||||||
bp = timezone.now().date() + relativedelta.relativedelta(months=6)
|
bp = timezone.now().date() + relativedelta(months=6)
|
||||||
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
bills = service.orders.bill(billing_point=bp, fixed_point=True)
|
||||||
self.assertEqual(5, bills[0].get_total())
|
self.assertEqual(5, bills[0].get_total())
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ class FTPBillingTest(BaseBillingTest):
|
||||||
account = self.create_account()
|
account = self.create_account()
|
||||||
service = self.create_ftp_service()
|
service = self.create_ftp_service()
|
||||||
user = self.create_ftp(account=account)
|
user = self.create_ftp(account=account)
|
||||||
first_bp = timezone.now().date() + relativedelta.relativedelta(years=2)
|
first_bp = timezone.now().date() + relativedelta(years=2)
|
||||||
bills = service.orders.bill(billing_point=first_bp, fixed_point=True)
|
bills = service.orders.bill(billing_point=first_bp, fixed_point=True)
|
||||||
self.assertEqual(1, service.orders.active().count())
|
self.assertEqual(1, service.orders.active().count())
|
||||||
user.delete()
|
user.delete()
|
||||||
|
@ -103,7 +104,7 @@ class FTPBillingTest(BaseBillingTest):
|
||||||
user = self.create_ftp(account=account)
|
user = self.create_ftp(account=account)
|
||||||
self.assertEqual(1, service.orders.active().count())
|
self.assertEqual(1, service.orders.active().count())
|
||||||
self.assertEqual(2, service.orders.count())
|
self.assertEqual(2, service.orders.count())
|
||||||
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
|
bp = timezone.now().date() + relativedelta(years=1)
|
||||||
bills = service.orders.bill(billing_point=bp, fixed_point=True, new_open=True)
|
bills = service.orders.bill(billing_point=bp, fixed_point=True, new_open=True)
|
||||||
discount = bills[0].lines.order_by('id')[0].sublines.get()
|
discount = bills[0].lines.order_by('id')[0].sublines.get()
|
||||||
self.assertEqual(decimal.Decimal(-20), discount.total)
|
self.assertEqual(decimal.Decimal(-20), discount.total)
|
||||||
|
@ -246,7 +247,9 @@ class DomainBillingTest(BaseBillingTest):
|
||||||
self.assertEqual(6, bills[0].get_total())
|
self.assertEqual(6, bills[0].get_total())
|
||||||
|
|
||||||
|
|
||||||
class TrafficBillingTest(BaseBillingTest):
|
class BaseTrafficBillingTest(BaseBillingTest):
|
||||||
|
METRIC = 'account.resources.traffic.used'
|
||||||
|
|
||||||
def create_traffic_service(self):
|
def create_traffic_service(self):
|
||||||
service = Service.objects.create(
|
service = Service.objects.create(
|
||||||
description="Traffic",
|
description="Traffic",
|
||||||
|
@ -255,7 +258,7 @@ class TrafficBillingTest(BaseBillingTest):
|
||||||
billing_period=Service.MONTHLY,
|
billing_period=Service.MONTHLY,
|
||||||
billing_point=Service.FIXED_DATE,
|
billing_point=Service.FIXED_DATE,
|
||||||
is_fee=False,
|
is_fee=False,
|
||||||
metric='account.resources.traffic.used',
|
metric=self.METRIC,
|
||||||
pricing_period=Service.BILLING_PERIOD,
|
pricing_period=Service.BILLING_PERIOD,
|
||||||
rate_algorithm=Service.STEP_PRICE,
|
rate_algorithm=Service.STEP_PRICE,
|
||||||
on_cancel=Service.NOTHING,
|
on_cancel=Service.NOTHING,
|
||||||
|
@ -288,6 +291,8 @@ class TrafficBillingTest(BaseBillingTest):
|
||||||
data = ResourceData.get_or_create(account, self.resource)
|
data = ResourceData.get_or_create(account, self.resource)
|
||||||
data.update()
|
data.update()
|
||||||
|
|
||||||
|
|
||||||
|
class TrafficBillingTest(BaseTrafficBillingTest):
|
||||||
def test_traffic(self):
|
def test_traffic(self):
|
||||||
service = self.create_traffic_service()
|
service = self.create_traffic_service()
|
||||||
resource = self.create_traffic_resource()
|
resource = self.create_traffic_resource()
|
||||||
|
@ -297,7 +302,7 @@ class TrafficBillingTest(BaseBillingTest):
|
||||||
bills = service.orders.bill(commit=False)
|
bills = service.orders.bill(commit=False)
|
||||||
self.assertEqual([(account, [])], bills)
|
self.assertEqual([(account, [])], bills)
|
||||||
|
|
||||||
# Prepay
|
# move into the past
|
||||||
delta = datetime.timedelta(days=60)
|
delta = datetime.timedelta(days=60)
|
||||||
date = (timezone.now()-delta).date()
|
date = (timezone.now()-delta).date()
|
||||||
order = service.orders.get()
|
order = service.orders.get()
|
||||||
|
@ -323,9 +328,70 @@ class TrafficBillingTest(BaseBillingTest):
|
||||||
account2 = self.create_account()
|
account2 = self.create_account()
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
|
|
||||||
|
class TrafficPrepayBillingTest(BaseTrafficBillingTest):
|
||||||
|
METRIC = "max((account.resources.traffic.used or 0) - getattr(account.miscellaneous.filter(service__name='traffic prepay').last(), 'amount', 0), 0)"
|
||||||
|
|
||||||
|
def create_prepay_service(self):
|
||||||
|
service = Service.objects.create(
|
||||||
|
description="Traffic prepay",
|
||||||
|
content_type=ContentType.objects.get_for_model(Miscellaneous),
|
||||||
|
match="miscellaneous.is_active and miscellaneous.service.name.lower() == 'traffic prepay'",
|
||||||
|
billing_period=Service.ANUAL,
|
||||||
|
billing_point=Service.FIXED_DATE,
|
||||||
|
is_fee=False,
|
||||||
|
metric="miscellaneous.amount",
|
||||||
|
pricing_period=Service.BILLING_PERIOD,
|
||||||
|
rate_algorithm=Service.STEP_PRICE,
|
||||||
|
on_cancel=Service.NOTHING, # TODO on_register == NOTHING or make on_cancel generic
|
||||||
|
payment_style=Service.PREPAY,
|
||||||
|
tax=0,
|
||||||
|
nominal_price=5
|
||||||
|
)
|
||||||
|
return service
|
||||||
|
|
||||||
|
def create_prepay(self, amount, account=None):
|
||||||
|
if not account:
|
||||||
|
account = self.create_account()
|
||||||
|
name = 'traffic prepay'
|
||||||
|
service, __ = MiscService.objects.get_or_create(name='traffic prepay', description='Traffic prepay', has_amount=True)
|
||||||
|
return Miscellaneous.objects.create(service=service, description=name, account=account, amount=amount)
|
||||||
|
|
||||||
def test_traffic_prepay(self):
|
def test_traffic_prepay(self):
|
||||||
pass
|
service = self.create_traffic_service()
|
||||||
# TODO
|
prepay_service = self.create_prepay_service()
|
||||||
|
account = self.create_account()
|
||||||
|
|
||||||
|
self.create_traffic_resource()
|
||||||
|
prepay = self.create_prepay(10, account=account)
|
||||||
|
self.report_traffic(account, timezone.now(), 10**9)
|
||||||
|
|
||||||
|
print prepay_service.orders.all()
|
||||||
|
# TODO metric on the current day! how to solve it consistently?
|
||||||
|
# TODO prepay doesnt allow for discount
|
||||||
|
|
||||||
|
# move into the past
|
||||||
|
# TODO with patch.object(timezone, 'now', return_value=now+relativedelta(years=1)):
|
||||||
|
delta = datetime.timedelta(days=60)
|
||||||
|
date = (timezone.now()-delta).date()
|
||||||
|
order = service.orders.get()
|
||||||
|
order.registered_on = date
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
metric = order.metrics.latest()
|
||||||
|
metric.updated_on -= delta
|
||||||
|
metric.save()
|
||||||
|
|
||||||
|
bills = service.orders.bill(proforma=True)
|
||||||
|
self.assertEqual(0, bills[0].get_total())
|
||||||
|
|
||||||
|
self.report_traffic(account, date, 10**10*9)
|
||||||
|
metric = order.metrics.latest()
|
||||||
|
metric.updated_on -= delta
|
||||||
|
metric.save()
|
||||||
|
|
||||||
|
bills = service.orders.bill(proforma=True)
|
||||||
|
self.assertEqual((90-10-10)*10, bills[0].get_total())
|
||||||
|
|
||||||
|
|
||||||
class MailboxBillingTest(BaseBillingTest):
|
class MailboxBillingTest(BaseBillingTest):
|
||||||
|
@ -403,7 +469,7 @@ class MailboxBillingTest(BaseBillingTest):
|
||||||
self.allocate_disk(mailbox, 10)
|
self.allocate_disk(mailbox, 10)
|
||||||
bill = service.orders.bill()[0]
|
bill = service.orders.bill()[0]
|
||||||
self.assertEqual(0, bill.get_total())
|
self.assertEqual(0, bill.get_total())
|
||||||
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
|
bp = timezone.now().date() + relativedelta(years=1)
|
||||||
bill = disk_service.orders.bill(billing_point=bp, fixed_point=True)[0]
|
bill = disk_service.orders.bill(billing_point=bp, fixed_point=True)[0]
|
||||||
self.assertEqual(90, bill.get_total())
|
self.assertEqual(90, bill.get_total())
|
||||||
mailbox = self.create_mailbox(account=account)
|
mailbox = self.create_mailbox(account=account)
|
||||||
|
@ -421,38 +487,30 @@ class MailboxBillingTest(BaseBillingTest):
|
||||||
account = self.create_account()
|
account = self.create_account()
|
||||||
mailbox = self.create_mailbox(account=account)
|
mailbox = self.create_mailbox(account=account)
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
bp = now.date() + relativedelta.relativedelta(years=1)
|
bp = now.date() + relativedelta(years=1)
|
||||||
|
options = dict(billing_point=bp, fixed_point=True, proforma=True, new_open=True)
|
||||||
|
|
||||||
self.allocate_disk(mailbox, 10)
|
self.allocate_disk(mailbox, 10)
|
||||||
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
|
bill = service.orders.bill(**options).pop()
|
||||||
self.assertEqual(9*10, bill.get_total())
|
self.assertEqual(9*10, bill.get_total())
|
||||||
|
|
||||||
|
with freeze_time(now+relativedelta(months=6)):
|
||||||
self.allocate_disk(mailbox, 20)
|
self.allocate_disk(mailbox, 20)
|
||||||
created_on = now+relativedelta.relativedelta(months=6)
|
bill = service.orders.bill(**options).pop()
|
||||||
order = service.orders.get()
|
total = 9*10*0.5 + 19*10*0.5
|
||||||
metric = order.metrics.latest('id')
|
self.assertEqual(total, bill.get_total())
|
||||||
metric.created_on = created_on
|
|
||||||
metric.save()
|
|
||||||
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
|
|
||||||
self.assertEqual(9*10*0.5 + 19*10*0.5, bill.get_total())
|
|
||||||
|
|
||||||
|
with freeze_time(now+relativedelta(months=9)):
|
||||||
self.allocate_disk(mailbox, 30)
|
self.allocate_disk(mailbox, 30)
|
||||||
created_on = now+relativedelta.relativedelta(months=9)
|
bill = service.orders.bill(**options).pop()
|
||||||
order = service.orders.get()
|
total = 9*10*0.5 + 19*10*0.25 + 29*10*0.25
|
||||||
metric = order.metrics.latest('id')
|
self.assertEqual(total, bill.get_total())
|
||||||
metric.created_on = created_on
|
|
||||||
metric.save()
|
|
||||||
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
|
|
||||||
self.assertEqual(9*10*0.5 + 19*10*0.25 + 29*10*0.25, bill.get_total())
|
|
||||||
|
|
||||||
|
with freeze_time(now+relativedelta(years=1)):
|
||||||
self.allocate_disk(mailbox, 10)
|
self.allocate_disk(mailbox, 10)
|
||||||
created_on = now+relativedelta.relativedelta(years=1)
|
bill = service.orders.bill(**options).pop()
|
||||||
order = service.orders.get()
|
total = 9*10*0.5 + 19*10*0.25 + 29*10*0.25
|
||||||
metric = order.metrics.latest('id')
|
self.assertEqual(total, bill.get_total())
|
||||||
metric.created_on = created_on
|
|
||||||
metric.save()
|
|
||||||
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
|
|
||||||
self.assertEqual(9*10*0.5 + 19*10*0.25 + 29*10*0.25, bill.get_total())
|
|
||||||
|
|
||||||
|
|
||||||
class JobBillingTest(BaseBillingTest):
|
class JobBillingTest(BaseBillingTest):
|
||||||
|
@ -480,9 +538,9 @@ class JobBillingTest(BaseBillingTest):
|
||||||
def create_job(self, amount, account=None):
|
def create_job(self, amount, account=None):
|
||||||
if not account:
|
if not account:
|
||||||
account = self.create_account()
|
account = self.create_account()
|
||||||
job_name = '%s.es' % random_ascii(10)
|
description = 'Random Job %s' % random_ascii(10)
|
||||||
job_service, __ = MiscService.objects.get_or_create(name='job', description='Random job', has_amount=True)
|
service, __ = MiscService.objects.get_or_create(name='job', description=description, has_amount=True)
|
||||||
return Miscellaneous.objects.create(service=job_service, description=job_name, account=account, amount=amount)
|
return Miscellaneous.objects.create(service=service, description=description, account=account, amount=amount)
|
||||||
|
|
||||||
def test_job(self):
|
def test_job(self):
|
||||||
service = self.create_job_service()
|
service = self.create_job_service()
|
||||||
|
@ -499,7 +557,22 @@ class JobBillingTest(BaseBillingTest):
|
||||||
|
|
||||||
class PlanBillingTest(BaseBillingTest):
|
class PlanBillingTest(BaseBillingTest):
|
||||||
def create_plan_service(self):
|
def create_plan_service(self):
|
||||||
pass
|
service = Service.objects.create(
|
||||||
|
description="Association membership fee",
|
||||||
|
content_type=ContentType.objects.get_for_model(Miscellaneous),
|
||||||
|
match="account.is_active and account.type == 'ASSOCIATION'",
|
||||||
|
billing_period=Service.ANUAL,
|
||||||
|
billing_point=Service.FIXED_DATE,
|
||||||
|
is_fee=True,
|
||||||
|
metric='',
|
||||||
|
pricing_period=Service.BILLING_PERIOD,
|
||||||
|
rate_algorithm=Service.STEP_PRICE,
|
||||||
|
on_cancel=Service.DISCOUNT,
|
||||||
|
payment_style=Service.PREPAY,
|
||||||
|
tax=0,
|
||||||
|
nominal_price=20
|
||||||
|
)
|
||||||
|
return service
|
||||||
|
|
||||||
def create_plan(self):
|
def create_plan(self):
|
||||||
if not account:
|
if not account:
|
||||||
|
|
|
@ -161,7 +161,7 @@ class MonitorData(models.Model):
|
||||||
content_object = GenericForeignKey()
|
content_object = GenericForeignKey()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = 'date'
|
get_latest_by = 'id'
|
||||||
verbose_name_plural = _("monitor data")
|
verbose_name_plural = _("monitor data")
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
|
|
|
@ -288,7 +288,9 @@ class ServiceHandler(plugins.Plugin):
|
||||||
dsize, new_end = self.apply_compensations(order, only_beyond=True)
|
dsize, new_end = self.apply_compensations(order, only_beyond=True)
|
||||||
cprice += dsize*price
|
cprice += dsize*price
|
||||||
if cprice:
|
if cprice:
|
||||||
discounts = (('compensation', -cprice),)
|
discounts = (
|
||||||
|
('compensation', -cprice),
|
||||||
|
)
|
||||||
if new_end:
|
if new_end:
|
||||||
size = self.get_price_size(order.new_billed_until, new_end)
|
size = self.get_price_size(order.new_billed_until, new_end)
|
||||||
price += price*size
|
price += price*size
|
||||||
|
@ -386,7 +388,9 @@ class ServiceHandler(plugins.Plugin):
|
||||||
discounts = ()
|
discounts = ()
|
||||||
dsize, new_end = self.apply_compensations(order)
|
dsize, new_end = self.apply_compensations(order)
|
||||||
if dsize:
|
if dsize:
|
||||||
discounts=(('compensation', -dsize*price),)
|
discounts=(
|
||||||
|
('compensation', -dsize*price),
|
||||||
|
)
|
||||||
if new_end:
|
if new_end:
|
||||||
order.new_billed_until = new_end
|
order.new_billed_until = new_end
|
||||||
end = new_end
|
end = new_end
|
||||||
|
|
|
@ -366,3 +366,6 @@ class HandlerTests(BaseTestCase):
|
||||||
lines = service.handler.generate_bill_lines(orders, account, commit=False)
|
lines = service.handler.generate_bill_lines(orders, account, commit=False)
|
||||||
print lines
|
print lines
|
||||||
print len(lines)
|
print len(lines)
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# TODO test incomplete rate 1 -> nominal_price 10 -> rate
|
||||||
|
|
|
@ -13,7 +13,9 @@ from .. import settings
|
||||||
|
|
||||||
class Apache2Backend(ServiceController):
|
class Apache2Backend(ServiceController):
|
||||||
model = 'websites.Website'
|
model = 'websites.Website'
|
||||||
related_models = (('websites.Content', 'website'),)
|
related_models = (
|
||||||
|
('websites.Content', 'website'),
|
||||||
|
)
|
||||||
verbose_name = _("Apache 2")
|
verbose_name = _("Apache 2")
|
||||||
|
|
||||||
def save(self, site):
|
def save(self, site):
|
||||||
|
|
|
@ -157,7 +157,8 @@ function install_requirements () {
|
||||||
iceweasel"
|
iceweasel"
|
||||||
PIP="${PIP} \
|
PIP="${PIP} \
|
||||||
selenium \
|
selenium \
|
||||||
xvfbwrapper"
|
xvfbwrapper \
|
||||||
|
freezegun"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure locales are in place before installing postgres
|
# Make sure locales are in place before installing postgres
|
||||||
|
@ -253,6 +254,7 @@ function print_install_certificate_help () {
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function install_certificate () {
|
function install_certificate () {
|
||||||
opts=$(getopt -o h -l help -- "$@") || exit 1
|
opts=$(getopt -o h -l help -- "$@") || exit 1
|
||||||
set -- $opts
|
set -- $opts
|
||||||
|
@ -311,7 +313,6 @@ function uninstall_certificate () {
|
||||||
export -f uninstall_certificate
|
export -f uninstall_certificate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function print_install_postfix_help () {
|
function print_install_postfix_help () {
|
||||||
cat <<- EOF
|
cat <<- EOF
|
||||||
|
|
||||||
|
@ -364,6 +365,7 @@ function install_postfix () {
|
||||||
}
|
}
|
||||||
export -f install_postfix
|
export -f install_postfix
|
||||||
|
|
||||||
|
|
||||||
function print_uninstall_postfix_help () {
|
function print_uninstall_postfix_help () {
|
||||||
cat <<- EOF
|
cat <<- EOF
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue