- Fix: Support decimal in price (database migration needed)
- Fix: New instance usage not counted when add new project after billing enabled
This commit is contained in:
parent
f714b31ffd
commit
d1227fd6fb
4 changed files with 309 additions and 3 deletions
30
CHANGELOG.txt
Normal file
30
CHANGELOG.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
v1.0.1
|
||||||
|
---------------------------
|
||||||
|
- Fix: Support decimal in price (database migration needed)
|
||||||
|
- Fix: New instance usage not counted when add new project after billing enabled
|
||||||
|
|
||||||
|
v1.0
|
||||||
|
---------------------------
|
||||||
|
- Bug fixing for handling price not found
|
||||||
|
- Upload logo for your invoice
|
||||||
|
- Add currency to overview
|
||||||
|
- Email SMTP setting now optional, it will ignore any error regarding sending email. You can resend it on notification center
|
||||||
|
- Change invoice email format
|
||||||
|
- Handle new project when billing already started (you need to update your keystone.conf)
|
||||||
|
|
||||||
|
|
||||||
|
v1.0-beta
|
||||||
|
----------------------------
|
||||||
|
- Setting company profile
|
||||||
|
- Send invoice to email
|
||||||
|
- Notification center
|
||||||
|
- Update invoice format
|
||||||
|
|
||||||
|
|
||||||
|
v1.0-alpha
|
||||||
|
----------------------------
|
||||||
|
- Price Configuration
|
||||||
|
- Project Overview
|
||||||
|
- Project Invoice
|
||||||
|
- Usage Cost
|
||||||
|
- Billing Settings
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from core.models import BillingProject
|
from core.models import BillingProject, Invoice
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
LOG = logging.getLogger("yuyu_notification")
|
LOG = logging.getLogger("yuyu_notification")
|
||||||
|
|
||||||
|
@ -13,3 +14,14 @@ class ProjectEventHandler:
|
||||||
project = BillingProject()
|
project = BillingProject()
|
||||||
project.tenant_id = new_project_id
|
project.tenant_id = new_project_id
|
||||||
project.save()
|
project.save()
|
||||||
|
LOG.info("Creating invoice for " + new_project_id)
|
||||||
|
self.init_first_invoice(project)
|
||||||
|
|
||||||
|
def init_first_invoice(self, project):
|
||||||
|
date_today = timezone.now()
|
||||||
|
month_first_day = date_today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
Invoice.objects.create(
|
||||||
|
project=project,
|
||||||
|
start_date=month_first_day,
|
||||||
|
state=Invoice.InvoiceState.IN_PROGRESS
|
||||||
|
)
|
||||||
|
|
264
core/migrations/0010_auto_20221031_1801.py
Normal file
264
core/migrations/0010_auto_20221031_1801.py
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
# Generated by Django 3.2.6 on 2022-10-31 18:01
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import djmoney.models.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0009_notification'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='flavorprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='flavorprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='flavorprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='flavorprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='floatingipsprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='floatingipsprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='floatingipsprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='floatingipsprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='imageprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='imageprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='imageprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='imageprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoice',
|
||||||
|
name='tax_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoice',
|
||||||
|
name='total_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicefloatingip',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicefloatingip',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicefloatingip',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicefloatingip',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceimage',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceimage',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceimage',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceimage',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceinstance',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceinstance',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceinstance',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoiceinstance',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicerouter',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicerouter',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicerouter',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicerouter',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicesnapshot',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicesnapshot',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicesnapshot',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicesnapshot',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicevolume',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicevolume',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicevolume',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invoicevolume',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='routerprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='routerprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='routerprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='routerprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snapshotprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snapshotprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snapshotprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='snapshotprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='volumeprice',
|
||||||
|
name='hourly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(decimal_places=2, max_digits=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='volumeprice',
|
||||||
|
name='hourly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='volumeprice',
|
||||||
|
name='monthly_price',
|
||||||
|
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default=None, max_digits=10, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='volumeprice',
|
||||||
|
name='monthly_price_currency',
|
||||||
|
field=djmoney.models.fields.CurrencyField(choices=[('USD', 'US Dollar')], default='USD', editable=False, max_length=3),
|
||||||
|
),
|
||||||
|
]
|
|
@ -19,8 +19,8 @@ class TimestampMixin(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class PriceMixin(models.Model):
|
class PriceMixin(models.Model):
|
||||||
hourly_price = MoneyField(max_digits=10, decimal_places=0)
|
hourly_price = MoneyField(max_digits=10)
|
||||||
monthly_price = MoneyField(max_digits=10, decimal_places=0, default=None, blank=True, null=True)
|
monthly_price = MoneyField(max_digits=10, default=None, blank=True, null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
Loading…
Add table
Reference in a new issue