diff --git a/.gitignore b/.gitignore
index e09fef54..1b2b4d16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,5 @@ secret-key
/utils/optimize/
# to keep empty dirs
-!.gitkeep
\ No newline at end of file
+!.gitkeep
+*.orig
diff --git a/Changelog b/Changelog
index 46b2534b..471f0720 100644
--- a/Changelog
+++ b/Changelog
@@ -1,7 +1,10 @@
-next:
+1.7: 2018-04-20
* bgfix: [all] Make /blog available on all domains
* #4367: [dcl] email logo resolution fix
* #4376: [cms] dcl promo section plugin link color changed to brighter shade
+ * #4379: [dcl] pricing without VAT
+ * bgfix: [blog] fix top menu items to show only one item
+ * #4297: [cms] favicon as a page attribute for dcl template
1.6.5: 2018-04-08
* #4396: [ungleich] add favicon to ungleich blog
* #4327: [dcl] fix navbar logo repeat
diff --git a/datacenterlight/admin.py b/datacenterlight/admin.py
index acb93fff..d95e4f87 100644
--- a/datacenterlight/admin.py
+++ b/datacenterlight/admin.py
@@ -1,10 +1,18 @@
from django.contrib import admin
from cms.admin.placeholderadmin import PlaceholderAdminMixin
-from .cms_models import CMSIntegration
+from cms.extensions import PageExtensionAdmin
+from .cms_models import CMSIntegration, CMSFaviconExtension
+from .models import VMPricing
class CMSIntegrationAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
list_display = ('name', 'domain')
+class CMSFaviconExtensionAdmin(PageExtensionAdmin):
+ pass
+
+
admin.site.register(CMSIntegration, CMSIntegrationAdmin)
+admin.site.register(CMSFaviconExtension, CMSFaviconExtensionAdmin)
+admin.site.register(VMPricing)
diff --git a/datacenterlight/cms_models.py b/datacenterlight/cms_models.py
index 9eb55e0c..dd6a165f 100644
--- a/datacenterlight/cms_models.py
+++ b/datacenterlight/cms_models.py
@@ -1,11 +1,16 @@
+from cms.extensions import PageExtension
+from cms.extensions.extension_pool import extension_pool
from cms.models.fields import PlaceholderField
from cms.models.pluginmodel import CMSPlugin
from django.contrib.sites.models import Site
from django.db import models
from django.utils.safestring import mark_safe
from djangocms_text_ckeditor.fields import HTMLField
+from filer.fields.file import FilerFileField
from filer.fields.image import FilerImageField
+from datacenterlight.models import VMPricing
+
class CMSIntegration(models.Model):
name = models.CharField(
@@ -30,9 +35,15 @@ class CMSIntegration(models.Model):
return self.name
-# Models for CMS Plugins
+class CMSFaviconExtension(PageExtension):
+ favicon = FilerFileField(related_name="cms_favicon_image")
+extension_pool.register(CMSFaviconExtension)
+
+
+# Models for CMS Plugins
+
class DCLSectionPluginModel(CMSPlugin):
heading = models.CharField(
blank=True, null=True, max_length=100,
@@ -275,3 +286,12 @@ class DCLSectionPromoPluginModel(CMSPlugin):
if self.background_image:
extra_classes += ' promo-with-bg'
return extra_classes
+
+
+class DCLCustomPricingModel(CMSPlugin):
+ pricing = models.ForeignKey(
+ VMPricing,
+ related_name="dcl_custom_pricing_vm_pricing",
+ help_text='Choose a pricing that will be associated with this '
+ 'Calculator'
+ )
diff --git a/datacenterlight/cms_plugins.py b/datacenterlight/cms_plugins.py
index a1a3833d..19dc0b39 100644
--- a/datacenterlight/cms_plugins.py
+++ b/datacenterlight/cms_plugins.py
@@ -6,9 +6,9 @@ from .cms_models import (
DCLFooterPluginModel, DCLLinkPluginModel, DCLNavbarDropdownPluginModel,
DCLSectionIconPluginModel, DCLSectionImagePluginModel,
DCLSectionPluginModel, DCLNavbarPluginModel,
- DCLSectionPromoPluginModel
+ DCLSectionPromoPluginModel, DCLCustomPricingModel
)
-from .models import VMTemplate
+from .models import VMTemplate, VMPricing
@plugin_pool.register_plugin
@@ -75,13 +75,13 @@ class DCLSectionPromoPlugin(CMSPluginBase):
@plugin_pool.register_plugin
class DCLCalculatorPlugin(CMSPluginBase):
module = "Datacenterlight"
- name = "DCL Calculator Plugin"
+ name = "DCL Calculator Section Plugin"
model = DCLSectionPluginModel
render_template = "datacenterlight/cms/calculator.html"
cache = False
allow_children = True
child_classes = [
- 'DCLSectionPromoPlugin', 'UngleichHTMLPlugin'
+ 'DCLSectionPromoPlugin', 'UngleichHTMLPlugin', 'DCLCustomPricingPlugin'
]
def render(self, context, instance, placeholder):
@@ -89,15 +89,38 @@ class DCLCalculatorPlugin(CMSPluginBase):
context, instance, placeholder
)
context['templates'] = VMTemplate.objects.all()
- context['children_to_side'] = []
context['children_to_content'] = []
+ pricing_plugin_model = None
if instance.child_plugin_instances is not None:
context['children_to_content'].extend(
instance.child_plugin_instances
)
+ for child in instance.child_plugin_instances:
+ if child.__class__.__name__ == 'DCLCustomPricingModel':
+ # The second clause is just to make sure we pick up the
+ # most recent CustomPricing, if more than one is present
+ if (pricing_plugin_model is None or child.pricing_id >
+ pricing_plugin_model.model.pricing_id):
+ pricing_plugin_model = child
+
+ if pricing_plugin_model:
+ context['vm_pricing'] = VMPricing.get_vm_pricing_by_name(
+ name=pricing_plugin_model.pricing.name
+ )
+ else:
+ context['vm_pricing'] = VMPricing.get_default_pricing()
+
return context
+@plugin_pool.register_plugin
+class DCLCustomPricingPlugin(CMSPluginBase):
+ module = "Datacenterlight"
+ name = "DCL Custom Pricing Plugin"
+ model = DCLCustomPricingModel
+ render_plugin = False
+
+
@plugin_pool.register_plugin
class DCLBannerListPlugin(CMSPluginBase):
module = "Datacenterlight"
diff --git a/datacenterlight/cms_toolbar.py b/datacenterlight/cms_toolbar.py
new file mode 100644
index 00000000..15a8cb4b
--- /dev/null
+++ b/datacenterlight/cms_toolbar.py
@@ -0,0 +1,24 @@
+from cms.extensions.toolbar import ExtensionToolbar
+from cms.toolbar_pool import toolbar_pool
+from django.utils.translation import ugettext_lazy as _
+
+from .cms_models import CMSFaviconExtension
+
+
+@toolbar_pool.register
+class CMSFaviconExtensionToolbar(ExtensionToolbar):
+ # defineds the model for the current toolbar
+ model = CMSFaviconExtension
+
+ def populate(self):
+ # setup the extension toolbar with permissions and sanity checks
+ current_page_menu = self._setup_extension_toolbar()
+ # if it's all ok
+ if current_page_menu:
+ # retrieves the instance of the current extension (if any) and the toolbar item url
+ page_extension, url = self.get_page_extension_admin()
+ if url:
+ # adds a toolbar item
+ current_page_menu.add_modal_item(
+ _('CMS Favicon'), url=url, disabled=not self.toolbar.edit_mode
+ )
diff --git a/datacenterlight/locale/de/LC_MESSAGES/django.po b/datacenterlight/locale/de/LC_MESSAGES/django.po
index 5942573b..50dbfbe8 100644
--- a/datacenterlight/locale/de/LC_MESSAGES/django.po
+++ b/datacenterlight/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-03-30 21:29+0000\n"
+"POT-Creation-Date: 2018-04-17 19:26+0000\n"
"PO-Revision-Date: 2018-03-30 23:22+0000\n"
"Last-Translator: b'Anonymous User
We grew up with it, live by it, and believe in it.
The "
-"more we work on our data center,
the more we contribute back to the FOSS"
-" community."
+"more we work on our data center,
the more we contribute back to the FOSS "
+"community."
msgstr ""
"Data Center Light ist ein Teil der Free und Opens Source Software (FOSS) "
-"Bewegung.
Wir sind damit gross geworden, leben damit und glauben "
-"daran.
Je weiter wir mit unserem Data Center Light vorankommen, desto "
-"mehr können wir etwas an die FOSS Community zurückgeben."
+"Bewegung.
Wir sind damit gross geworden, leben damit und glauben daran."
+"
Je weiter wir mit unserem Data Center Light vorankommen, desto mehr "
+"können wir etwas an die FOSS Community zurückgeben."
msgid "We bring the future to you."
msgstr "Wir bringen die Zukunft zu dir."
msgid ""
"Data Center Light uses the most modern technologies out there.
Your VM "
-"needs only IPv6. Data Center Light provides
transparent two-way "
-"IPv6/IPv4 translation."
+"needs only IPv6. Data Center Light provides
transparent two-way IPv6/"
+"IPv4 translation."
msgstr ""
"Data Center Light verwendet die zur Zeit modernsten Technologien.
Deine "
-"VM läuft mit IPv6. Data Center Light bietet eine transparente "
-"IPv6/IPv4-Zweiweglösung."
+"VM läuft mit IPv6. Data Center Light bietet eine transparente IPv6/IPv4-"
+"Zweiweglösung."
msgid ""
" No more spinning metal plates! Data Center Light uses only SSDs. We keep "
@@ -497,6 +499,10 @@ msgstr "Ungültige RAM-Grösse"
msgid "Invalid storage size"
msgstr "Ungültige Speicher-Grösse"
+#, python-brace-format
+msgid "Incorrect pricing name. Please contact support{support_email}"
+msgstr ""
+
msgid "Confirm Order"
msgstr "Bestellung Bestätigen"
@@ -507,8 +513,8 @@ msgid ""
"There was a payment related error. On close of this popup, you will be "
"redirected back to the payment page."
msgstr ""
-"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom"
-" Popup zur Bezahlseite weitergeleitet."
+"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom "
+"Popup zur Bezahlseite weitergeleitet."
msgid "Thank you for the order."
msgstr "Danke für Deine Bestellung."
@@ -517,8 +523,14 @@ msgid ""
"Your VM will be up and running in a few moments. We will send you a "
"confirmation email as soon as it is ready."
msgstr ""
-"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du"
-" auf sie zugreifen kannst."
+"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
+"auf sie zugreifen kannst."
+
+#~ msgid "Pricing"
+#~ msgstr "Preise"
+
+#~ msgid "Order VM"
+#~ msgstr "VM bestellen"
#~ msgid "Enter name"
#~ msgstr "Name"
@@ -533,18 +545,19 @@ msgstr ""
#~ msgstr "Anfrage verschickt"
#~ msgid ""
-#~ "Thank you for your subscription! You will receive a confirmation mail from "
-#~ "our team"
+#~ "Thank you for your subscription! You will receive a confirmation mail "
+#~ "from our team"
#~ msgstr ""
-#~ "Vielen dank für Ihre Anmeldung. Sie erhalten in kürze eine Bestätigungsmail "
-#~ "von unserem Team"
+#~ "Vielen dank für Ihre Anmeldung. Sie erhalten in kürze eine "
+#~ "Bestätigungsmail von unserem Team"
#~ msgid "Thank you for your request."
#~ msgstr "Vielen Dank für Deine Anfrage."
#~ msgid "You are one step away from being our beta tester!"
#~ msgstr ""
-#~ "Sie sind nur noch einen Schritt davon entfernt, unser Beta-Tester zu werden!"
+#~ "Sie sind nur noch einen Schritt davon entfernt, unser Beta-Tester zu "
+#~ "werden!"
#~ msgid ""
#~ "Currently we are running our tests to make sure everything runs perfectly."
@@ -553,8 +566,8 @@ msgstr ""
#~ "sicherzustellen."
#~ msgid ""
-#~ "In the meantime, we would like to ask you a little patience
until our "
-#~ "team contacts you with beta access."
+#~ "In the meantime, we would like to ask you a little patience
until "
+#~ "our team contacts you with beta access."
#~ msgstr ""
#~ "Wir werden dann sobald als möglich Ihren Beta-Zugang erstellen und Sie "
#~ "daraufhin kontaktieren.Bis dahin bitten wir Sie um etwas Geduld."
@@ -564,8 +577,8 @@ msgstr ""
#~ msgid "Thank you for order! Our team will contact you via email"
#~ msgstr ""
-#~ "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit"
-#~ " Dir via E-Mail in Verbindung."
+#~ "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich "
+#~ "mit Dir via E-Mail in Verbindung."
#~ msgid "Affordable VM hosting based in Switzerland"
#~ msgstr "Bezahlbares VM Hosting in der Schweiz"
@@ -581,18 +594,18 @@ msgstr ""
#~ msgid ""
#~ "Our VMs are hosted in Glarus, Switzerland, and our website is currently "
-#~ "running in BETA mode. If you want more information that you did not find on "
-#~ "our website, or if your order is more detailed, or if you encounter any "
-#~ "technical hiccups, please contact us at support@datacenterlight.ch, our team"
-#~ " will get in touch with you asap."
+#~ "running in BETA mode. If you want more information that you did not find "
+#~ "on our website, or if your order is more detailed, or if you encounter "
+#~ "any technical hiccups, please contact us at support@datacenterlight.ch, "
+#~ "our team will get in touch with you asap."
#~ msgstr ""
-#~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden sich"
-#~ " zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren und "
-#~ "hast auf unserer Website nicht genügend Informationen gefunden? Möchtest "
-#~ "eine detailliertere Bestellung aufgeben? Bist du auf technische Probleme "
-#~ "gestossen, die du uns mitteilen möchtest? Dann zögere nicht und kontaktiere "
-#~ "uns unter support@datacenterlight.ch. Unser Team wird sich umgehend um dein "
-#~ "Anliegen kümmern!"
+#~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden "
+#~ "sich zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren "
+#~ "und hast auf unserer Website nicht genügend Informationen gefunden? "
+#~ "Möchtest eine detailliertere Bestellung aufgeben? Bist du auf technische "
+#~ "Probleme gestossen, die du uns mitteilen möchtest? Dann zögere nicht und "
+#~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich "
+#~ "umgehend um dein Anliegen kümmern!"
#~ msgid "is not a proper name"
#~ msgstr "ist kein gültiger Name"
@@ -610,12 +623,14 @@ msgstr ""
#~ "\n"
#~ "Hi,\n"
#~ "\n"
-#~ "You can activate your %(dcl_text)s account by clicking here %(base_url)s%(activation_link)s\n"
+#~ "You can activate your %(dcl_text)s account by clicking here %(base_url)s"
+#~ "%(activation_link)s\n"
#~ msgstr ""
#~ "\n"
#~ "Hallo,\n"
#~ "\n"
-#~ "Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst %(base_url)s%(activation_link)s\n"
+#~ "Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst "
+#~ "%(base_url)s%(activation_link)s\n"
#~ msgid "Your"
#~ msgstr "Dein"
@@ -650,12 +665,14 @@ msgstr ""
#~ msgid "I want to have it!"
#~ msgstr "Das möchte ich haben!"
-#~ msgid "Reuse existing factory halls intead of building an expensive building."
+#~ msgid ""
+#~ "Reuse existing factory halls intead of building an expensive building."
#~ msgstr ""
#~ "Nachhaltigkeit: Wiederverwendung ehemaliger Fabrikhallen an Stelle der "
#~ "Errichtung eines neuen Gebäudes"
-#~ msgid "Being creative, using modern and alternative design for a datacenter."
+#~ msgid ""
+#~ "Being creative, using modern and alternative design for a datacenter."
#~ msgstr ""
#~ "Kreativität: Verwendung eines modernen und alternativen Designs für unser "
#~ "Datencenter"
@@ -678,8 +695,8 @@ msgstr ""
#~ msgstr "Standort des Datacenters ist in der Schweiz"
#~ msgid ""
-#~ " WARNING: We are currently running in BETA mode. We hope you won't encounter"
-#~ " any hiccups, but if you do, please let us know at "
+#~ " WARNING: We are currently running in BETA mode. We hope you won't "
+#~ "encounter any hiccups, but if you do, please let us know at "
#~ "support@datacenterlight.ch"
#~ msgstr ""
#~ " Achtung: Wir befinden uns zurzeit im Beta-Release. Wir hoffen, dass Sie "
@@ -693,8 +710,8 @@ msgstr ""
#~ msgstr "Unser Versprechen"
#~ msgid ""
-#~ "Instead of creating an expensive SLA for availability, we promise that we do"
-#~ " our best to run things as smooth as possible."
+#~ "Instead of creating an expensive SLA for availability, we promise that we "
+#~ "do our best to run things as smooth as possible."
#~ msgstr ""
#~ "Anstatt eines SLAs (Service Levle Agreements) zu vereinbaren,setzen wir "
#~ "unsere persönliche Arbeitskraft ein, um Ihnen ein sorgenfreiesHosting zu "
diff --git a/datacenterlight/management/commands/create_default_vm_pricing.py b/datacenterlight/management/commands/create_default_vm_pricing.py
new file mode 100644
index 00000000..c1b36eea
--- /dev/null
+++ b/datacenterlight/management/commands/create_default_vm_pricing.py
@@ -0,0 +1,36 @@
+from django.core.management.base import BaseCommand
+
+from datacenterlight.models import VMPricing
+
+
+class Command(BaseCommand):
+ help = '''Creates default VMPricing object'''
+ DEFAULT_VMPRICING_NAME = 'default'
+
+ def handle(self, *args, **options):
+ self.create_default_vm_pricing()
+
+ def create_default_vm_pricing(self):
+ obj, created = VMPricing.objects.get_or_create(
+ name=self.DEFAULT_VMPRICING_NAME,
+ defaults={
+ "vat_inclusive": True,
+ "cores_unit_price": 5,
+ "ram_unit_price": 2,
+ "ssd_unit_price": 0.6,
+ "hdd_unit_price": 0.01
+ }
+ )
+
+ if created:
+ print(
+ 'Successfully created {} VMPricing object'.format(
+ self.DEFAULT_VMPRICING_NAME
+ )
+ )
+ else:
+ print(
+ '{} VMPricing exists already.'.format(
+ self.DEFAULT_VMPRICING_NAME
+ )
+ )
diff --git a/datacenterlight/migrations/0019_auto_20180415_2236.py b/datacenterlight/migrations/0019_auto_20180415_2236.py
new file mode 100644
index 00000000..4b711a2b
--- /dev/null
+++ b/datacenterlight/migrations/0019_auto_20180415_2236.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-04-15 22:36
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cms', '0014_auto_20160404_1908'),
+ ('datacenterlight', '0018_auto_20180403_1930'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='DCLCustomPricingModel',
+ fields=[
+ ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('cms.cmsplugin',),
+ ),
+ migrations.CreateModel(
+ name='VMPricing',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255, unique=True)),
+ ('vat_inclusive', models.BooleanField(default=True)),
+ ('vat_percentage', models.DecimalField(blank=True, decimal_places=5, default=0, max_digits=7)),
+ ('cores_unit_price', models.DecimalField(decimal_places=5, default=0, max_digits=7)),
+ ('ram_unit_price', models.DecimalField(decimal_places=5, default=0, max_digits=7)),
+ ('ssd_unit_price', models.DecimalField(decimal_places=5, default=0, max_digits=7)),
+ ('hdd_unit_price', models.DecimalField(decimal_places=6, default=0, max_digits=7)),
+ ],
+ ),
+ migrations.AddField(
+ model_name='dclcustompricingmodel',
+ name='pricing',
+ field=models.ForeignKey(help_text='Choose a pricing that will be associated with this Calculator', on_delete=django.db.models.deletion.CASCADE, related_name='dcl_custom_pricing_vm_pricing', to='datacenterlight.VMPricing'),
+ ),
+ ]
diff --git a/datacenterlight/migrations/0019_cmsfaviconextension.py b/datacenterlight/migrations/0019_cmsfaviconextension.py
new file mode 100644
index 00000000..7b350a70
--- /dev/null
+++ b/datacenterlight/migrations/0019_cmsfaviconextension.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-04-12 03:16
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import filer.fields.file
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('datacenterlight', '0018_auto_20180403_1930'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CMSFaviconExtension',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('extended_object', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='cms.Page')),
+ ('favicon', filer.fields.file.FilerFileField(on_delete=django.db.models.deletion.CASCADE, related_name='cms_favicon_image', to='filer.File')),
+ ('public_extension', models.OneToOneField(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='draft_extension', to='datacenterlight.CMSFaviconExtension')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ ]
diff --git a/datacenterlight/migrations/0020_merge.py b/datacenterlight/migrations/0020_merge.py
new file mode 100644
index 00000000..6bbe0086
--- /dev/null
+++ b/datacenterlight/migrations/0020_merge.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-04-20 15:04
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('datacenterlight', '0019_auto_20180415_2236'),
+ ('datacenterlight', '0019_cmsfaviconextension'),
+ ]
+
+ operations = [
+ ]
diff --git a/datacenterlight/models.py b/datacenterlight/models.py
index 6fcf24a9..eceb7617 100644
--- a/datacenterlight/models.py
+++ b/datacenterlight/models.py
@@ -1,5 +1,9 @@
+import logging
+
from django.db import models
+logger = logging.getLogger(__name__)
+
class VMTemplate(models.Model):
name = models.CharField(max_length=50)
@@ -12,6 +16,59 @@ class VMTemplate(models.Model):
return vm_template
+class VMPricing(models.Model):
+ name = models.CharField(max_length=255, unique=True)
+ vat_inclusive = models.BooleanField(default=True)
+ vat_percentage = models.DecimalField(
+ max_digits=7, decimal_places=5, blank=True, default=0
+ )
+ cores_unit_price = models.DecimalField(
+ max_digits=7, decimal_places=5, default=0
+ )
+ ram_unit_price = models.DecimalField(
+ max_digits=7, decimal_places=5, default=0
+ )
+ ssd_unit_price = models.DecimalField(
+ max_digits=7, decimal_places=5, default=0
+ )
+ hdd_unit_price = models.DecimalField(
+ max_digits=7, decimal_places=6, default=0
+ )
+
+ def __str__(self):
+ return self.name + ' => ' + ' - '.join([
+ '{}/Core'.format(self.cores_unit_price.normalize()),
+ '{}/GB RAM'.format(self.ram_unit_price.normalize()),
+ '{}/GB SSD'.format(self.ssd_unit_price.normalize()),
+ '{}/GB HDD'.format(self.hdd_unit_price.normalize()),
+ '{}% VAT'.format(self.vat_percentage.normalize())
+ if not self.vat_inclusive else 'VAT-Incl', ]
+ )
+
+ @classmethod
+ def get_vm_pricing_by_name(cls, name):
+ try:
+ pricing = VMPricing.objects.get(name=name)
+ except Exception as e:
+ logger.error(
+ "Error getting VMPricing with name {name}. "
+ "Details: {details}. Attempting to return default"
+ "pricing.".format(name=name, details=str(e))
+ )
+ pricing = VMPricing.get_default_pricing()
+ return pricing
+
+ @classmethod
+ def get_default_pricing(cls):
+ """ Returns the default pricing or None """
+ try:
+ default_pricing = VMPricing.objects.get(name='default')
+ except Exception as e:
+ logger.error(str(e))
+ default_pricing = None
+ return default_pricing
+
+
class StripePlan(models.Model):
"""
A model to store Data Center Light's created Stripe plans
diff --git a/datacenterlight/static/datacenterlight/css/header-slider.css b/datacenterlight/static/datacenterlight/css/header-slider.css
index e21e2b49..d01f02a7 100644
--- a/datacenterlight/static/datacenterlight/css/header-slider.css
+++ b/datacenterlight/static/datacenterlight/css/header-slider.css
@@ -120,6 +120,11 @@
.header_slider .intro-cap {
font-size: 3.25em;
}
+
+ .header_slider > .carousel .item .container {
+ padding-left: 0;
+ padding-right: 0;
+ }
}
.header_slider .intro_lead {
diff --git a/datacenterlight/static/datacenterlight/js/main.js b/datacenterlight/static/datacenterlight/js/main.js
index 6753695c..35f2b247 100644
--- a/datacenterlight/static/datacenterlight/js/main.js
+++ b/datacenterlight/static/datacenterlight/js/main.js
@@ -171,7 +171,18 @@
}
function _calcPricing() {
- var total = (cardPricing['cpu'].value * 5) + (2 * cardPricing['ram'].value) + (0.6 * cardPricing['storage'].value);
+ if(typeof window.coresUnitPrice === 'undefined'){
+ window.coresUnitPrice = 5;
+ }
+ if(typeof window.ramUnitPrice === 'undefined'){
+ window.coresUnitPrice = 2;
+ }
+ if(typeof window.ssdUnitPrice === 'undefined'){
+ window.ssdUnitPrice = 0.6;
+ }
+ var total = (cardPricing['cpu'].value * window.coresUnitPrice) +
+ (cardPricing['ram'].value * window.ramUnitPrice) +
+ (cardPricing['storage'].value * window.ssdUnitPrice);
total = parseFloat(total.toFixed(2));
$("#total").text(total);
}
diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py
index 815d627d..66a91917 100644
--- a/datacenterlight/tasks.py
+++ b/datacenterlight/tasks.py
@@ -18,6 +18,8 @@ from utils.hosting_utils import get_all_public_keys, get_or_create_vm_detail
from utils.mailer import BaseEmail
from utils.stripe_utils import StripeUtils
+from .models import VMPricing
+
logger = get_task_logger(__name__)
@@ -53,6 +55,11 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
"Running create_vm_task on {}".format(current_task.request.hostname))
vm_id = None
try:
+ final_price = (
+ specs.get('total_price') if 'total_price' in specs
+ else specs.get('price')
+ )
+
if 'pass' in user:
on_user = user.get('email')
on_pass = user.get('pass')
@@ -110,8 +117,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
if result.get('error') is not None:
emsg = "Could not update subscription metadata for {sub}".format(
- sub=hosting_order.subscription_id
- )
+ sub=hosting_order.subscription_id
+ )
logger.error(emsg)
if error_msg:
error_msg += emsg
@@ -126,7 +133,7 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
'cores': specs.get('cpu'),
'memory': specs.get('memory'),
'storage': specs.get('disk_size'),
- 'price': specs.get('price'),
+ 'price': final_price,
'template': template.get('name'),
'vm_name': vm.get('name'),
'vm_id': vm['vm_id'],
@@ -135,6 +142,10 @@ def create_vm_task(self, vm_template_id, user, specs, template, order_id):
if error_msg:
context['errors'] = error_msg
+ if 'pricing_name' in specs:
+ context['pricing'] = str(VMPricing.get_vm_pricing_by_name(
+ name=specs['pricing_name']
+ ))
email_data = {
'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
diff --git a/datacenterlight/templates/datacenterlight/cms/base.html b/datacenterlight/templates/datacenterlight/cms/base.html
index 0c356735..942a0ad4 100644
--- a/datacenterlight/templates/datacenterlight/cms/base.html
+++ b/datacenterlight/templates/datacenterlight/cms/base.html
@@ -8,9 +8,9 @@
-
+
- {% page_attribute page_title %}
+ {% page_attribute "page_title" %}
+ {% trans "Subtotal" %}: + {{vm.price|floatformat:2|intcomma}} CHF +
++ {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%): + {{vm.vat|floatformat:2|intcomma}} CHF +
+ {% endif %}- {% trans "Total" %} - {{vm.price|intcomma}} CHF + {% trans "Total" %} + {{vm.total_price|floatformat:2|intcomma}} CHF
@@ -78,7 +88,7 @@ {% csrf_token %}