forked from uncloud/uncloud
Merge branch 'uncloud-product-activation' into 'master'
Handle product activation on payment See merge request uncloud/uncloud!6
This commit is contained in:
commit
7afb3f8793
16 changed files with 352 additions and 38 deletions
|
@ -44,6 +44,8 @@ router.register(r'vm/vm', vmviews.VMProductViewSet, basename='vmproduct')
|
|||
|
||||
# Services
|
||||
router.register(r'service/matrix', serviceviews.MatrixServiceProductViewSet, basename='matrixserviceproduct')
|
||||
router.register(r'service/generic', serviceviews.GenericServiceProductViewSet, basename='genericserviceproduct')
|
||||
|
||||
|
||||
# Net
|
||||
router.register(r'net/vpn', netviews.VPNNetworkViewSet, basename='vpnnet')
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-17 05:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_net', '0002_auto_20200409_1225'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='vpnnetwork',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,6 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from uncloud_auth.models import User
|
||||
from uncloud_pay.models import Order, Bill, PaymentMethod, get_balance_for
|
||||
from uncloud_pay.models import Order, Bill, PaymentMethod, get_balance_for_user
|
||||
|
||||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
|
@ -15,7 +15,7 @@ class Command(BaseCommand):
|
|||
users = User.objects.all()
|
||||
print("Processing {} users.".format(users.count()))
|
||||
for user in users:
|
||||
balance = get_balance_for(user)
|
||||
balance = get_balance_for_user(user)
|
||||
if balance < 0:
|
||||
print("User {} has negative balance ({}), charging.".format(user.username, balance))
|
||||
payment_method = PaymentMethod.get_primary_for(user)
|
||||
|
|
|
@ -92,19 +92,19 @@ class Payment(models.Model):
|
|||
default='unknown')
|
||||
timestamp = models.DateTimeField(editable=False, auto_now_add=True)
|
||||
|
||||
# WIP prepaid and service activation logic by fnux.
|
||||
## We override save() in order to active products awaiting payment.
|
||||
#def save(self, *args, **kwargs):
|
||||
# # TODO: only run activation logic on creation, not on update.
|
||||
# unpaid_bills_before_payment = Bill.get_unpaid_for(self.owner)
|
||||
# super(Payment, self).save(*args, **kwargs) # Save payment in DB.
|
||||
# unpaid_bills_after_payment = Bill.get_unpaid_for(self.owner)
|
||||
# We override save() in order to active products awaiting payment.
|
||||
def save(self, *args, **kwargs):
|
||||
# _state.adding is switched to false after super(...) call.
|
||||
being_created = self._state.adding
|
||||
|
||||
# newly_paid_bills = list(
|
||||
# set(unpaid_bills_before_payment) - set(unpaid_bills_after_payment))
|
||||
# for bill in newly_paid_bills:
|
||||
# bill.activate_orders()
|
||||
unpaid_bills_before_payment = Bill.get_unpaid_for(self.owner)
|
||||
super(Payment, self).save(*args, **kwargs) # Save payment in DB.
|
||||
unpaid_bills_after_payment = Bill.get_unpaid_for(self.owner)
|
||||
|
||||
newly_paid_bills = list(
|
||||
set(unpaid_bills_before_payment) - set(unpaid_bills_after_payment))
|
||||
for bill in newly_paid_bills:
|
||||
bill.activate_products()
|
||||
|
||||
class PaymentMethod(models.Model):
|
||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
@ -201,6 +201,12 @@ class Bill(models.Model):
|
|||
|
||||
valid = models.BooleanField(default=True)
|
||||
|
||||
# Trigger product activation if bill paid at creation (from balance).
|
||||
def save(self, *args, **kwargs):
|
||||
super(Bill, self).save(*args, **kwargs)
|
||||
if not self in Bill.get_unpaid_for(self.owner):
|
||||
self.activate_products()
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
return "{}-{}".format(
|
||||
|
@ -227,6 +233,15 @@ class Bill(models.Model):
|
|||
# A bill is final when its ending date is passed.
|
||||
return self.ending_date < timezone.now()
|
||||
|
||||
def activate_products(self):
|
||||
for order in self.order_set.all():
|
||||
# FIXME: using __something might not be a good idea.
|
||||
for product_class in Product.__subclasses__():
|
||||
for product in product_class.objects.filter(order=order):
|
||||
if product.status == UncloudStatus.AWAITING_PAYMENT:
|
||||
product.status = UncloudStatus.PENDING
|
||||
product.save()
|
||||
|
||||
@staticmethod
|
||||
def generate_for(year, month, user):
|
||||
# /!\ We exclusively work on the specified year and month.
|
||||
|
@ -248,7 +263,7 @@ class Bill(models.Model):
|
|||
# (next_bill) ending_date, a new bill has to be generated.
|
||||
# * For yearly bill: if previous_bill.ending_date is on working
|
||||
# month, generate new bill.
|
||||
unpaid_orders = { 'monthly_or_less': [], 'yearly': {}}
|
||||
unpaid_orders = { 'monthly_or_less': [], 'yearly': {} }
|
||||
for order in orders:
|
||||
try:
|
||||
previous_bill = order.bill.latest('ending_date')
|
||||
|
@ -276,7 +291,7 @@ class Bill(models.Model):
|
|||
else:
|
||||
unpaid_orders['yearly'][next_yearly_bill_start_on] = bucket + [order]
|
||||
else:
|
||||
if previous_bill == None or previous_bill.ending_date <= ending_date:
|
||||
if previous_bill == None or previous_bill.ending_date < ending_date:
|
||||
unpaid_orders['monthly_or_less'].append(order)
|
||||
|
||||
# Handle working month's billing.
|
||||
|
@ -335,24 +350,23 @@ class Bill(models.Model):
|
|||
|
||||
@staticmethod
|
||||
def get_unpaid_for(user):
|
||||
balance = get_balance_for(user)
|
||||
balance = get_balance_for_user(user)
|
||||
unpaid_bills = []
|
||||
# No unpaid bill if balance is positive.
|
||||
if balance >= 0:
|
||||
return []
|
||||
return unpaid_bills
|
||||
else:
|
||||
bills = Bill.objects.filter(
|
||||
owner=user,
|
||||
due_date__lt=timezone.now()
|
||||
).order_by('-creation_date')
|
||||
|
||||
# Amount to be paid by the customer.
|
||||
unpaid_balance = abs(balance)
|
||||
for bill in bills:
|
||||
if unpaid_balance < 0:
|
||||
if unpaid_balance <= 0:
|
||||
break
|
||||
|
||||
unpaid_balance -= bill.amount
|
||||
unpaid_balance -= bill.total
|
||||
unpaid_bills.append(bill)
|
||||
|
||||
return unpaid_bills
|
||||
|
@ -464,6 +478,11 @@ class Order(models.Model):
|
|||
choices = RecurringPeriod.choices,
|
||||
default = RecurringPeriod.PER_MONTH)
|
||||
|
||||
# Trigger initial bill generation at order creation.
|
||||
def save(self, *args, **kwargs):
|
||||
super(Order, self).save(*args, **kwargs)
|
||||
Bill.generate_for(self.starting_date.year, self.starting_date.month, self.owner)
|
||||
|
||||
@property
|
||||
def records(self):
|
||||
return OrderRecord.objects.filter(order=self)
|
||||
|
@ -477,6 +496,10 @@ class Order(models.Model):
|
|||
return reduce(lambda acc, record: acc + record.recurring_price, self.records, 0)
|
||||
|
||||
# Used by uncloud_pay tests.
|
||||
@property
|
||||
def bills(self):
|
||||
return Bill.objects.filter(order=self)
|
||||
|
||||
def add_record(self, one_time_price, recurring_price, description):
|
||||
OrderRecord.objects.create(order=self,
|
||||
one_time_price=one_time_price,
|
||||
|
@ -531,11 +554,11 @@ class Product(UncloudModel):
|
|||
on_delete=models.CASCADE,
|
||||
editable=False)
|
||||
|
||||
description = ""
|
||||
description = "Generic Product"
|
||||
|
||||
status = models.CharField(max_length=32,
|
||||
choices=UncloudStatus.choices,
|
||||
default=UncloudStatus.PENDING)
|
||||
default=UncloudStatus.AWAITING_PAYMENT)
|
||||
|
||||
order = models.ForeignKey(Order,
|
||||
on_delete=models.CASCADE,
|
||||
|
@ -556,7 +579,7 @@ class Product(UncloudModel):
|
|||
if being_created:
|
||||
record = OrderRecord(
|
||||
one_time_price=self.one_time_price,
|
||||
recurring_price=self.recurring_price(self.recurring_period),
|
||||
recurring_price=self.recurring_price(recurring_period=self.recurring_period),
|
||||
description=self.description)
|
||||
self.order.orderrecord_set.add(record, bulk=False)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.contrib.auth import get_user_model
|
|||
from datetime import datetime, date, timedelta
|
||||
|
||||
from .models import *
|
||||
from uncloud_service.models import GenericServiceProduct
|
||||
|
||||
class BillingTestCase(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -10,9 +11,6 @@ class BillingTestCase(TestCase):
|
|||
username='jdoe',
|
||||
email='john.doe@domain.tld')
|
||||
|
||||
def test_truth(self):
|
||||
self.assertEqual(1+1, 2)
|
||||
|
||||
def test_basic_monthly_billing(self):
|
||||
one_time_price = 10
|
||||
recurring_price = 20
|
||||
|
@ -31,7 +29,7 @@ class BillingTestCase(TestCase):
|
|||
order.add_record(one_time_price, recurring_price, description)
|
||||
|
||||
# Generate & check bill for first month: full recurring_price + setup.
|
||||
first_month_bills = Bill.generate_for(2020, 3, self.user)
|
||||
first_month_bills = order.bills # Initial bill generated at order creation.
|
||||
self.assertEqual(len(first_month_bills), 1)
|
||||
self.assertEqual(first_month_bills[0].total, one_time_price + recurring_price)
|
||||
|
||||
|
@ -65,7 +63,7 @@ class BillingTestCase(TestCase):
|
|||
order.add_record(one_time_price, recurring_price, description)
|
||||
|
||||
# Generate & check bill for first year: recurring_price + setup.
|
||||
first_year_bills = Bill.generate_for(2020, 3, self.user)
|
||||
first_year_bills = order.bills # Initial bill generated at order creation.
|
||||
self.assertEqual(len(first_year_bills), 1)
|
||||
self.assertEqual(first_year_bills[0].starting_date.date(),
|
||||
date.fromisoformat('2020-03-31'))
|
||||
|
@ -106,7 +104,7 @@ class BillingTestCase(TestCase):
|
|||
order.add_record(one_time_price, recurring_price, description)
|
||||
|
||||
# Generate & check bill for first month: recurring_price + setup.
|
||||
first_month_bills = Bill.generate_for(2020, 3, self.user)
|
||||
first_month_bills = order.bills
|
||||
self.assertEqual(len(first_month_bills), 1)
|
||||
self.assertEqual(float(first_month_bills[0].total),
|
||||
round(16 * recurring_price, AMOUNT_DECIMALS) + one_time_price)
|
||||
|
@ -116,3 +114,41 @@ class BillingTestCase(TestCase):
|
|||
self.assertEqual(len(second_month_bills), 1)
|
||||
self.assertEqual(float(second_month_bills[0].total),
|
||||
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')
|
||||
|
||||
def test_product_activation(self):
|
||||
starting_date = datetime.fromisoformat('2020-03-01')
|
||||
|
||||
order = Order.objects.create(
|
||||
owner=self.user,
|
||||
starting_date=starting_date,
|
||||
recurring_period=RecurringPeriod.PER_MONTH)
|
||||
order.save()
|
||||
|
||||
product = GenericServiceProduct(
|
||||
custom_description="Test product",
|
||||
custom_one_time_price=0,
|
||||
custom_recurring_price=20,
|
||||
owner=self.user,
|
||||
order=order)
|
||||
product.save()
|
||||
|
||||
# XXX: to be automated.
|
||||
order.add_record(product.one_time_price, product.recurring_price(), product.description)
|
||||
|
||||
# Validate initial state: must be awaiting payment.
|
||||
self.assertEqual(product.status, UncloudStatus.AWAITING_PAYMENT)
|
||||
|
||||
# Pay initial bill, check that product is activated.
|
||||
amount = product.order.bills[0].total
|
||||
payment = Payment(owner=self.user, amount=amount)
|
||||
payment.save()
|
||||
self.assertEqual(
|
||||
GenericServiceProduct.objects.get(uuid=product.uuid).status,
|
||||
UncloudStatus.PENDING
|
||||
)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-18 06:41
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('uncloud_pay', '0005_auto_20200413_0924'),
|
||||
('uncloud_service', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='matrixserviceproduct',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GenericServiceProduct',
|
||||
fields=[
|
||||
('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)),
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('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)),
|
||||
('custom_description', models.TextField()),
|
||||
('custom_recurring_price', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('custom_one_time_price', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('order', models.ForeignKey(editable=False, 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,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,8 +1,9 @@
|
|||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from uncloud_pay.models import Product, RecurringPeriod
|
||||
from uncloud_pay.models import Product, RecurringPeriod, AMOUNT_MAX_DIGITS, AMOUNT_DECIMALS
|
||||
from uncloud_vm.models import VMProduct, VMDiskImageProduct
|
||||
from django.core.validators import MinValueValidator
|
||||
|
||||
class MatrixServiceProduct(Product):
|
||||
monthly_managment_fee = 20
|
||||
|
@ -16,7 +17,7 @@ class MatrixServiceProduct(Product):
|
|||
domain = models.CharField(max_length=255, default='domain.tld')
|
||||
|
||||
# Default recurring price is PER_MONT, see Product class.
|
||||
def recurring_price(self):
|
||||
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
||||
return self.monthly_managment_fee
|
||||
|
||||
@staticmethod
|
||||
|
@ -33,3 +34,30 @@ class MatrixServiceProduct(Product):
|
|||
@property
|
||||
def one_time_price(self):
|
||||
return 30
|
||||
|
||||
class GenericServiceProduct(Product):
|
||||
custom_description = models.TextField()
|
||||
custom_recurring_price = models.DecimalField(default=0.0,
|
||||
max_digits=AMOUNT_MAX_DIGITS,
|
||||
decimal_places=AMOUNT_DECIMALS,
|
||||
validators=[MinValueValidator(0)])
|
||||
custom_one_time_price = models.DecimalField(default=0.0,
|
||||
max_digits=AMOUNT_MAX_DIGITS,
|
||||
decimal_places=AMOUNT_DECIMALS,
|
||||
validators=[MinValueValidator(0)])
|
||||
|
||||
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
||||
# FIXME: handle recurring_period somehow.
|
||||
return self.custom_recurring_price
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.custom_description
|
||||
|
||||
@property
|
||||
def one_time_price(self):
|
||||
return self.custom_one_time_price
|
||||
|
||||
@staticmethod
|
||||
def allowed_recurring_periods():
|
||||
return RecurringPeriod.choices
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from rest_framework import serializers
|
||||
from .models import MatrixServiceProduct
|
||||
from .models import *
|
||||
from uncloud_vm.serializers import ManagedVMProductSerializer
|
||||
from uncloud_vm.models import VMProduct
|
||||
from uncloud_pay.models import RecurringPeriod
|
||||
|
@ -15,3 +15,14 @@ class MatrixServiceProductSerializer(serializers.ModelSerializer):
|
|||
model = MatrixServiceProduct
|
||||
fields = ['uuid', 'order', 'owner', 'status', 'vm', 'domain', 'recurring_period']
|
||||
read_only_fields = ['uuid', 'order', 'owner', 'status']
|
||||
|
||||
class GenericServiceProductSerializer(serializers.ModelSerializer):
|
||||
# Custom field used at creation (= ordering) only.
|
||||
recurring_period = serializers.ChoiceField(
|
||||
choices=GenericServiceProduct.allowed_recurring_periods())
|
||||
|
||||
class Meta:
|
||||
model = GenericServiceProduct
|
||||
fields = ['uuid', 'order', 'owner', 'status', 'custom_recurring_price',
|
||||
'custom_description', 'custom_one_time_price', 'recurring_period']
|
||||
read_only_fields = ['uuid', 'order', 'owner', 'status']
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from rest_framework import viewsets, permissions
|
||||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import MatrixServiceProduct
|
||||
from .serializers import MatrixServiceProductSerializer
|
||||
from .models import *
|
||||
from .serializers import *
|
||||
|
||||
from uncloud_pay.helpers import ProductViewSet
|
||||
from uncloud_pay.models import Order
|
||||
|
@ -47,7 +48,10 @@ class MatrixServiceProductViewSet(ProductViewSet):
|
|||
# Create base order.)
|
||||
order = Order.objects.create(
|
||||
recurring_period=order_recurring_period,
|
||||
owner=request.user)
|
||||
owner=request.user,
|
||||
starting_date=timezone.now()
|
||||
)
|
||||
order.save()
|
||||
|
||||
# Create unerderlying VM.
|
||||
data = serializer.validated_data.pop('vm')
|
||||
|
@ -65,3 +69,45 @@ class MatrixServiceProductViewSet(ProductViewSet):
|
|||
vm=vm)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
class GenericServiceProductViewSet(ProductViewSet):
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
serializer_class = GenericServiceProductSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return GenericServiceProduct.objects.filter(owner=self.request.user)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, request):
|
||||
# Extract serializer data.
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
order_recurring_period = serializer.validated_data.pop("recurring_period")
|
||||
|
||||
# Create base order.
|
||||
order = Order.objects.create(
|
||||
recurring_period=order_recurring_period,
|
||||
owner=request.user,
|
||||
starting_date=timezone.now()
|
||||
)
|
||||
order.save()
|
||||
|
||||
# Create service.
|
||||
print(serializer.validated_data)
|
||||
service = serializer.save(order=order, owner=request.user)
|
||||
|
||||
# XXX: Move this to some kind of on_create hook in parent
|
||||
# Product class?
|
||||
order.add_record(
|
||||
service.one_time_price,
|
||||
service.recurring_price,
|
||||
service.description)
|
||||
|
||||
# XXX: Move this to some kind of on_create hook in parent
|
||||
# Product class?
|
||||
order.add_record(
|
||||
service.one_time_price,
|
||||
service.recurring_price,
|
||||
service.description)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -7,7 +7,7 @@ import django.db.models.deletion
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_vm', '0003_remove_vmhost_vms'),
|
||||
('uncloud_vm', '0004_remove_vmproduct_vmid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-17 05:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_vm', '0008_auto_20200403_1727'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='vmproduct',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vmsnapshotproduct',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-18 06:41
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_vm', '0009_auto_20200417_0551'),
|
||||
('uncloud_vm', '0010_auto_20200413_0924'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-18 06:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_vm', '0011_merge_20200418_0641'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='vmdiskproduct',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
]
|
|
@ -116,7 +116,7 @@ class VMProductViewSet(ProductViewSet):
|
|||
order_recurring_period = serializer.validated_data.pop("recurring_period")
|
||||
|
||||
# Create base order.
|
||||
order = Order.objects.create(
|
||||
order = Order(
|
||||
recurring_period=order_recurring_period,
|
||||
owner=request.user,
|
||||
starting_date=timezone.now()
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-17 05:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ungleich_service', '0004_auto_20200403_1727'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='matrixserviceproduct',
|
||||
name='status',
|
||||
field=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),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 3.0.5 on 2020-04-17 08:02
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('uncloud_pay', '0005_auto_20200417_0551'),
|
||||
('ungleich_service', '0005_auto_20200417_0551'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GenericServiceProduct',
|
||||
fields=[
|
||||
('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)),
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('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)),
|
||||
('custom_description', models.TextField()),
|
||||
('custom_recurring_price', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('custom_one_time_price', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('order', models.ForeignKey(editable=False, 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,
|
||||
},
|
||||
),
|
||||
]
|
Loading…
Reference in a new issue