Can order a generic product now

This commit is contained in:
Nico Schottelius 2020-09-28 21:59:35 +02:00
parent c32499199a
commit 8d8c4d660c
4 changed files with 135 additions and 46 deletions

View file

@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-09-28 19:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('uncloud_pay', '0022_auto_20200928_1932'),
]
operations = [
migrations.RenameField(
model_name='order',
old_name='price',
new_name='one_time_price',
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 3.1 on 2020-09-28 19:45
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('uncloud_pay', '0023_auto_20200928_1944'),
]
operations = [
migrations.AddField(
model_name='order',
name='currency',
field=models.CharField(choices=[('CHF', 'Swiss Franc'), ('EUR', 'Euro'), ('USD', 'US Dollar')], default='CHF', max_length=32),
),
migrations.AddField(
model_name='order',
name='recurring_price',
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]),
),
]

View file

@ -563,14 +563,22 @@ class Order(models.Model):
starting_date = models.DateTimeField(default=timezone.now) starting_date = models.DateTimeField(default=timezone.now)
ending_date = models.DateTimeField(blank=True, null=True) ending_date = models.DateTimeField(blank=True, null=True)
# FIXME: ensure the period is defined in the product
recurring_period = models.IntegerField(choices = RecurringPeriod.choices, recurring_period = models.IntegerField(choices = RecurringPeriod.choices,
default = RecurringPeriod.PER_30D) default = RecurringPeriod.PER_30D)
price = models.DecimalField(default=0.0, one_time_price = models.DecimalField(default=0.0,
max_digits=AMOUNT_MAX_DIGITS, max_digits=AMOUNT_MAX_DIGITS,
decimal_places=AMOUNT_DECIMALS, decimal_places=AMOUNT_DECIMALS,
validators=[MinValueValidator(0)]) validators=[MinValueValidator(0)])
recurring_price = models.DecimalField(default=0.0,
max_digits=AMOUNT_MAX_DIGITS,
decimal_places=AMOUNT_DECIMALS,
validators=[MinValueValidator(0)])
currency = models.CharField(max_length=32, choices=Currency.choices, default=Currency.CHF)
replaces = models.ForeignKey('self', replaces = models.ForeignKey('self',
related_name='replaced_by', related_name='replaced_by',
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -768,6 +776,33 @@ class Order(models.Model):
starting_date=starting_date, starting_date=starting_date,
ending_date=ending_date) ending_date=ending_date)
def save(self, *args, **kwargs):
one_time_price = 0
recurring_price = 0
# FIXME: support amount independent one time prices
# FIXME: support a base price
if 'features' in self.product.config:
for feature in self.product.config['features']:
# FIXME: support optional features (?)
if not feature in self.config['features']:
raise ValidationError(f"Configuration is missing feature {feature}")
one_time_price += self.product.config['features'][feature]['one_time_price'] * self.config['features'][feature]
recurring_price += self.product.config['features'][feature]['recurring_price'] * self.config['features'][feature]
# IMMUTABLE fields -- need to create new order to modify them
# However this is not enforced here...
if self._state.adding:
self.one_time_price = one_time_price
self.recurring_price = recurring_price
super().save(*args, **kwargs)
def __str__(self): def __str__(self):
return f"{self.description} (order={self.id})" return f"{self.description} (order={self.id})"

View file

@ -8,33 +8,29 @@ from uncloud_service.models import GenericServiceProduct
import json import json
# class OrderTestCase(TestCase): vm_sample_product_config = {
# """ 'features': {
# The heart of ordering products 'cores':
# """ { 'min': 1,
'max': 48,
'one_time_price': 0,
'recurring_price': 4
},
'ram_gb':
{ 'min': 1,
'max': 256,
'one_time_price': 0,
'recurring_price': 4
},
},
}
# def setUp(self): vm_sample_order_config = {
# self.user = get_user_model().objects.create( 'features': {
# username='random_user', 'cores': 2,
# email='jane.random@domain.tld') 'ram_gb': 2
}
# 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?
# """
# p = SampleOneTimeProduct.objects.create(owner=self.user)
# self.assertEqual(p.one_time_price, 5)
# self.assertEqual(p.recurring_price, 0)
class ProductTestCase(TestCase): class ProductTestCase(TestCase):
@ -60,29 +56,45 @@ class ProductTestCase(TestCase):
Create a sample product Create a sample product
""" """
config = { p = Product.objects.create(name="Testproduct",
'features': { description="Only for testing",
'cores': config=vm_sample_product_config)
{ 'min': 1,
'max': 48,
'one_time_price': 0, class OrderTestCase(TestCase):
'recurring_price': 4 """
}, The heart of ordering products
'ram_gb': """
{ 'min': 1,
'max': 256, def setUp(self):
'one_time_price': 0, self.user = get_user_model().objects.create(
'recurring_price': 3 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)
def test_order_product(self):
"""
Order a product, ensure the order has correct price setup
"""
p = Product.objects.create(name="Testproduct", p = Product.objects.create(name="Testproduct",
description="Only for testing", description="Only for testing",
config=config) config=vm_sample_product_config)
# self.assertEqual(p.one_time_price, 5) o = Order.objects.create(owner=self.user,
# self.assertEqual(p.recurring_price, 0) billing_address=self.ba,
product=p,
config=vm_sample_order_config)
self.assertEqual(o.one_time_price, 0)
self.assertEqual(o.recurring_price, 16)
# class ProductTestCase(TestCase): # class ProductTestCase(TestCase):