uncloud/uncloud_pay/tests.py

490 lines
15 KiB
Python
Raw Normal View History

from django.test import TestCase
2020-03-09 10:30:11 +00:00
from django.contrib.auth import get_user_model
from datetime import datetime, date, timedelta
from django.utils import timezone
2020-03-09 10:30:11 +00:00
from .models import *
from uncloud_service.models import GenericServiceProduct
2021-06-20 09:51:27 +00:00
from uncloud.models import UncloudProvider
2020-03-09 10:30:11 +00:00
import json
2020-09-28 21:16:17 +00:00
chocolate_product_config = {
'features': {
'gramm':
{ 'min': 100,
'max': 5000,
2020-10-06 21:14:32 +00:00
'one_time_price_per_unit': 0.2,
'recurring_price_per_unit': 0
2020-09-28 21:16:17 +00:00
},
},
}
chocolate_order_config = {
'features': {
'gramm': 500,
}
}
2020-10-06 21:14:32 +00:00
chocolate_one_time_price = chocolate_order_config['features']['gramm'] * chocolate_product_config['features']['gramm']['one_time_price_per_unit']
2020-09-28 21:16:17 +00:00
vm_product_config = {
2020-09-28 19:59:35 +00:00
'features': {
'cores':
{ 'min': 1,
'max': 48,
2020-10-06 21:14:32 +00:00
'one_time_price_per_unit': 0,
'recurring_price_per_unit': 4
2020-09-28 19:59:35 +00:00
},
'ram_gb':
{ 'min': 1,
'max': 256,
2020-10-06 21:14:32 +00:00
'one_time_price_per_unit': 0,
'recurring_price_per_unit': 4
2020-09-28 19:59:35 +00:00
},
},
}
vm_order_config = {
2020-09-28 19:59:35 +00:00
'features': {
'cores': 2,
'ram_gb': 2
}
}
vm_order_downgrade_config = {
'features': {
'cores': 1,
'ram_gb': 1
}
}
vm_order_upgrade_config = {
'features': {
'cores': 4,
'ram_gb': 4
}
}
class ProductTestCase(TestCase):
"""
Test products and products <-> order interaction
"""
2020-08-08 21:02:24 +00:00
def setUp(self):
self.user = get_user_model().objects.create(
username='random_user',
email='jane.random@domain.tld')
self.ba = BillingAddress.objects.create(
2020-08-08 21:02:24 +00:00
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="somewhere else",
active=True)
RecurringPeriod.populate_db_defaults()
self.default_recurring_period = RecurringPeriod.objects.get(name="Per 30 days")
def test_create_product(self):
"""
Create a sample product
"""
2020-09-28 19:59:35 +00:00
p = Product.objects.create(name="Testproduct",
description="Only for testing",
2020-10-06 21:14:32 +00:00
config=vm_product_config)
p.recurring_periods.add(self.default_recurring_period,
through_defaults= { 'is_default': True })
2020-09-28 19:59:35 +00:00
class OrderTestCase(TestCase):
"""
The heart of ordering products
"""
def setUp(self):
self.user = get_user_model().objects.create(
username='random_user',
email='jane.random@domain.tld')
self.ba = BillingAddress.objects.create(
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="somewhere else",
active=True)
2020-10-06 21:14:32 +00:00
self.product = Product.objects.create(name="Testproduct",
description="Only for testing",
config=vm_product_config)
RecurringPeriod.populate_db_defaults()
self.default_recurring_period = RecurringPeriod.objects.get(name="Per 30 days")
2020-10-06 21:14:32 +00:00
self.product.recurring_periods.add(self.default_recurring_period,
through_defaults= { 'is_default': True })
def test_order_invalid_recurring_period(self):
"""
Order a products with a recurringperiod that is not added to the product
"""
o = Order.objects.create(owner=self.user,
billing_address=self.ba,
product=self.product,
config=vm_order_config)
2020-09-28 19:59:35 +00:00
def test_order_product(self):
"""
Order a product, ensure the order has correct price setup
"""
2020-08-08 21:02:24 +00:00
2020-09-28 19:59:35 +00:00
o = Order.objects.create(owner=self.user,
billing_address=self.ba,
2020-10-06 21:14:32 +00:00
product=self.product)
2020-08-08 21:02:24 +00:00
2020-09-28 19:59:35 +00:00
self.assertEqual(o.one_time_price, 0)
self.assertEqual(o.recurring_price, 16)
2020-08-08 21:02:24 +00:00
def test_change_order(self):
"""
Change an order and ensure that
- a new order is created
- the price is correct in the new order
"""
order1 = Order.objects.create(owner=self.user,
billing_address=self.ba,
2020-10-06 21:14:32 +00:00
product=self.product,
config=vm_order_config)
self.assertEqual(order1.one_time_price, 0)
self.assertEqual(order1.recurring_price, 16)
class ModifyOrderTestCase(TestCase):
"""
Test typical order flows like
- cancelling
- downgrading
- upgrading
"""
def setUp(self):
self.user = get_user_model().objects.create(
username='random_user',
email='jane.random@domain.tld')
self.ba = BillingAddress.objects.create(
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="somewhere else",
active=True)
2020-10-06 21:14:32 +00:00
self.product = Product.objects.create(name="Testproduct",
description="Only for testing",
config=vm_product_config)
RecurringPeriod.populate_db_defaults()
self.default_recurring_period = RecurringPeriod.objects.get(name="Per 30 days")
2020-10-06 21:14:32 +00:00
self.product.recurring_periods.add(self.default_recurring_period,
through_defaults= { 'is_default': True })
def test_change_order(self):
"""
Test changing an order
Expected result:
- Old order should be closed before new order starts
- New order should start at starting data
"""
user = self.user
starting_price = 16
downgrade_price = 8
starting_date = timezone.make_aware(datetime.datetime(2019,3,3))
ending1_date = starting_date + datetime.timedelta(days=15)
change1_date = start_after(ending1_date)
bill_ending_date = change1_date + datetime.timedelta(days=1)
order1 = Order.objects.create(owner=self.user,
billing_address=BillingAddress.get_address_for(self.user),
product=self.product,
config=vm_order_config,
starting_date=starting_date)
order1.update_order(vm_order_downgrade_config, starting_date=change1_date)
bills = Bill.create_next_bills_for_user(user, ending_date=bill_ending_date)
bill = bills[0]
bill_records = BillRecord.objects.filter(bill=bill)
self.assertEqual(len(bill_records), 2)
self.assertEqual(bill_records[0].starting_date, starting_date)
self.assertEqual(bill_records[0].ending_date, ending1_date)
self.assertEqual(bill_records[1].starting_date, change1_date)
def test_downgrade_product(self):
"""
Test downgrading behaviour:
We create a recurring product (recurring time: 30 days) and downgrade after 15 days.
We create the bill right AFTER the end of the first order.
Expected result:
- First bill record for 30 days
- Second bill record starting after 30 days
- Bill contains two bill records
"""
user = self.user
starting_price = 16
downgrade_price = 8
starting_date = timezone.make_aware(datetime.datetime(2019,3,3))
first_order_should_end_at = starting_date + datetime.timedelta(days=30)
change1_date = start_after(starting_date + datetime.timedelta(days=15))
bill_ending_date = change1_date + datetime.timedelta(days=1)
order1 = Order.objects.create(owner=self.user,
billing_address=BillingAddress.get_address_for(self.user),
product=self.product,
config=vm_order_config,
starting_date=starting_date)
order1.update_order(vm_order_downgrade_config, starting_date=change1_date)
bills = Bill.create_next_bills_for_user(user, ending_date=bill_ending_date)
bill = bills[0]
bill_records = BillRecord.objects.filter(bill=bill)
self.assertEqual(len(bill_records), 2)
self.assertEqual(bill_records[0].starting_date, starting_date)
self.assertEqual(bill_records[0].order.ending_date, first_order_should_end_at)
2020-09-28 21:16:17 +00:00
class BillTestCase(TestCase):
"""
Test aspects of billing / creating a bill
"""
def setUp(self):
RecurringPeriod.populate_db_defaults()
2020-09-28 21:16:17 +00:00
self.user_without_address = get_user_model().objects.create(
username='no_home_person',
email='far.away@domain.tld')
self.user = get_user_model().objects.create(
username='jdoe',
email='john.doe@domain.tld')
self.recurring_user = get_user_model().objects.create(
username='recurrent_product_user',
email='jane.doe@domain.tld')
self.user_addr = BillingAddress.objects.create(
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="unknown",
active=True)
self.recurring_user_addr = BillingAddress.objects.create(
owner=self.recurring_user,
organization = 'Test org',
street="Somewhere",
city="Else",
postal_code="unknown",
active=True)
self.order_meta = {}
self.order_meta[1] = {
'starting_date': timezone.make_aware(datetime.datetime(2020,3,3)),
'ending_date': timezone.make_aware(datetime.datetime(2020,4,17)),
'price': 15,
'description': 'One chocolate bar'
}
self.chocolate = Product.objects.create(name="Swiss Chocolate",
description="Not only for testing, but for joy",
config=chocolate_product_config)
self.vm = Product.objects.create(name="Super Fast VM",
description="Zooooom",
config=vm_product_config)
2020-09-28 21:16:17 +00:00
2020-10-06 21:14:32 +00:00
RecurringPeriod.populate_db_defaults()
self.default_recurring_period = RecurringPeriod.objects.get(name="Per 30 days")
self.onetime_recurring_period = RecurringPeriod.objects.get(name="Onetime")
self.chocolate.recurring_periods.add(self.onetime_recurring_period,
through_defaults= { 'is_default': True })
self.vm.recurring_periods.add(self.default_recurring_period,
through_defaults= { 'is_default': True })
2020-09-28 21:16:17 +00:00
# used for generating multiple bills
self.bill_dates = [
timezone.make_aware(datetime.datetime(2020,3,31)),
timezone.make_aware(datetime.datetime(2020,4,30)),
timezone.make_aware(datetime.datetime(2020,5,31)),
]
def order_chocolate(self):
return Order.objects.create(
owner=self.user,
recurring_period=RecurringPeriod.objects.get(name="Onetime"),
2020-09-28 21:16:17 +00:00
product=self.chocolate,
billing_address=BillingAddress.get_address_for(self.user),
starting_date=self.order_meta[1]['starting_date'],
ending_date=self.order_meta[1]['ending_date'],
config=chocolate_order_config)
def order_vm(self, owner=None):
if not owner:
owner = self.recurring_user
return Order.objects.create(
owner=owner,
product=self.vm,
config=vm_order_config,
billing_address=BillingAddress.get_address_for(self.recurring_user),
starting_date=timezone.make_aware(datetime.datetime(2020,3,3)),
)
return Order.objects.create(
owner=self.user,
recurring_period=RecurringPeriod.objects.get(name="Onetime"),
product=self.chocolate,
billing_address=BillingAddress.get_address_for(self.user),
starting_date=self.order_meta[1]['starting_date'],
ending_date=self.order_meta[1]['ending_date'],
config=chocolate_order_config)
2020-09-28 21:16:17 +00:00
def test_bill_one_time_one_bill_record(self):
"""
Ensure there is only 1 bill record per order
"""
order = self.order_chocolate()
bill = Bill.create_next_bill_for_user_address(self.user_addr)
self.assertEqual(order.billrecord_set.count(), 1)
def test_bill_sum_onetime(self):
"""
Check the bill sum for a single one time order
"""
order = self.order_chocolate()
bill = Bill.create_next_bill_for_user_address(self.user_addr)
self.assertEqual(bill.sum, chocolate_one_time_price)
def test_bill_creates_record_for_recurring_order(self):
"""
Ensure there is only 1 bill record per order
"""
2020-09-28 21:16:17 +00:00
order = self.order_vm()
bill = Bill.create_next_bill_for_user_address(self.recurring_user_addr)
2020-09-28 21:16:17 +00:00
self.assertEqual(order.billrecord_set.count(), 1)
self.assertEqual(bill.billrecord_set.count(), 1)
2020-09-28 21:16:17 +00:00
def test_new_bill_after_closing(self):
"""
After closing a bill and the user has a recurring product,
the next bill run should create e new bill
"""
2020-09-28 21:16:17 +00:00
order = self.order_vm()
2020-09-28 21:16:17 +00:00
for ending_date in self.bill_dates:
b = Bill.create_next_bill_for_user_address(self.recurring_user_addr, ending_date)
b.close()
2020-09-28 21:16:17 +00:00
bill_count = Bill.objects.filter(owner=self.recurring_user).count()
2020-09-28 21:16:17 +00:00
self.assertEqual(len(self.bill_dates), bill_count)
2020-09-28 21:16:17 +00:00
class BillingAddressTestCase(TestCase):
def setUp(self):
self.user = get_user_model().objects.create(
username='random_user',
email='jane.random@domain.tld')
2020-08-09 08:14:49 +00:00
def test_user_no_address(self):
"""
Raise an error, when there is no address
"""
2020-08-09 08:14:49 +00:00
self.assertRaises(uncloud_pay.models.BillingAddress.DoesNotExist,
BillingAddress.get_address_for,
self.user)
2021-06-20 09:51:27 +00:00
class VATRatesTestCase(TestCase):
def setUp(self):
self.user = get_user_model().objects.create(
username='random_user',
email='jane.random@domain.tld')
self.user_addr = BillingAddress.objects.create(
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="unknown",
active=True)
UncloudProvider.populate_db_defaults()
def test_get_rate_for_user(self):
"""
Raise an error, when there is no address
"""