add sample products and improve testing for Product

This commit is contained in:
Nico Schottelius 2020-08-09 11:02:45 +02:00
parent 6a928a2b2a
commit 0dd1093812
4 changed files with 156 additions and 17 deletions

View file

@ -0,0 +1,65 @@
# Generated by Django 3.1 on 2020-08-09 08:56
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('uncloud_pay', '0009_auto_20200808_2113'),
]
operations = [
migrations.AlterField(
model_name='order',
name='depends_on',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parent_of', to='uncloud_pay.order'),
),
migrations.AlterField(
model_name='order',
name='replaces',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='replaced_by', to='uncloud_pay.order'),
),
migrations.CreateModel(
name='SampleRecurringProductOneTimeFee',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extra_data', models.JSONField(blank=True, editable=False, null=True)),
('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='AWAITING_PAYMENT', max_length=32)),
('order', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.order')),
('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='SampleRecurringProduct',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extra_data', models.JSONField(blank=True, editable=False, null=True)),
('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='AWAITING_PAYMENT', max_length=32)),
('order', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.order')),
('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='SampleOneTimeProduct',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extra_data', models.JSONField(blank=True, editable=False, null=True)),
('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='AWAITING_PAYMENT', max_length=32)),
('order', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.order')),
('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]

View file

@ -596,7 +596,6 @@ class BillRecord(models.Model):
return record_delta.total_seconds()/self.order.recurring_period
@property
def sum(self):
return self.order.price * Decimal(self.quantity)
@ -604,6 +603,12 @@ class BillRecord(models.Model):
def __str__(self):
return f"{self.bill}: {self.quantity} x {self.order}"
def save(self, *args, **kwargs):
if self.ending_date < self.starting_date:
raise ValidationError("End date cannot be before starting date")
super().save(*args, **kwargs)
###
# Products
@ -703,13 +708,12 @@ class Product(UncloudModel):
@property
def recurring_price(self):
pass # To be implemented in child.
""" implement correct values in the child class """
return 0
@property
def one_time_price(self):
"""
Default is 0 CHF
"""
""" implement correct values in the child class """
return 0
@ -799,3 +803,30 @@ class Product(UncloudModel):
else:
# FIXME: use the right type of exception here!
raise Exception("Did not implement the discounter for this case")
# Sample products included into uncloud
class SampleOneTimeProduct(Product):
default_recurring_period = RecurringPeriod.ONE_TIME
@property
def one_time_price(self):
return 5
class SampleRecurringProduct(Product):
default_recurring_period = RecurringPeriod.PER_30D
@property
def recurring_price(self):
return 10
class SampleRecurringProductOneTimeFee(Product):
default_recurring_period = RecurringPeriod.PER_30D
@property
def one_time_price(self):
return 5
@property
def recurring_price(self):
return 1

View file

@ -5,6 +5,7 @@ from datetime import datetime, date, timedelta
from .models import *
from uncloud_service.models import GenericServiceProduct
class ProductOrderTestCase(TestCase):
"""
Test products and products <-> order interaction
@ -15,12 +16,53 @@ class ProductOrderTestCase(TestCase):
username='random_user',
email='jane.random@domain.tld')
def test_update_one_time_product(self):
ba = BillingAddress.objects.create(
owner=self.user,
organization = 'Test org',
street="unknown",
city="unknown",
postal_code="somewhere else",
active=True)
def test_create_one_time_product(self):
"""
One time payment products cannot be updated - can they?
"""
pass
p = SampleOneTimeProduct.objects.create(owner=self.user)
self.assertEqual(p.one_time_price, 5)
self.assertEqual(p.recurring_price, 0)
def test_create_order_creates_correct_order_count(self):
"""
Ensure creating orders from product only creates 1 order
"""
# One order
p = SampleOneTimeProduct(owner=self.user)
p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
p.save()
order_count = Order.objects.filter(owner=self.user).count()
self.assertEqual(order_count, 1)
# One more order
p = SampleRecurringProduct(owner=self.user)
p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
p.save()
order_count = Order.objects.filter(owner=self.user).count()
self.assertEqual(order_count, 2)
# Should create 2 orders
p = SampleRecurringProductOneTimeFee(owner=self.user)
p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
p.save()
order_count = Order.objects.filter(owner=self.user).count()
self.assertEqual(order_count, 4)
class BillingAddressTestCase(TestCase):

View file

@ -69,16 +69,6 @@ class VMProduct(Product):
def recurring_price(self):
return self.cores * 3 + self.ram_in_gb * 4
def __str__(self):
if self.name:
name = f"{self.name} ({self.id})"
else:
name = self.id
return "VM {}: {} cores {} gb ram".format(name,
self.cores,
self.ram_in_gb)
@property
def description(self):
return "Virtual machine '{}': {} core(s), {}GB memory".format(
@ -92,6 +82,17 @@ class VMProduct(Product):
RecurringPeriod.choices))
def __str__(self):
name = f"{self.id}"
if self.name:
name = f"{self.id} ({self.name})"
return "VM {}: {} cores {} gb ram".format(name,
self.cores,
self.ram_in_gb)
class VMWithOSProduct(VMProduct):
primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True)