uncloud pay cleanups
Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
parent
c9be8cc50b
commit
9bf0a99f6a
5 changed files with 324 additions and 239 deletions
|
@ -14,7 +14,8 @@ from uncloud_pay.models import Bill, Order, BillRecord, BillingAddress
|
||||||
|
|
||||||
|
|
||||||
class BillRecordInline(admin.TabularInline):
|
class BillRecordInline(admin.TabularInline):
|
||||||
model = Bill.bill_records.through
|
# model = Bill.bill_records.through
|
||||||
|
model = BillRecord
|
||||||
|
|
||||||
# AT some point in the future: expose REPLACED and orders that depend on us
|
# AT some point in the future: expose REPLACED and orders that depend on us
|
||||||
# class OrderInline(admin.TabularInline):
|
# class OrderInline(admin.TabularInline):
|
||||||
|
@ -29,6 +30,10 @@ class BillAdmin(admin.ModelAdmin):
|
||||||
# change_list_template = "uncloud_pay/change_list.html"
|
# change_list_template = "uncloud_pay/change_list.html"
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
|
"""
|
||||||
|
Create URLs for PDF view
|
||||||
|
"""
|
||||||
|
|
||||||
info = "%s_%s" % (self.model._meta.app_label, self.model._meta.model_name)
|
info = "%s_%s" % (self.model._meta.app_label, self.model._meta.model_name)
|
||||||
pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__))
|
pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__))
|
||||||
|
|
||||||
|
@ -77,7 +82,9 @@ class BillAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Bill, BillAdmin)
|
admin.site.register(Bill, BillAdmin)
|
||||||
#admin.site.register(Order, OrderAdmin)
|
|
||||||
admin.site.register(Order)
|
admin.site.register(Order)
|
||||||
admin.site.register(BillRecord)
|
admin.site.register(BillRecord)
|
||||||
admin.site.register(BillingAddress)
|
admin.site.register(BillingAddress)
|
||||||
|
|
||||||
|
|
||||||
|
#admin.site.register(Order, OrderAdmin)
|
||||||
|
|
17
uncloud_pay/migrations/0006_remove_billrecord_quantity.py
Normal file
17
uncloud_pay/migrations/0006_remove_billrecord_quantity.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 3.1 on 2020-08-08 19:57
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_pay', '0005_auto_20200808_1954'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='billrecord',
|
||||||
|
name='quantity',
|
||||||
|
),
|
||||||
|
]
|
17
uncloud_pay/migrations/0007_remove_bill_bill_records.py
Normal file
17
uncloud_pay/migrations/0007_remove_bill_bill_records.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 3.1 on 2020-08-08 20:20
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_pay', '0006_remove_billrecord_quantity'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='bill',
|
||||||
|
name='bill_records',
|
||||||
|
),
|
||||||
|
]
|
|
@ -340,6 +340,10 @@ class Order(models.Model):
|
||||||
def is_recurring(self):
|
def is_recurring(self):
|
||||||
return not self.recurring_period == RecurringPeriod.ONE_TIME
|
return not self.recurring_period == RecurringPeriod.ONE_TIME
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_one_time(self):
|
||||||
|
return not self.is_recurring
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_terminated(self):
|
def is_terminated(self):
|
||||||
return self.ending_date != None and self.ending_date < timezone.now()
|
return self.ending_date != None and self.ending_date < timezone.now()
|
||||||
|
@ -382,10 +386,6 @@ class Bill(models.Model):
|
||||||
# what is valid for? should this be "final"?
|
# what is valid for? should this be "final"?
|
||||||
valid = models.BooleanField(default=True)
|
valid = models.BooleanField(default=True)
|
||||||
|
|
||||||
# Mapping to BillRecords
|
|
||||||
# https://stackoverflow.com/questions/4443190/djangos-manytomany-relationship-with-additional-fields
|
|
||||||
bill_records = models.ManyToManyField(Order, through="BillRecord")
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(fields=['owner',
|
models.UniqueConstraint(fields=['owner',
|
||||||
|
@ -399,13 +399,14 @@ class Bill(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum(self):
|
def sum(self):
|
||||||
pass
|
return 0
|
||||||
|
# for self.billrecord_set.
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_next_bill_for_user(cls, user):
|
def create_next_bill_for_user(cls, owner):
|
||||||
last_bill = cls.objects.filter(owner=user).order_by('id').last()
|
last_bill = cls.objects.filter(owner=owner).order_by('id').last()
|
||||||
all_orders = Order.objects.filter(owner=user).order_by('id')
|
all_orders = Order.objects.filter(owner=owner).order_by('id')
|
||||||
first_order = all_orders.first()
|
first_order = all_orders.first()
|
||||||
|
|
||||||
|
|
||||||
|
@ -420,16 +421,21 @@ class Bill(models.Model):
|
||||||
|
|
||||||
ending_date = end_of_month(starting_date)
|
ending_date = end_of_month(starting_date)
|
||||||
|
|
||||||
bill = cls()
|
bill, created = cls.objects.get_or_create(
|
||||||
|
owner=owner,
|
||||||
|
starting_date=starting_date,
|
||||||
|
ending_date=ending_date)
|
||||||
|
|
||||||
for order in all_orders:
|
for order in all_orders:
|
||||||
# check if order needs to be billed
|
# check if order needs to be billed
|
||||||
# check if order has previous billing record
|
# check if order has previous billing record
|
||||||
|
|
||||||
# one time orders
|
if order.is_one_time:
|
||||||
if not order.is_recurring:
|
if order.billrecord_set.count() == 0:
|
||||||
pass
|
br = BillRecord.objects.create(bill=bill,
|
||||||
|
order=order,
|
||||||
|
starting_date=starting_date,
|
||||||
|
ending_date=ending_date)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return bill
|
return bill
|
||||||
|
@ -515,20 +521,13 @@ class BillRecord(models.Model):
|
||||||
bill = models.ForeignKey(Bill, on_delete=models.CASCADE)
|
bill = models.ForeignKey(Bill, on_delete=models.CASCADE)
|
||||||
order = models.ForeignKey(Order, on_delete=models.CASCADE)
|
order = models.ForeignKey(Order, on_delete=models.CASCADE)
|
||||||
|
|
||||||
# How many times the order has been used in this record
|
|
||||||
quantity = models.DecimalField(max_digits=19, decimal_places=10)
|
|
||||||
|
|
||||||
# quantity can actually be derived from starting/ending date
|
|
||||||
|
|
||||||
# The timeframe the bill record is for can (and probably often will) differ
|
|
||||||
# from the bill time
|
|
||||||
|
|
||||||
creation_date = models.DateTimeField(auto_now_add=True)
|
creation_date = models.DateTimeField(auto_now_add=True)
|
||||||
starting_date = models.DateTimeField()
|
starting_date = models.DateTimeField()
|
||||||
ending_date = models.DateTimeField()
|
ending_date = models.DateTimeField()
|
||||||
|
|
||||||
def quantity2(self):
|
def quantity(self):
|
||||||
if self.order.recurring_period == RecurringPeriod.ONE_TIME:
|
""" Determine the quantity by the duration"""
|
||||||
|
if self.order.is_recurring:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
record_delta = self.ending_date - self.starting_date
|
record_delta = self.ending_date - self.starting_date
|
||||||
|
@ -537,10 +536,7 @@ class BillRecord(models.Model):
|
||||||
|
|
||||||
|
|
||||||
def sum(self):
|
def sum(self):
|
||||||
if self.order.recurring_period == RecurringPeriod.ONE_TIME:
|
return self.order.price * self.quantity
|
||||||
return 1
|
|
||||||
|
|
||||||
return self.quantity * 1
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.bill}: {self.quantity} x {self.order}"
|
return f"{self.bill}: {self.quantity} x {self.order}"
|
||||||
|
|
|
@ -5,131 +5,6 @@ from datetime import datetime, date, timedelta
|
||||||
from .models import *
|
from .models import *
|
||||||
from uncloud_service.models import GenericServiceProduct
|
from uncloud_service.models import GenericServiceProduct
|
||||||
|
|
||||||
class NotABillingTC(TestCase):
|
|
||||||
#class BillingTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.user = get_user_model().objects.create(
|
|
||||||
username='jdoe',
|
|
||||||
email='john.doe@domain.tld')
|
|
||||||
self.billing_address = BillingAddress.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
street="unknown",
|
|
||||||
city="unknown",
|
|
||||||
postal_code="unknown")
|
|
||||||
|
|
||||||
def test_basic_monthly_billing(self):
|
|
||||||
one_time_price = 10
|
|
||||||
recurring_price = 20
|
|
||||||
description = "Test Product 1"
|
|
||||||
|
|
||||||
# Three months: full, full, partial.
|
|
||||||
# starting_date = datetime.fromisoformat('2020-03-01')
|
|
||||||
starting_date = datetime(2020,3,1)
|
|
||||||
ending_date = datetime(2020,5,8)
|
|
||||||
|
|
||||||
# Create order to be billed.
|
|
||||||
order = Order.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
starting_date=starting_date,
|
|
||||||
ending_date=ending_date,
|
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
|
||||||
recurring_price=recurring_price,
|
|
||||||
one_time_price=one_time_price,
|
|
||||||
description=description,
|
|
||||||
billing_address=self.billing_address)
|
|
||||||
|
|
||||||
# Generate & check bill for first month: full recurring_price + setup.
|
|
||||||
first_month_bills = order.generate_initial_bill()
|
|
||||||
self.assertEqual(len(first_month_bills), 1)
|
|
||||||
self.assertEqual(first_month_bills[0].amount, one_time_price + recurring_price)
|
|
||||||
|
|
||||||
# Generate & check bill for second month: full recurring_price.
|
|
||||||
second_month_bills = Bill.generate_for(2020, 4, self.user)
|
|
||||||
self.assertEqual(len(second_month_bills), 1)
|
|
||||||
self.assertEqual(second_month_bills[0].amount, recurring_price)
|
|
||||||
|
|
||||||
# Generate & check bill for third and last month: partial recurring_price.
|
|
||||||
third_month_bills = Bill.generate_for(2020, 5, self.user)
|
|
||||||
self.assertEqual(len(third_month_bills), 1)
|
|
||||||
# 31 days in May.
|
|
||||||
self.assertEqual(float(third_month_bills[0].amount),
|
|
||||||
round(round((7/31), AMOUNT_DECIMALS) * recurring_price, AMOUNT_DECIMALS))
|
|
||||||
|
|
||||||
# Check that running Bill.generate_for() twice does not create duplicates.
|
|
||||||
self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0)
|
|
||||||
|
|
||||||
def test_basic_yearly_billing(self):
|
|
||||||
one_time_price = 10
|
|
||||||
recurring_price = 150
|
|
||||||
description = "Test Product 1"
|
|
||||||
|
|
||||||
starting_date = datetime.fromisoformat('2020-03-31T08:05:23')
|
|
||||||
|
|
||||||
# Create order to be billed.
|
|
||||||
order = Order.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
starting_date=starting_date,
|
|
||||||
recurring_period=RecurringPeriod.PER_365D,
|
|
||||||
recurring_price=recurring_price,
|
|
||||||
one_time_price=one_time_price,
|
|
||||||
description=description,
|
|
||||||
billing_address=self.billing_address)
|
|
||||||
|
|
||||||
# Generate & check bill for first year: recurring_price + setup.
|
|
||||||
first_year_bills = order.generate_initial_bill()
|
|
||||||
self.assertEqual(len(first_year_bills), 1)
|
|
||||||
self.assertEqual(first_year_bills[0].starting_date.date(),
|
|
||||||
date.fromisoformat('2020-03-31'))
|
|
||||||
self.assertEqual(first_year_bills[0].ending_date.date(),
|
|
||||||
date.fromisoformat('2021-03-30'))
|
|
||||||
self.assertEqual(first_year_bills[0].amount,
|
|
||||||
recurring_price + one_time_price)
|
|
||||||
|
|
||||||
# Generate & check bill for second year: recurring_price.
|
|
||||||
second_year_bills = Bill.generate_for(2021, 3, self.user)
|
|
||||||
self.assertEqual(len(second_year_bills), 1)
|
|
||||||
self.assertEqual(second_year_bills[0].starting_date.date(),
|
|
||||||
date.fromisoformat('2021-03-31'))
|
|
||||||
self.assertEqual(second_year_bills[0].ending_date.date(),
|
|
||||||
date.fromisoformat('2022-03-30'))
|
|
||||||
self.assertEqual(second_year_bills[0].amount, recurring_price)
|
|
||||||
|
|
||||||
# Check that running Bill.generate_for() twice does not create duplicates.
|
|
||||||
self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0)
|
|
||||||
self.assertEqual(len(Bill.generate_for(2020, 4, self.user)), 0)
|
|
||||||
self.assertEqual(len(Bill.generate_for(2020, 2, self.user)), 0)
|
|
||||||
self.assertEqual(len(Bill.generate_for(2021, 3, self.user)), 0)
|
|
||||||
|
|
||||||
def test_basic_hourly_billing(self):
|
|
||||||
one_time_price = 10
|
|
||||||
recurring_price = 1.4
|
|
||||||
description = "Test Product 1"
|
|
||||||
|
|
||||||
starting_date = datetime.fromisoformat('2020-03-31T08:05:23')
|
|
||||||
ending_date = datetime.fromisoformat('2020-04-01T11:13:32')
|
|
||||||
|
|
||||||
# Create order to be billed.
|
|
||||||
order = Order.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
starting_date=starting_date,
|
|
||||||
ending_date=ending_date,
|
|
||||||
recurring_period=RecurringPeriod.PER_HOUR,
|
|
||||||
recurring_price=recurring_price,
|
|
||||||
one_time_price=one_time_price,
|
|
||||||
description=description,
|
|
||||||
billing_address=self.billing_address)
|
|
||||||
|
|
||||||
# Generate & check bill for first month: recurring_price + setup.
|
|
||||||
first_month_bills = order.generate_initial_bill()
|
|
||||||
self.assertEqual(len(first_month_bills), 1)
|
|
||||||
self.assertEqual(float(first_month_bills[0].amount),
|
|
||||||
round(16 * recurring_price, AMOUNT_DECIMALS) + one_time_price)
|
|
||||||
|
|
||||||
# Generate & check bill for first month: recurring_price.
|
|
||||||
second_month_bills = Bill.generate_for(2020, 4, self.user)
|
|
||||||
self.assertEqual(len(second_month_bills), 1)
|
|
||||||
self.assertEqual(float(second_month_bills[0].amount),
|
|
||||||
round(12 * recurring_price, AMOUNT_DECIMALS))
|
|
||||||
|
|
||||||
class ProductActivationTestCase(TestCase):
|
class ProductActivationTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -139,102 +14,275 @@ class ProductActivationTestCase(TestCase):
|
||||||
|
|
||||||
self.billing_address = BillingAddress.objects.create(
|
self.billing_address = BillingAddress.objects.create(
|
||||||
owner=self.user,
|
owner=self.user,
|
||||||
|
organization = 'Test org',
|
||||||
street="unknown",
|
street="unknown",
|
||||||
city="unknown",
|
city="unknown",
|
||||||
postal_code="unknown")
|
postal_code="unknown")
|
||||||
|
|
||||||
def test_product_activation(self):
|
self.order_meta = {}
|
||||||
starting_date = datetime.fromisoformat('2020-03-01')
|
self.order_meta[1] = {
|
||||||
one_time_price = 0
|
'starting_date': timezone.make_aware(datetime.datetime(2020,3,3)),
|
||||||
recurring_price = 1
|
'ending_date': timezone.make_aware(datetime.datetime(2020,4,17)),
|
||||||
description = "Test Product"
|
'price': 15,
|
||||||
|
'description': 'One chocolate bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_bill_one_time_order(self):
|
||||||
|
one_time_price = 10
|
||||||
|
recurring_price = 150
|
||||||
|
description = "Test Product 1"
|
||||||
|
|
||||||
|
|
||||||
order = Order.objects.create(
|
order = Order.objects.create(
|
||||||
owner=self.user,
|
owner=self.user,
|
||||||
starting_date=starting_date,
|
starting_date=self.order_meta[1]['starting_date'],
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
ending_date=self.order_meta[1]['ending_date'],
|
||||||
recurring_price=recurring_price,
|
recurring_period=RecurringPeriod.ONE_TIME,
|
||||||
one_time_price=one_time_price,
|
price=self.order_meta[1]['price'],
|
||||||
description=description,
|
description=self.order_meta[1]['description'],
|
||||||
billing_address=self.billing_address)
|
billing_address=self.billing_address)
|
||||||
|
|
||||||
product = GenericServiceProduct(
|
|
||||||
custom_description=description,
|
|
||||||
custom_one_time_price=one_time_price,
|
|
||||||
custom_recurring_price=recurring_price,
|
|
||||||
owner=self.user,
|
|
||||||
order=order)
|
|
||||||
product.save()
|
|
||||||
|
|
||||||
# Validate initial state: must be awaiting payment.
|
bill = Bill.create_next_bill_for_user(self.user)
|
||||||
self.assertEqual(product.status, UncloudStatus.AWAITING_PAYMENT)
|
|
||||||
|
|
||||||
# Pay initial bill, check that product is activated.
|
self.assertEqual(order.billrecord_set.count(), 1)
|
||||||
order.generate_initial_bill()
|
|
||||||
amount = product.order.bills[0].amount
|
|
||||||
payment = Payment(owner=self.user, amount=amount)
|
|
||||||
payment.save()
|
|
||||||
self.assertEqual(
|
|
||||||
GenericServiceProduct.objects.get(uuid=product.uuid).status,
|
|
||||||
UncloudStatus.PENDING
|
|
||||||
)
|
|
||||||
|
|
||||||
class BillingAddressTestCase(TestCase):
|
self.assertEqual(bill.sum, self.order_meta[1]['price'])
|
||||||
def setUp(self):
|
|
||||||
self.user = get_user_model().objects.create(
|
|
||||||
username='jdoe',
|
|
||||||
email='john.doe@domain.tld')
|
|
||||||
|
|
||||||
self.billing_address_01 = BillingAddress.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
street="unknown1",
|
|
||||||
city="unknown1",
|
|
||||||
postal_code="unknown1",
|
|
||||||
country="CH")
|
|
||||||
|
|
||||||
self.billing_address_02 = BillingAddress.objects.create(
|
|
||||||
owner=self.user,
|
|
||||||
street="unknown2",
|
|
||||||
city="unknown2",
|
|
||||||
postal_code="unknown2",
|
|
||||||
country="CH")
|
|
||||||
|
|
||||||
def test_billing_with_single_address(self):
|
|
||||||
# Create new orders somewhere in the past so that we do not encounter
|
|
||||||
# auto-created initial bills.
|
|
||||||
starting_date = datetime.fromisoformat('2020-03-01')
|
|
||||||
|
|
||||||
order_01 = Order.objects.create(
|
# class NotABillingTC(TestCase):
|
||||||
owner=self.user,
|
# #class BillingTestCase(TestCase):
|
||||||
starting_date=starting_date,
|
# def setUp(self):
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
# self.user = get_user_model().objects.create(
|
||||||
billing_address=self.billing_address_01)
|
# username='jdoe',
|
||||||
order_02 = Order.objects.create(
|
# email='john.doe@domain.tld')
|
||||||
owner=self.user,
|
# self.billing_address = BillingAddress.objects.create(
|
||||||
starting_date=starting_date,
|
# owner=self.user,
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
# street="unknown",
|
||||||
billing_address=self.billing_address_01)
|
# city="unknown",
|
||||||
|
# postal_code="unknown")
|
||||||
|
|
||||||
# We need a single bill since we work with a single address.
|
# def test_basic_monthly_billing(self):
|
||||||
bills = Bill.generate_for(2020, 4, self.user)
|
# one_time_price = 10
|
||||||
self.assertEqual(len(bills), 1)
|
# recurring_price = 20
|
||||||
|
# description = "Test Product 1"
|
||||||
|
|
||||||
def test_billing_with_multiple_addresses(self):
|
# # Three months: full, full, partial.
|
||||||
# Create new orders somewhere in the past so that we do not encounter
|
# # starting_date = datetime.fromisoformat('2020-03-01')
|
||||||
# auto-created initial bills.
|
# starting_date = datetime(2020,3,1)
|
||||||
starting_date = datetime.fromisoformat('2020-03-01')
|
# ending_date = datetime(2020,5,8)
|
||||||
|
|
||||||
order_01 = Order.objects.create(
|
# # Create order to be billed.
|
||||||
owner=self.user,
|
# order = Order.objects.create(
|
||||||
starting_date=starting_date,
|
# owner=self.user,
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
# starting_date=starting_date,
|
||||||
billing_address=self.billing_address_01)
|
# ending_date=ending_date,
|
||||||
order_02 = Order.objects.create(
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
owner=self.user,
|
# recurring_price=recurring_price,
|
||||||
starting_date=starting_date,
|
# one_time_price=one_time_price,
|
||||||
recurring_period=RecurringPeriod.PER_30D,
|
# description=description,
|
||||||
billing_address=self.billing_address_02)
|
# billing_address=self.billing_address)
|
||||||
|
|
||||||
# We need different bills since we work with different addresses.
|
# # Generate & check bill for first month: full recurring_price + setup.
|
||||||
bills = Bill.generate_for(2020, 4, self.user)
|
# first_month_bills = order.generate_initial_bill()
|
||||||
self.assertEqual(len(bills), 2)
|
# self.assertEqual(len(first_month_bills), 1)
|
||||||
|
# self.assertEqual(first_month_bills[0].amount, one_time_price + recurring_price)
|
||||||
|
|
||||||
|
# # Generate & check bill for second month: full recurring_price.
|
||||||
|
# second_month_bills = Bill.generate_for(2020, 4, self.user)
|
||||||
|
# self.assertEqual(len(second_month_bills), 1)
|
||||||
|
# self.assertEqual(second_month_bills[0].amount, recurring_price)
|
||||||
|
|
||||||
|
# # Generate & check bill for third and last month: partial recurring_price.
|
||||||
|
# third_month_bills = Bill.generate_for(2020, 5, self.user)
|
||||||
|
# self.assertEqual(len(third_month_bills), 1)
|
||||||
|
# # 31 days in May.
|
||||||
|
# self.assertEqual(float(third_month_bills[0].amount),
|
||||||
|
# round(round((7/31), AMOUNT_DECIMALS) * recurring_price, AMOUNT_DECIMALS))
|
||||||
|
|
||||||
|
# # Check that running Bill.generate_for() twice does not create duplicates.
|
||||||
|
# self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0)
|
||||||
|
|
||||||
|
# def test_basic_yearly_billing(self):
|
||||||
|
# one_time_price = 10
|
||||||
|
# recurring_price = 150
|
||||||
|
# description = "Test Product 1"
|
||||||
|
|
||||||
|
# starting_date = datetime.fromisoformat('2020-03-31T08:05:23')
|
||||||
|
|
||||||
|
# # Create order to be billed.
|
||||||
|
# order = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_365D,
|
||||||
|
# recurring_price=recurring_price,
|
||||||
|
# one_time_price=one_time_price,
|
||||||
|
# description=description,
|
||||||
|
# billing_address=self.billing_address)
|
||||||
|
|
||||||
|
# # Generate & check bill for first year: recurring_price + setup.
|
||||||
|
# first_year_bills = order.generate_initial_bill()
|
||||||
|
# self.assertEqual(len(first_year_bills), 1)
|
||||||
|
# self.assertEqual(first_year_bills[0].starting_date.date(),
|
||||||
|
# date.fromisoformat('2020-03-31'))
|
||||||
|
# self.assertEqual(first_year_bills[0].ending_date.date(),
|
||||||
|
# date.fromisoformat('2021-03-30'))
|
||||||
|
# self.assertEqual(first_year_bills[0].amount,
|
||||||
|
# recurring_price + one_time_price)
|
||||||
|
|
||||||
|
# # Generate & check bill for second year: recurring_price.
|
||||||
|
# second_year_bills = Bill.generate_for(2021, 3, self.user)
|
||||||
|
# self.assertEqual(len(second_year_bills), 1)
|
||||||
|
# self.assertEqual(second_year_bills[0].starting_date.date(),
|
||||||
|
# date.fromisoformat('2021-03-31'))
|
||||||
|
# self.assertEqual(second_year_bills[0].ending_date.date(),
|
||||||
|
# date.fromisoformat('2022-03-30'))
|
||||||
|
# self.assertEqual(second_year_bills[0].amount, recurring_price)
|
||||||
|
|
||||||
|
# # Check that running Bill.generate_for() twice does not create duplicates.
|
||||||
|
# self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0)
|
||||||
|
# self.assertEqual(len(Bill.generate_for(2020, 4, self.user)), 0)
|
||||||
|
# self.assertEqual(len(Bill.generate_for(2020, 2, self.user)), 0)
|
||||||
|
# self.assertEqual(len(Bill.generate_for(2021, 3, self.user)), 0)
|
||||||
|
|
||||||
|
# def test_basic_hourly_billing(self):
|
||||||
|
# one_time_price = 10
|
||||||
|
# recurring_price = 1.4
|
||||||
|
# description = "Test Product 1"
|
||||||
|
|
||||||
|
# starting_date = datetime.fromisoformat('2020-03-31T08:05:23')
|
||||||
|
# ending_date = datetime.fromisoformat('2020-04-01T11:13:32')
|
||||||
|
|
||||||
|
# # Create order to be billed.
|
||||||
|
# order = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# ending_date=ending_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_HOUR,
|
||||||
|
# recurring_price=recurring_price,
|
||||||
|
# one_time_price=one_time_price,
|
||||||
|
# description=description,
|
||||||
|
# billing_address=self.billing_address)
|
||||||
|
|
||||||
|
# # Generate & check bill for first month: recurring_price + setup.
|
||||||
|
# first_month_bills = order.generate_initial_bill()
|
||||||
|
# self.assertEqual(len(first_month_bills), 1)
|
||||||
|
# self.assertEqual(float(first_month_bills[0].amount),
|
||||||
|
# round(16 * recurring_price, AMOUNT_DECIMALS) + one_time_price)
|
||||||
|
|
||||||
|
# # Generate & check bill for first month: recurring_price.
|
||||||
|
# second_month_bills = Bill.generate_for(2020, 4, self.user)
|
||||||
|
# self.assertEqual(len(second_month_bills), 1)
|
||||||
|
# self.assertEqual(float(second_month_bills[0].amount),
|
||||||
|
# round(12 * recurring_price, AMOUNT_DECIMALS))
|
||||||
|
|
||||||
|
# class ProductActivationTestCase(TestCase):
|
||||||
|
# def setUp(self):
|
||||||
|
# self.user = get_user_model().objects.create(
|
||||||
|
# username='jdoe',
|
||||||
|
# email='john.doe@domain.tld')
|
||||||
|
|
||||||
|
# self.billing_address = BillingAddress.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# street="unknown",
|
||||||
|
# city="unknown",
|
||||||
|
# postal_code="unknown")
|
||||||
|
|
||||||
|
# def test_product_activation(self):
|
||||||
|
# starting_date = datetime.fromisoformat('2020-03-01')
|
||||||
|
# one_time_price = 0
|
||||||
|
# recurring_price = 1
|
||||||
|
# description = "Test Product"
|
||||||
|
|
||||||
|
# order = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
|
# recurring_price=recurring_price,
|
||||||
|
# one_time_price=one_time_price,
|
||||||
|
# description=description,
|
||||||
|
# billing_address=self.billing_address)
|
||||||
|
|
||||||
|
# product = GenericServiceProduct(
|
||||||
|
# custom_description=description,
|
||||||
|
# custom_one_time_price=one_time_price,
|
||||||
|
# custom_recurring_price=recurring_price,
|
||||||
|
# owner=self.user,
|
||||||
|
# order=order)
|
||||||
|
# product.save()
|
||||||
|
|
||||||
|
# # Validate initial state: must be awaiting payment.
|
||||||
|
# self.assertEqual(product.status, UncloudStatus.AWAITING_PAYMENT)
|
||||||
|
|
||||||
|
# # Pay initial bill, check that product is activated.
|
||||||
|
# order.generate_initial_bill()
|
||||||
|
# amount = product.order.bills[0].amount
|
||||||
|
# payment = Payment(owner=self.user, amount=amount)
|
||||||
|
# payment.save()
|
||||||
|
# self.assertEqual(
|
||||||
|
# GenericServiceProduct.objects.get(uuid=product.uuid).status,
|
||||||
|
# UncloudStatus.PENDING
|
||||||
|
# )
|
||||||
|
|
||||||
|
# class BillingAddressTestCase(TestCase):
|
||||||
|
# def setUp(self):
|
||||||
|
# self.user = get_user_model().objects.create(
|
||||||
|
# username='jdoe',
|
||||||
|
# email='john.doe@domain.tld')
|
||||||
|
|
||||||
|
# self.billing_address_01 = BillingAddress.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# street="unknown1",
|
||||||
|
# city="unknown1",
|
||||||
|
# postal_code="unknown1",
|
||||||
|
# country="CH")
|
||||||
|
|
||||||
|
# self.billing_address_02 = BillingAddress.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# street="unknown2",
|
||||||
|
# city="unknown2",
|
||||||
|
# postal_code="unknown2",
|
||||||
|
# country="CH")
|
||||||
|
|
||||||
|
# def test_billing_with_single_address(self):
|
||||||
|
# # Create new orders somewhere in the past so that we do not encounter
|
||||||
|
# # auto-created initial bills.
|
||||||
|
# starting_date = datetime.fromisoformat('2020-03-01')
|
||||||
|
|
||||||
|
# order_01 = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
|
# billing_address=self.billing_address_01)
|
||||||
|
# order_02 = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
|
# billing_address=self.billing_address_01)
|
||||||
|
|
||||||
|
# # We need a single bill since we work with a single address.
|
||||||
|
# bills = Bill.generate_for(2020, 4, self.user)
|
||||||
|
# self.assertEqual(len(bills), 1)
|
||||||
|
|
||||||
|
# def test_billing_with_multiple_addresses(self):
|
||||||
|
# # Create new orders somewhere in the past so that we do not encounter
|
||||||
|
# # auto-created initial bills.
|
||||||
|
# starting_date = datetime.fromisoformat('2020-03-01')
|
||||||
|
|
||||||
|
# order_01 = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
|
# billing_address=self.billing_address_01)
|
||||||
|
# order_02 = Order.objects.create(
|
||||||
|
# owner=self.user,
|
||||||
|
# starting_date=starting_date,
|
||||||
|
# recurring_period=RecurringPeriod.PER_30D,
|
||||||
|
# billing_address=self.billing_address_02)
|
||||||
|
|
||||||
|
# # We need different bills since we work with different addresses.
|
||||||
|
# bills = Bill.generate_for(2020, 4, self.user)
|
||||||
|
# self.assertEqual(len(bills), 2)
|
||||||
|
|
Loading…
Reference in a new issue