merge master
This commit is contained in:
		
				commit
				
					
						275ea47e41
					
				
			
		
					 32 changed files with 530 additions and 125 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -42,3 +42,4 @@ secret-key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# to keep empty dirs
 | 
					# to keep empty dirs
 | 
				
			||||||
!.gitkeep
 | 
					!.gitkeep
 | 
				
			||||||
 | 
					*.orig
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,7 @@
 | 
				
			||||||
 | 
					next:
 | 
				
			||||||
 | 
					    * 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
 | 
				
			||||||
1.6.5: 2018-04-08
 | 
					1.6.5: 2018-04-08
 | 
				
			||||||
    * #4396: [ungleich] add favicon to ungleich blog
 | 
					    * #4396: [ungleich] add favicon to ungleich blog
 | 
				
			||||||
    * #4327: [dcl] fix navbar logo repeat
 | 
					    * #4327: [dcl] fix navbar logo repeat
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ from django.contrib import admin
 | 
				
			||||||
from cms.admin.placeholderadmin import PlaceholderAdminMixin
 | 
					from cms.admin.placeholderadmin import PlaceholderAdminMixin
 | 
				
			||||||
from cms.extensions import PageExtensionAdmin
 | 
					from cms.extensions import PageExtensionAdmin
 | 
				
			||||||
from .cms_models import CMSIntegration, CMSFaviconExtension
 | 
					from .cms_models import CMSIntegration, CMSFaviconExtension
 | 
				
			||||||
 | 
					from .models import VMPricing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CMSIntegrationAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
 | 
					class CMSIntegrationAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
 | 
				
			||||||
| 
						 | 
					@ -14,3 +15,4 @@ class CMSFaviconExtensionAdmin(PageExtensionAdmin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
admin.site.register(CMSIntegration, CMSIntegrationAdmin)
 | 
					admin.site.register(CMSIntegration, CMSIntegrationAdmin)
 | 
				
			||||||
admin.site.register(CMSFaviconExtension, CMSFaviconExtensionAdmin)
 | 
					admin.site.register(CMSFaviconExtension, CMSFaviconExtensionAdmin)
 | 
				
			||||||
 | 
					admin.site.register(VMPricing)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,8 @@ from djangocms_text_ckeditor.fields import HTMLField
 | 
				
			||||||
from filer.fields.file import FilerFileField
 | 
					from filer.fields.file import FilerFileField
 | 
				
			||||||
from filer.fields.image import FilerImageField
 | 
					from filer.fields.image import FilerImageField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datacenterlight.models import VMPricing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CMSIntegration(models.Model):
 | 
					class CMSIntegration(models.Model):
 | 
				
			||||||
    name = models.CharField(
 | 
					    name = models.CharField(
 | 
				
			||||||
| 
						 | 
					@ -284,3 +286,12 @@ class DCLSectionPromoPluginModel(CMSPlugin):
 | 
				
			||||||
        if self.background_image:
 | 
					        if self.background_image:
 | 
				
			||||||
            extra_classes += ' promo-with-bg'
 | 
					            extra_classes += ' promo-with-bg'
 | 
				
			||||||
        return extra_classes
 | 
					        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'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,9 +6,9 @@ from .cms_models import (
 | 
				
			||||||
    DCLFooterPluginModel, DCLLinkPluginModel, DCLNavbarDropdownPluginModel,
 | 
					    DCLFooterPluginModel, DCLLinkPluginModel, DCLNavbarDropdownPluginModel,
 | 
				
			||||||
    DCLSectionIconPluginModel, DCLSectionImagePluginModel,
 | 
					    DCLSectionIconPluginModel, DCLSectionImagePluginModel,
 | 
				
			||||||
    DCLSectionPluginModel, DCLNavbarPluginModel,
 | 
					    DCLSectionPluginModel, DCLNavbarPluginModel,
 | 
				
			||||||
    DCLSectionPromoPluginModel
 | 
					    DCLSectionPromoPluginModel, DCLCustomPricingModel
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .models import VMTemplate
 | 
					from .models import VMTemplate, VMPricing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@plugin_pool.register_plugin
 | 
					@plugin_pool.register_plugin
 | 
				
			||||||
| 
						 | 
					@ -75,13 +75,13 @@ class DCLSectionPromoPlugin(CMSPluginBase):
 | 
				
			||||||
@plugin_pool.register_plugin
 | 
					@plugin_pool.register_plugin
 | 
				
			||||||
class DCLCalculatorPlugin(CMSPluginBase):
 | 
					class DCLCalculatorPlugin(CMSPluginBase):
 | 
				
			||||||
    module = "Datacenterlight"
 | 
					    module = "Datacenterlight"
 | 
				
			||||||
    name = "DCL Calculator Plugin"
 | 
					    name = "DCL Calculator Section Plugin"
 | 
				
			||||||
    model = DCLSectionPluginModel
 | 
					    model = DCLSectionPluginModel
 | 
				
			||||||
    render_template = "datacenterlight/cms/calculator.html"
 | 
					    render_template = "datacenterlight/cms/calculator.html"
 | 
				
			||||||
    cache = False
 | 
					    cache = False
 | 
				
			||||||
    allow_children = True
 | 
					    allow_children = True
 | 
				
			||||||
    child_classes = [
 | 
					    child_classes = [
 | 
				
			||||||
        'DCLSectionPromoPlugin', 'UngleichHTMLPlugin'
 | 
					        'DCLSectionPromoPlugin', 'UngleichHTMLPlugin', 'DCLCustomPricingPlugin'
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def render(self, context, instance, placeholder):
 | 
					    def render(self, context, instance, placeholder):
 | 
				
			||||||
| 
						 | 
					@ -89,15 +89,38 @@ class DCLCalculatorPlugin(CMSPluginBase):
 | 
				
			||||||
            context, instance, placeholder
 | 
					            context, instance, placeholder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        context['templates'] = VMTemplate.objects.all()
 | 
					        context['templates'] = VMTemplate.objects.all()
 | 
				
			||||||
        context['children_to_side'] = []
 | 
					 | 
				
			||||||
        context['children_to_content'] = []
 | 
					        context['children_to_content'] = []
 | 
				
			||||||
 | 
					        pricing_plugin_model = None
 | 
				
			||||||
        if instance.child_plugin_instances is not None:
 | 
					        if instance.child_plugin_instances is not None:
 | 
				
			||||||
            context['children_to_content'].extend(
 | 
					            context['children_to_content'].extend(
 | 
				
			||||||
                instance.child_plugin_instances
 | 
					                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
 | 
					        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
 | 
					@plugin_pool.register_plugin
 | 
				
			||||||
class DCLBannerListPlugin(CMSPluginBase):
 | 
					class DCLBannerListPlugin(CMSPluginBase):
 | 
				
			||||||
    module = "Datacenterlight"
 | 
					    module = "Datacenterlight"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
					"Project-Id-Version: PACKAGE VERSION\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: \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"
 | 
					"PO-Revision-Date: 2018-03-30 23:22+0000\n"
 | 
				
			||||||
"Last-Translator: b'Anonymous User <coder.purple+25@gmail.com>'\n"
 | 
					"Last-Translator: b'Anonymous User <coder.purple+25@gmail.com>'\n"
 | 
				
			||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
					"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
				
			||||||
| 
						 | 
					@ -72,9 +72,9 @@ msgstr "Data Center Light Account Aktivierung"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"You can activate your Data Center Light account by clicking <a "
 | 
					"You can activate your Data Center Light account by clicking <a href="
 | 
				
			||||||
"href=\"%(base_url)s%(activation_link)s\" style=\"text-decoration: none; "
 | 
					"\"%(base_url)s%(activation_link)s\" style=\"text-decoration: none; color: "
 | 
				
			||||||
"color: #4382c8; font-weight: 400;\">here</a>."
 | 
					"#4382c8; font-weight: 400;\">here</a>."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Klicke <a href=\"%(base_url)s%(activation_link)s\"style=\"text-decoration: "
 | 
					"Klicke <a href=\"%(base_url)s%(activation_link)s\"style=\"text-decoration: "
 | 
				
			||||||
"none; color: #4382c8; font-weight: 400;\">hier</a> um deinen Data Center "
 | 
					"none; color: #4382c8; font-weight: 400;\">hier</a> um deinen Data Center "
 | 
				
			||||||
| 
						 | 
					@ -97,12 +97,13 @@ msgstr "Deine E-Mail-Adresse"
 | 
				
			||||||
msgid "Password"
 | 
					msgid "Password"
 | 
				
			||||||
msgstr "Passwort"
 | 
					msgstr "Passwort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#, python-format
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"You can reset your password <a href=\"%(base_url)s%(reset_password_url)s\" "
 | 
					"You can reset your password <a href=\"%(base_url)s%(reset_password_url)s\" "
 | 
				
			||||||
"style=\"text-decoration: none; color: #4382c8; font-weight: 400;\">here</a>."
 | 
					"style=\"text-decoration: none; color: #4382c8; font-weight: 400;\">here</a>."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Du kannst dein Passwort <a href=\"%(base_url)s%(reset_password_url)s\" "
 | 
					"Du kannst dein Passwort <a href=\"%(base_url)s%(reset_password_url)s\" style="
 | 
				
			||||||
"style=\"text-decoration: none; color: #4382c8; font-weight: 400;\">hier</a> "
 | 
					"\"text-decoration: none; color: #4382c8; font-weight: 400;\">hier</a> "
 | 
				
			||||||
"zurücksetzen."
 | 
					"zurücksetzen."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Your Data Center Light Team"
 | 
					msgid "Your Data Center Light Team"
 | 
				
			||||||
| 
						 | 
					@ -160,21 +161,6 @@ msgstr "Weiter"
 | 
				
			||||||
msgid "Home"
 | 
					msgid "Home"
 | 
				
			||||||
msgstr "Home"
 | 
					msgstr "Home"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Highlights"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Scale out"
 | 
					 | 
				
			||||||
msgstr "Skalierung"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Reliable and light"
 | 
					 | 
				
			||||||
msgstr "Zuverlässig und leicht"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Pricing"
 | 
					 | 
				
			||||||
msgstr "Preise"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Order VM"
 | 
					 | 
				
			||||||
msgstr "VM bestellen"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Contact"
 | 
					msgid "Contact"
 | 
				
			||||||
msgstr "Kontakt"
 | 
					msgstr "Kontakt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,6 +170,9 @@ msgstr "Nutzungsbedingungen"
 | 
				
			||||||
msgid "Finally, an affordable VM hosting in Switzerland!"
 | 
					msgid "Finally, an affordable VM hosting in Switzerland!"
 | 
				
			||||||
msgstr "Endlich: bezahlbares VM Hosting in der Schweiz"
 | 
					msgstr "Endlich: bezahlbares VM Hosting in der Schweiz"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Highlights"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "I want it!"
 | 
					msgid "I want it!"
 | 
				
			||||||
msgstr "Das will ich haben!"
 | 
					msgstr "Das will ich haben!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,8 +192,8 @@ msgid ""
 | 
				
			||||||
"order to make it more sustainable and affordable at the same time."
 | 
					"order to make it more sustainable and affordable at the same time."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Ist kreativ, indem es sich ein modernes und alternatives Layout zu Nutze "
 | 
					"Ist kreativ, indem es sich ein modernes und alternatives Layout zu Nutze "
 | 
				
			||||||
"macht um Nachhaltigkeit zu fördern und somit erschwingliche Preise bieten zu"
 | 
					"macht um Nachhaltigkeit zu fördern und somit erschwingliche Preise bieten zu "
 | 
				
			||||||
" können.
"
 | 
					"können.
"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Cuts down the costs for you by using FOSS (Free Open Source Software) "
 | 
					"Cuts down the costs for you by using FOSS (Free Open Source Software) "
 | 
				
			||||||
| 
						 | 
					@ -214,6 +203,9 @@ msgstr ""
 | 
				
			||||||
"mit FOSS (Free Open Source Software) arbeitet und wir daher auf "
 | 
					"mit FOSS (Free Open Source Software) arbeitet und wir daher auf "
 | 
				
			||||||
"Lizenzgebühren verzichten können.
"
 | 
					"Lizenzgebühren verzichten können.
"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Scale out"
 | 
				
			||||||
 | 
					msgstr "Skalierung"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"We don't use special hardware. We use commodity hardware: we buy computers "
 | 
					"We don't use special hardware. We use commodity hardware: we buy computers "
 | 
				
			||||||
"that you buy. Just many more and put them in a cozy home for computers "
 | 
					"that you buy. Just many more and put them in a cozy home for computers "
 | 
				
			||||||
| 
						 | 
					@ -223,6 +215,9 @@ msgstr ""
 | 
				
			||||||
"erschwingliche Systeme. Bei grösserer Auslastung werden mehr "
 | 
					"erschwingliche Systeme. Bei grösserer Auslastung werden mehr "
 | 
				
			||||||
"Standardkomponenten hinzugekauft und skalieren so das Datencenter."
 | 
					"Standardkomponenten hinzugekauft und skalieren so das Datencenter."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Reliable and light"
 | 
				
			||||||
 | 
					msgstr "Zuverlässig und leicht"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Our VMs are located in Switzerland, with reliable power supply and fast "
 | 
					"Our VMs are located in Switzerland, with reliable power supply and fast "
 | 
				
			||||||
"internet connection. Our VM costs less thanks to our featherlight "
 | 
					"internet connection. Our VM costs less thanks to our featherlight "
 | 
				
			||||||
| 
						 | 
					@ -232,8 +227,7 @@ msgstr ""
 | 
				
			||||||
"Energieversorgung, sowie schneller Internetverbindung ausgestattet. Unser "
 | 
					"Energieversorgung, sowie schneller Internetverbindung ausgestattet. Unser "
 | 
				
			||||||
"Angebot ist aufgrund unserer leichten Infrastruktur überaus kostengünstig."
 | 
					"Angebot ist aufgrund unserer leichten Infrastruktur überaus kostengünstig."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid "Simple and affordable: Try our virtual machine with featherlight price."
 | 
				
			||||||
"Simple and affordable: Try our virtual machine with featherlight price."
 | 
					 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Einfach und bezahlbar: Teste nun unsere virtuellen Maschinen mit "
 | 
					"Einfach und bezahlbar: Teste nun unsere virtuellen Maschinen mit "
 | 
				
			||||||
"federleichten Preisen."
 | 
					"federleichten Preisen."
 | 
				
			||||||
| 
						 | 
					@ -314,6 +308,9 @@ msgstr "Gesamt"
 | 
				
			||||||
msgid "including VAT"
 | 
					msgid "including VAT"
 | 
				
			||||||
msgstr "inkl. Mehrwertsteuer"
 | 
					msgstr "inkl. Mehrwertsteuer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "excluding VAT"
 | 
				
			||||||
 | 
					msgstr "exkl. Mehrwertsteuer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Month"
 | 
					msgid "Month"
 | 
				
			||||||
msgstr "Monat"
 | 
					msgstr "Monat"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,20 +318,20 @@ msgid "Credit Card"
 | 
				
			||||||
msgstr "Kreditkarte"
 | 
					msgstr "Kreditkarte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Please fill in your credit card information below. We are using <a "
 | 
					"Please fill in your credit card information below. We are using <a href="
 | 
				
			||||||
"href=\"https://stripe.com\" target=\"_blank\">Stripe</a> for payment and do "
 | 
					"\"https://stripe.com\" target=\"_blank\">Stripe</a> for payment and do not "
 | 
				
			||||||
"not store your information in our database."
 | 
					"store your information in our database."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Bitte fülle Deine Kreditkarteninformationen unten aus. Wir nutzen <a "
 | 
					"Bitte fülle Deine Kreditkarteninformationen unten aus. Wir nutzen <a href="
 | 
				
			||||||
"href=\"https://stripe.com\" target=\"_blank\">Stripe</a> für die Bezahlung "
 | 
					"\"https://stripe.com\" target=\"_blank\">Stripe</a> für die Bezahlung und "
 | 
				
			||||||
"und speichern keine Informationen in unserer Datenbank."
 | 
					"speichern keine Informationen in unserer Datenbank."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"You are not making any payment yet. After submitting your card information, "
 | 
					"You are not making any payment yet. After submitting your card information, "
 | 
				
			||||||
"you will be taken to the Confirm Order Page."
 | 
					"you will be taken to the Confirm Order Page."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst ausgelöst,"
 | 
					"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst ausgelöst, "
 | 
				
			||||||
" nachdem Du die Bestellung auf der nächsten Seite bestätigt hast."
 | 
					"nachdem Du die Bestellung auf der nächsten Seite bestätigt hast."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Card Number"
 | 
					msgid "Card Number"
 | 
				
			||||||
msgstr "Kreditkartennummer"
 | 
					msgstr "Kreditkartennummer"
 | 
				
			||||||
| 
						 | 
					@ -352,8 +349,8 @@ msgid ""
 | 
				
			||||||
"You are not making any payment yet. After placing your order, you will be "
 | 
					"You are not making any payment yet. After placing your order, you will be "
 | 
				
			||||||
"taken to the Submit Payment Page."
 | 
					"taken to the Submit Payment Page."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst ausgelöst,"
 | 
					"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst ausgelöst, "
 | 
				
			||||||
" nachdem Du die Bestellung auf der nächsten Seite bestätigt hast."
 | 
					"nachdem Du die Bestellung auf der nächsten Seite bestätigt hast."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Processing"
 | 
					msgid "Processing"
 | 
				
			||||||
msgstr "Weiter"
 | 
					msgstr "Weiter"
 | 
				
			||||||
| 
						 | 
					@ -383,13 +380,18 @@ msgstr "Bestellungsübersicht"
 | 
				
			||||||
msgid "Product"
 | 
					msgid "Product"
 | 
				
			||||||
msgstr "Produkt"
 | 
					msgstr "Produkt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#, python-format
 | 
					msgid "Subtotal"
 | 
				
			||||||
 | 
					msgstr "Zwischensumme"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "VAT"
 | 
				
			||||||
 | 
					msgstr "Mehrwertsteuer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"By clicking \"Place order\" this plan will charge your credit card account "
 | 
					"By clicking \"Place order\" this plan will charge your credit card account "
 | 
				
			||||||
"with the fee of %(vm_price)sCHF/month"
 | 
					"with the fee of %(vm_total_price)s CHF/month"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(vm_price)sCHF "
 | 
					"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit "
 | 
				
			||||||
"pro Monat belastet"
 | 
					"%(vm_total_price)s CHF pro Monat belastet"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Place order"
 | 
					msgid "Place order"
 | 
				
			||||||
msgstr "Bestellen"
 | 
					msgstr "Bestellen"
 | 
				
			||||||
| 
						 | 
					@ -455,25 +457,25 @@ msgstr "Wir unterstützen die FOSS Community."
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Data Center Light is the child of free and open source software (FOSS) "
 | 
					"Data Center Light is the child of free and open source software (FOSS) "
 | 
				
			||||||
"movement. <br>We grew up with it, live by it, and believe in it.<br> The "
 | 
					"movement. <br>We grew up with it, live by it, and believe in it.<br> The "
 | 
				
			||||||
"more we work on our data center,<br> the more we contribute back to the FOSS"
 | 
					"more we work on our data center,<br> the more we contribute back to the FOSS "
 | 
				
			||||||
" community."
 | 
					"community."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Data Center Light ist ein Teil der Free und Opens Source Software (FOSS) "
 | 
					"Data Center Light ist ein Teil der Free und Opens Source Software (FOSS) "
 | 
				
			||||||
"Bewegung.<br/> Wir sind damit gross geworden, leben damit und glauben "
 | 
					"Bewegung.<br/> Wir sind damit gross geworden, leben damit und glauben daran."
 | 
				
			||||||
"daran.<br/> Je weiter wir mit unserem Data Center Light vorankommen, desto "
 | 
					"<br/> Je weiter wir mit unserem Data Center Light vorankommen, desto mehr "
 | 
				
			||||||
"mehr können wir etwas an die FOSS Community zurückgeben."
 | 
					"können wir etwas an die FOSS Community zurückgeben."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "We bring the future to you."
 | 
					msgid "We bring the future to you."
 | 
				
			||||||
msgstr "Wir bringen die Zukunft zu dir."
 | 
					msgstr "Wir bringen die Zukunft zu dir."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Data Center Light uses the most modern technologies out there.<br>Your VM "
 | 
					"Data Center Light uses the most modern technologies out there.<br>Your VM "
 | 
				
			||||||
"needs only IPv6. Data Center Light provides<br> transparent two-way "
 | 
					"needs only IPv6. Data Center Light provides<br> transparent two-way IPv6/"
 | 
				
			||||||
"IPv6/IPv4 translation."
 | 
					"IPv4 translation."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Data Center Light verwendet die zur Zeit modernsten Technologien.<br/>Deine "
 | 
					"Data Center Light verwendet die zur Zeit modernsten Technologien.<br/>Deine "
 | 
				
			||||||
"VM läuft mit IPv6. Data Center Light bietet eine transparente "
 | 
					"VM läuft mit IPv6. Data Center Light bietet eine transparente IPv6/IPv4-"
 | 
				
			||||||
"IPv6/IPv4-Zweiweglösung."
 | 
					"Zweiweglösung."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
" No more spinning metal plates! Data Center Light uses only SSDs. We keep "
 | 
					" 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"
 | 
					msgid "Invalid storage size"
 | 
				
			||||||
msgstr "Ungültige Speicher-Grösse"
 | 
					msgstr "Ungültige Speicher-Grösse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#, python-brace-format
 | 
				
			||||||
 | 
					msgid "Incorrect pricing name. Please contact support{support_email}"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Confirm Order"
 | 
					msgid "Confirm Order"
 | 
				
			||||||
msgstr "Bestellung Bestätigen"
 | 
					msgstr "Bestellung Bestätigen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -507,8 +513,8 @@ msgid ""
 | 
				
			||||||
"There was a payment related error. On close of this popup, you will be "
 | 
					"There was a payment related error. On close of this popup, you will be "
 | 
				
			||||||
"redirected back to the payment page."
 | 
					"redirected back to the payment page."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom"
 | 
					"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom "
 | 
				
			||||||
" Popup zur Bezahlseite weitergeleitet."
 | 
					"Popup zur Bezahlseite weitergeleitet."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Thank you for the order."
 | 
					msgid "Thank you for the order."
 | 
				
			||||||
msgstr "Danke für Deine Bestellung."
 | 
					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 "
 | 
					"Your VM will be up and running in a few moments. We will send you a "
 | 
				
			||||||
"confirmation email as soon as it is ready."
 | 
					"confirmation email as soon as it is ready."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du"
 | 
					"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
 | 
				
			||||||
" auf sie zugreifen kannst."
 | 
					"auf sie zugreifen kannst."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#~ msgid "Pricing"
 | 
				
			||||||
 | 
					#~ msgstr "Preise"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#~ msgid "Order VM"
 | 
				
			||||||
 | 
					#~ msgstr "VM bestellen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid "Enter name"
 | 
					#~ msgid "Enter name"
 | 
				
			||||||
#~ msgstr "Name"
 | 
					#~ msgstr "Name"
 | 
				
			||||||
| 
						 | 
					@ -533,18 +545,19 @@ msgstr ""
 | 
				
			||||||
#~ msgstr "Anfrage verschickt"
 | 
					#~ msgstr "Anfrage verschickt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ "Thank you for your subscription! You will receive a confirmation mail from "
 | 
					#~ "Thank you for your subscription! You will receive a confirmation mail "
 | 
				
			||||||
#~ "our team"
 | 
					#~ "from our team"
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Vielen dank für Ihre Anmeldung. Sie erhalten in kürze eine Bestätigungsmail "
 | 
					#~ "Vielen dank für Ihre Anmeldung. Sie erhalten in kürze eine "
 | 
				
			||||||
#~ "von unserem Team"
 | 
					#~ "Bestätigungsmail von unserem Team"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid "Thank you for your request."
 | 
					#~ msgid "Thank you for your request."
 | 
				
			||||||
#~ msgstr "Vielen Dank für Deine Anfrage."
 | 
					#~ msgstr "Vielen Dank für Deine Anfrage."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid "You are one step away from being our beta tester!"
 | 
					#~ msgid "You are one step away from being our beta tester!"
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ 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 ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ "Currently we are running our tests to make sure everything runs perfectly."
 | 
					#~ "Currently we are running our tests to make sure everything runs perfectly."
 | 
				
			||||||
| 
						 | 
					@ -553,8 +566,8 @@ msgstr ""
 | 
				
			||||||
#~ "sicherzustellen."
 | 
					#~ "sicherzustellen."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ "In the meantime, we would like to ask you a little patience<br/> until our "
 | 
					#~ "In the meantime, we would like to ask you a little patience<br/> until "
 | 
				
			||||||
#~ "team contacts you with beta access."
 | 
					#~ "our team contacts you with beta access."
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Wir werden dann sobald als möglich Ihren Beta-Zugang erstellen und Sie "
 | 
					#~ "Wir werden dann sobald als möglich Ihren Beta-Zugang erstellen und Sie "
 | 
				
			||||||
#~ "daraufhin kontaktieren.Bis dahin bitten wir Sie um etwas Geduld."
 | 
					#~ "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"
 | 
					#~ msgid "Thank you for order! Our team will contact you via email"
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit"
 | 
					#~ "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich "
 | 
				
			||||||
#~ " Dir via E-Mail in Verbindung."
 | 
					#~ "mit Dir via E-Mail in Verbindung."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid "Affordable VM hosting based in Switzerland"
 | 
					#~ msgid "Affordable VM hosting based in Switzerland"
 | 
				
			||||||
#~ msgstr "Bezahlbares VM Hosting in der Schweiz"
 | 
					#~ msgstr "Bezahlbares VM Hosting in der Schweiz"
 | 
				
			||||||
| 
						 | 
					@ -581,18 +594,18 @@ msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ "Our VMs are hosted in Glarus, Switzerland, and our website is currently "
 | 
					#~ "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 "
 | 
					#~ "running in BETA mode. If you want more information that you did not find "
 | 
				
			||||||
#~ "our website, or if your order is more detailed, or if you encounter any "
 | 
					#~ "on our website, or if your order is more detailed, or if you encounter "
 | 
				
			||||||
#~ "technical hiccups, please contact us at support@datacenterlight.ch, our team"
 | 
					#~ "any technical hiccups, please contact us at support@datacenterlight.ch, "
 | 
				
			||||||
#~ " will get in touch with you asap."
 | 
					#~ "our team will get in touch with you asap."
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden sich"
 | 
					#~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden "
 | 
				
			||||||
#~ " zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren und "
 | 
					#~ "sich zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren "
 | 
				
			||||||
#~ "hast auf unserer Website nicht genügend Informationen gefunden? Möchtest "
 | 
					#~ "und hast auf unserer Website nicht genügend Informationen gefunden? "
 | 
				
			||||||
#~ "eine detailliertere Bestellung aufgeben? Bist du auf technische Probleme "
 | 
					#~ "Möchtest eine detailliertere Bestellung aufgeben? Bist du auf technische "
 | 
				
			||||||
#~ "gestossen, die du uns mitteilen möchtest? Dann zögere nicht und kontaktiere "
 | 
					#~ "Probleme gestossen, die du uns mitteilen möchtest? Dann zögere nicht und "
 | 
				
			||||||
#~ "uns unter support@datacenterlight.ch. Unser Team wird sich umgehend um dein "
 | 
					#~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich "
 | 
				
			||||||
#~ "Anliegen kümmern!"
 | 
					#~ "umgehend um dein Anliegen kümmern!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid "is not a proper name"
 | 
					#~ msgid "is not a proper name"
 | 
				
			||||||
#~ msgstr "ist kein gültiger Name"
 | 
					#~ msgstr "ist kein gültiger Name"
 | 
				
			||||||
| 
						 | 
					@ -610,12 +623,14 @@ msgstr ""
 | 
				
			||||||
#~ "\n"
 | 
					#~ "\n"
 | 
				
			||||||
#~ "Hi,\n"
 | 
					#~ "Hi,\n"
 | 
				
			||||||
#~ "\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 ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "\n"
 | 
					#~ "\n"
 | 
				
			||||||
#~ "Hallo,\n"
 | 
					#~ "Hallo,\n"
 | 
				
			||||||
#~ "\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"
 | 
					#~ msgid "Your"
 | 
				
			||||||
#~ msgstr "Dein"
 | 
					#~ msgstr "Dein"
 | 
				
			||||||
| 
						 | 
					@ -650,12 +665,14 @@ msgstr ""
 | 
				
			||||||
#~ msgid "I want to have it!"
 | 
					#~ msgid "I want to have it!"
 | 
				
			||||||
#~ msgstr "Das möchte ich haben!"
 | 
					#~ 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 ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Nachhaltigkeit: Wiederverwendung ehemaliger Fabrikhallen an Stelle der "
 | 
					#~ "Nachhaltigkeit: Wiederverwendung ehemaliger Fabrikhallen an Stelle der "
 | 
				
			||||||
#~ "Errichtung eines neuen Gebäudes"
 | 
					#~ "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 ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Kreativität: Verwendung eines modernen und alternativen Designs für unser "
 | 
					#~ "Kreativität: Verwendung eines modernen und alternativen Designs für unser "
 | 
				
			||||||
#~ "Datencenter"
 | 
					#~ "Datencenter"
 | 
				
			||||||
| 
						 | 
					@ -678,8 +695,8 @@ msgstr ""
 | 
				
			||||||
#~ msgstr "Standort des Datacenters ist in der Schweiz"
 | 
					#~ msgstr "Standort des Datacenters ist in der Schweiz"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ " WARNING: We are currently running in BETA mode. We hope you won't encounter"
 | 
					#~ " WARNING: We are currently running in BETA mode. We hope you won't "
 | 
				
			||||||
#~ " any hiccups, but if you do, please let us know at "
 | 
					#~ "encounter any hiccups, but if you do, please let us know at "
 | 
				
			||||||
#~ "support@datacenterlight.ch"
 | 
					#~ "support@datacenterlight.ch"
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ " Achtung: Wir befinden uns zurzeit im Beta-Release. Wir hoffen, dass Sie "
 | 
					#~ " Achtung: Wir befinden uns zurzeit im Beta-Release. Wir hoffen, dass Sie "
 | 
				
			||||||
| 
						 | 
					@ -693,8 +710,8 @@ msgstr ""
 | 
				
			||||||
#~ msgstr "Unser Versprechen"
 | 
					#~ msgstr "Unser Versprechen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#~ msgid ""
 | 
					#~ msgid ""
 | 
				
			||||||
#~ "Instead of creating an expensive SLA for availability, we promise that we do"
 | 
					#~ "Instead of creating an expensive SLA for availability, we promise that we "
 | 
				
			||||||
#~ " our best to run things as smooth as possible."
 | 
					#~ "do our best to run things as smooth as possible."
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
#~ "Anstatt eines SLAs (Service Levle Agreements) zu vereinbaren,setzen wir "
 | 
					#~ "Anstatt eines SLAs (Service Levle Agreements) zu vereinbaren,setzen wir "
 | 
				
			||||||
#~ "unsere persönliche Arbeitskraft ein, um Ihnen ein sorgenfreiesHosting zu "
 | 
					#~ "unsere persönliche Arbeitskraft ein, um Ihnen ein sorgenfreiesHosting zu "
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
							
								
								
									
										45
									
								
								datacenterlight/migrations/0019_auto_20180415_2236.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								datacenterlight/migrations/0019_auto_20180415_2236.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,9 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VMTemplate(models.Model):
 | 
					class VMTemplate(models.Model):
 | 
				
			||||||
    name = models.CharField(max_length=50)
 | 
					    name = models.CharField(max_length=50)
 | 
				
			||||||
| 
						 | 
					@ -12,6 +16,59 @@ class VMTemplate(models.Model):
 | 
				
			||||||
        return vm_template
 | 
					        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):
 | 
					class StripePlan(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    A model to store Data Center Light's created Stripe plans
 | 
					    A model to store Data Center Light's created Stripe plans
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,6 +120,11 @@
 | 
				
			||||||
    .header_slider .intro-cap {
 | 
					    .header_slider .intro-cap {
 | 
				
			||||||
        font-size: 3.25em;
 | 
					        font-size: 3.25em;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .header_slider > .carousel .item .container {
 | 
				
			||||||
 | 
					        padding-left: 0;
 | 
				
			||||||
 | 
					        padding-right: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.header_slider .intro_lead {
 | 
					.header_slider .intro_lead {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1231,6 +1231,15 @@ footer {
 | 
				
			||||||
  background-position: center;
 | 
					  background-position: center;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.promo-section.promo-with-bg a {
 | 
				
			||||||
 | 
					  color: #87B6EA;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.promo-section.promo-with-bg a:hover,
 | 
				
			||||||
 | 
					.promo-section.promo-with-bg a:focus {
 | 
				
			||||||
 | 
					  color: #77a6da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.promo-section h3 {
 | 
					.promo-section h3 {
 | 
				
			||||||
  font-weight: 700;
 | 
					  font-weight: 700;
 | 
				
			||||||
  font-size: 36px;
 | 
					  font-size: 36px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5.8 KiB  | 
| 
						 | 
					@ -171,7 +171,18 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function _calcPricing() {
 | 
					    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 = parseFloat(total.toFixed(2));
 | 
				
			||||||
        $("#total").text(total);
 | 
					        $("#total").text(total);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,8 @@ from utils.forms import UserBillingAddressForm
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
from utils.models import BillingAddress
 | 
					from utils.models import BillingAddress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .models import VMPricing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
logger = get_task_logger(__name__)
 | 
					logger = get_task_logger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +58,8 @@ def create_vm_task(self, vm_template_id, user, specs, template,
 | 
				
			||||||
        "Running create_vm_task on {}".format(current_task.request.hostname))
 | 
					        "Running create_vm_task on {}".format(current_task.request.hostname))
 | 
				
			||||||
    vm_id = None
 | 
					    vm_id = None
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        final_price = specs.get('price')
 | 
					        final_price = (specs.get('total_price') if 'total_price' in specs
 | 
				
			||||||
 | 
					                       else specs.get('price'))
 | 
				
			||||||
        billing_address = BillingAddress(
 | 
					        billing_address = BillingAddress(
 | 
				
			||||||
            cardholder_name=billing_address_data['cardholder_name'],
 | 
					            cardholder_name=billing_address_data['cardholder_name'],
 | 
				
			||||||
            street_address=billing_address_data['street_address'],
 | 
					            street_address=billing_address_data['street_address'],
 | 
				
			||||||
| 
						 | 
					@ -94,17 +97,22 @@ def create_vm_task(self, vm_template_id, user, specs, template,
 | 
				
			||||||
        if vm_id is None:
 | 
					        if vm_id is None:
 | 
				
			||||||
            raise Exception("Could not create VM")
 | 
					            raise Exception("Could not create VM")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vm_pricing = VMPricing.get_vm_pricing_by_name(
 | 
				
			||||||
 | 
					            name=specs['pricing_name']
 | 
				
			||||||
 | 
					        ) if 'pricing_name' in specs else VMPricing.get_default_pricing()
 | 
				
			||||||
        # Create a Hosting Order
 | 
					        # Create a Hosting Order
 | 
				
			||||||
        order = HostingOrder.create(
 | 
					        order = HostingOrder.create(
 | 
				
			||||||
            price=final_price,
 | 
					            price=final_price,
 | 
				
			||||||
            vm_id=vm_id,
 | 
					            vm_id=vm_id,
 | 
				
			||||||
            customer=customer,
 | 
					            customer=customer,
 | 
				
			||||||
            billing_address=billing_address
 | 
					            billing_address=billing_address,
 | 
				
			||||||
 | 
					            vm_pricing=vm_pricing
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create a Hosting Bill
 | 
					        # Create a Hosting Bill
 | 
				
			||||||
        HostingBill.create(
 | 
					        HostingBill.create(
 | 
				
			||||||
            customer=customer, billing_address=billing_address)
 | 
					            customer=customer, billing_address=billing_address
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create Billing Address for User if he does not have one
 | 
					        # Create Billing Address for User if he does not have one
 | 
				
			||||||
        if not customer.user.billing_addresses.count():
 | 
					        if not customer.user.billing_addresses.count():
 | 
				
			||||||
| 
						 | 
					@ -130,12 +138,16 @@ def create_vm_task(self, vm_template_id, user, specs, template,
 | 
				
			||||||
            'cores': specs.get('cpu'),
 | 
					            'cores': specs.get('cpu'),
 | 
				
			||||||
            'memory': specs.get('memory'),
 | 
					            'memory': specs.get('memory'),
 | 
				
			||||||
            'storage': specs.get('disk_size'),
 | 
					            'storage': specs.get('disk_size'),
 | 
				
			||||||
            'price': specs.get('price'),
 | 
					            'price': final_price,
 | 
				
			||||||
            'template': template.get('name'),
 | 
					            'template': template.get('name'),
 | 
				
			||||||
            'vm_name': vm.get('name'),
 | 
					            'vm_name': vm.get('name'),
 | 
				
			||||||
            'vm_id': vm['vm_id'],
 | 
					            'vm_id': vm['vm_id'],
 | 
				
			||||||
            'order_id': order.id
 | 
					            'order_id': order.id
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if 'pricing_name' in specs:
 | 
				
			||||||
 | 
					            context['pricing'] = str(VMPricing.get_vm_pricing_by_name(
 | 
				
			||||||
 | 
					                name=specs['pricing_name']
 | 
				
			||||||
 | 
					            ))
 | 
				
			||||||
        email_data = {
 | 
					        email_data = {
 | 
				
			||||||
            'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
 | 
					            'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
 | 
				
			||||||
            'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
 | 
					            'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@
 | 
				
			||||||
    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
					    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td>
 | 
					            <td>
 | 
				
			||||||
                <img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
 | 
					                <img src="{{ base_url }}{% static 'datacenterlight/img/datacenterlight.png' %}" style="max-width: 200px;">
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@
 | 
				
			||||||
    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
					    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td>
 | 
					            <td>
 | 
				
			||||||
                <img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
 | 
					                <img src="{{ base_url }}{% static 'datacenterlight/img/datacenterlight.png' %}" style="max-width: 200px;">
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,16 @@
 | 
				
			||||||
{% load staticfiles i18n%}
 | 
					{% load staticfiles i18n%}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if vm_pricing %}
 | 
				
			||||||
 | 
					    <script type="application/javascript">
 | 
				
			||||||
 | 
					        window.vat_inclusive = {% if vm_pricing.vat_inclusive %}true{% else %}false{% endif%};
 | 
				
			||||||
 | 
					        window.vat_percentage = {{vm_pricing.vat_percentage|default:0}};
 | 
				
			||||||
 | 
					        window.coresUnitPrice = {{vm_pricing.cores_unit_price|default:0}};
 | 
				
			||||||
 | 
					        window.ramUnitPrice = {{vm_pricing.ram_unit_price|default:0}};
 | 
				
			||||||
 | 
					        window.ssdUnitPrice = {{vm_pricing.ssd_unit_price|default:0}};
 | 
				
			||||||
 | 
					        window.hddUnitPrice = {{vm_pricing.hdd_unit_price|default:0}};
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<form id="order_form" method="POST" action="{% url 'datacenterlight:index' %}" data-toggle="validator" role="form">
 | 
					<form id="order_form" method="POST" action="{% url 'datacenterlight:index' %}" data-toggle="validator" role="form">
 | 
				
			||||||
    {% csrf_token %}
 | 
					    {% csrf_token %}
 | 
				
			||||||
    <div class="title">
 | 
					    <div class="title">
 | 
				
			||||||
| 
						 | 
					@ -7,9 +19,11 @@
 | 
				
			||||||
    <div class="price">
 | 
					    <div class="price">
 | 
				
			||||||
        <span id="total">15</span>
 | 
					        <span id="total">15</span>
 | 
				
			||||||
        <span>CHF/{% trans "month" %}</span>
 | 
					        <span>CHF/{% trans "month" %}</span>
 | 
				
			||||||
 | 
					        {% if vm_pricing.vat_inclusive %}
 | 
				
			||||||
        <div class="price-text">
 | 
					        <div class="price-text">
 | 
				
			||||||
            <p>{% trans "VAT included" %}</p>
 | 
					            <p>{% trans "VAT included" %}</p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="descriptions">
 | 
					    <div class="descriptions">
 | 
				
			||||||
        <div class="description form-group">
 | 
					        <div class="description form-group">
 | 
				
			||||||
| 
						 | 
					@ -78,5 +92,6 @@
 | 
				
			||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					    <input type="hidden" name="pricing_name" value="{% if vm_pricing.name %}{{vm_pricing.name}}{% else %}unknown{% endif%}"></input>
 | 
				
			||||||
    <input type="submit" class="btn btn-primary disabled" value="{% trans 'Continue' %}"></input>
 | 
					    <input type="submit" class="btn btn-primary disabled" value="{% trans 'Continue' %}"></input>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@
 | 
				
			||||||
                        <hr>
 | 
					                        <hr>
 | 
				
			||||||
                        <p>{% trans "Configuration"%} <strong class="pull-right">{{request.session.template.name}}</strong></p>
 | 
					                        <p>{% trans "Configuration"%} <strong class="pull-right">{{request.session.template.name}}</strong></p>
 | 
				
			||||||
                        <hr>
 | 
					                        <hr>
 | 
				
			||||||
                        <p class="last-p"><strong>{%trans "Total" %}</strong>  <small>({%trans "including VAT" %})</small> <strong class="pull-right">{{request.session.specs.price|intcomma}} CHF/{% trans "Month" %}</strong></p>
 | 
					                        <p class="last-p"><strong>{%trans "Total" %}</strong>  <small>({% if vm_pricing.vat_inclusive %}{%trans "including VAT" %}{% else %}{%trans "excluding VAT" %}{% endif %})</small> <strong class="pull-right">{{request.session.specs.price|intcomma}} CHF/{% trans "Month" %}</strong></p>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,9 +65,19 @@
 | 
				
			||||||
                            <span>{% trans "Disk space" %}: </span>
 | 
					                            <span>{% trans "Disk space" %}: </span>
 | 
				
			||||||
                            <span class="pull-right">{{vm.disk_size|intcomma}} GB</span>
 | 
					                            <span class="pull-right">{{vm.disk_size|intcomma}} GB</span>
 | 
				
			||||||
                        </p>
 | 
					                        </p>
 | 
				
			||||||
 | 
					                        {% if vm.vat > 0 %}
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                                <strong>{% trans "Subtotal" %}: </strong>
 | 
				
			||||||
 | 
					                                <span class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</span>
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                                <span>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%): </span>
 | 
				
			||||||
 | 
					                                <span class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</span>
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                        {% endif %}
 | 
				
			||||||
                        <p>
 | 
					                        <p>
 | 
				
			||||||
                            <span>{% trans "Total" %}</span>
 | 
					                            <strong>{% trans "Total" %}</strong>
 | 
				
			||||||
                            <span class="pull-right">{{vm.price|intcomma}} CHF</span>
 | 
					                            <span class="pull-right">{{vm.total_price|floatformat:2|intcomma}} CHF</span>
 | 
				
			||||||
                        </p>
 | 
					                        </p>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
| 
						 | 
					@ -78,7 +88,7 @@
 | 
				
			||||||
            {% csrf_token %}
 | 
					            {% csrf_token %}
 | 
				
			||||||
            <div class="row">
 | 
					            <div class="row">
 | 
				
			||||||
                <div class="col-sm-8">
 | 
					                <div class="col-sm-8">
 | 
				
			||||||
                    <div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</div>
 | 
					                    <div class="dcl-place-order-text">{% blocktrans with vm_total_price=vm.total_price|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with the fee of {{vm_total_price}} CHF/month{% endblocktrans %}.</div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="col-sm-4 order-confirm-btn text-right">
 | 
					                <div class="col-sm-4 order-confirm-btn text-right">
 | 
				
			||||||
                    <button class="btn choice-btn" id="btn-create-vm" data-toggle="modal" data-target="#createvm-modal">
 | 
					                    <button class="btn choice-btn" id="btn-create-vm" data-toggle="modal" data-target="#createvm-modal">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,11 +19,11 @@ from hosting.models import HostingOrder
 | 
				
			||||||
from membership.models import CustomUser, StripeCustomer
 | 
					from membership.models import CustomUser, StripeCustomer
 | 
				
			||||||
from opennebula_api.serializers import VMTemplateSerializer
 | 
					from opennebula_api.serializers import VMTemplateSerializer
 | 
				
			||||||
from utils.forms import BillingAddressForm, BillingAddressFormSignup
 | 
					from utils.forms import BillingAddressForm, BillingAddressFormSignup
 | 
				
			||||||
from utils.hosting_utils import get_vm_price
 | 
					from utils.hosting_utils import get_vm_price_with_vat
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
from utils.tasks import send_plain_email_task
 | 
					from utils.tasks import send_plain_email_task
 | 
				
			||||||
from .forms import ContactForm
 | 
					from .forms import ContactForm
 | 
				
			||||||
from .models import VMTemplate
 | 
					from .models import VMTemplate, VMPricing
 | 
				
			||||||
from .utils import get_cms_integration
 | 
					from .utils import get_cms_integration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
| 
						 | 
					@ -93,7 +93,8 @@ class IndexView(CreateView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
 | 
					    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        for session_var in ['specs', 'user', 'billing_address_data']:
 | 
					        for session_var in ['specs', 'user', 'billing_address_data',
 | 
				
			||||||
 | 
					                            'pricing_name']:
 | 
				
			||||||
            if session_var in request.session:
 | 
					            if session_var in request.session:
 | 
				
			||||||
                del request.session[session_var]
 | 
					                del request.session[session_var]
 | 
				
			||||||
        return HttpResponseRedirect(reverse('datacenterlight:cms_index'))
 | 
					        return HttpResponseRedirect(reverse('datacenterlight:cms_index'))
 | 
				
			||||||
| 
						 | 
					@ -106,12 +107,30 @@ class IndexView(CreateView):
 | 
				
			||||||
        storage = request.POST.get('storage')
 | 
					        storage = request.POST.get('storage')
 | 
				
			||||||
        storage_field = forms.IntegerField(validators=[self.validate_storage])
 | 
					        storage_field = forms.IntegerField(validators=[self.validate_storage])
 | 
				
			||||||
        template_id = int(request.POST.get('config'))
 | 
					        template_id = int(request.POST.get('config'))
 | 
				
			||||||
 | 
					        pricing_name = request.POST.get('pricing_name')
 | 
				
			||||||
 | 
					        vm_pricing = VMPricing.get_vm_pricing_by_name(pricing_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        template = VMTemplate.objects.filter(
 | 
					        template = VMTemplate.objects.filter(
 | 
				
			||||||
            opennebula_vm_template_id=template_id
 | 
					            opennebula_vm_template_id=template_id
 | 
				
			||||||
        ).first()
 | 
					        ).first()
 | 
				
			||||||
        template_data = VMTemplateSerializer(template).data
 | 
					        template_data = VMTemplateSerializer(template).data
 | 
				
			||||||
        referer_url = request.META['HTTP_REFERER']
 | 
					        referer_url = request.META['HTTP_REFERER']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if vm_pricing is None:
 | 
				
			||||||
 | 
					            vm_pricing_name_msg = _(
 | 
				
			||||||
 | 
					                "Incorrect pricing name. Please contact support"
 | 
				
			||||||
 | 
					                "{support_email}".format(
 | 
				
			||||||
 | 
					                    support_email=settings.DCL_SUPPORT_FROM_ADDRESS
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            messages.add_message(
 | 
				
			||||||
 | 
					                self.request, messages.ERROR, vm_pricing_name_msg,
 | 
				
			||||||
 | 
					                extra_tags='pricing'
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            return HttpResponseRedirect(referer_url + "#order_form")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            vm_pricing_name = vm_pricing.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            cores = cores_field.clean(cores)
 | 
					            cores = cores_field.clean(cores)
 | 
				
			||||||
        except ValidationError as err:
 | 
					        except ValidationError as err:
 | 
				
			||||||
| 
						 | 
					@ -139,14 +158,21 @@ class IndexView(CreateView):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            return HttpResponseRedirect(referer_url + "#order_form")
 | 
					            return HttpResponseRedirect(referer_url + "#order_form")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        amount_to_be_charged = get_vm_price(
 | 
					        price, vat, vat_percent = get_vm_price_with_vat(
 | 
				
			||||||
            cpu=cores, memory=memory, disk_size=storage
 | 
					            cpu=cores,
 | 
				
			||||||
 | 
					            memory=memory,
 | 
				
			||||||
 | 
					            ssd_size=storage,
 | 
				
			||||||
 | 
					            pricing_name=vm_pricing_name
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        specs = {
 | 
					        specs = {
 | 
				
			||||||
            'cpu': cores,
 | 
					            'cpu': cores,
 | 
				
			||||||
            'memory': memory,
 | 
					            'memory': memory,
 | 
				
			||||||
            'disk_size': storage,
 | 
					            'disk_size': storage,
 | 
				
			||||||
            'price': amount_to_be_charged
 | 
					            'price': price,
 | 
				
			||||||
 | 
					            'vat': vat,
 | 
				
			||||||
 | 
					            'vat_percent': vat_percent,
 | 
				
			||||||
 | 
					            'total_price': price + vat,
 | 
				
			||||||
 | 
					            'pricing_name': vm_pricing_name
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        request.session['specs'] = specs
 | 
					        request.session['specs'] = specs
 | 
				
			||||||
        request.session['template'] = template_data
 | 
					        request.session['template'] = template_data
 | 
				
			||||||
| 
						 | 
					@ -220,7 +246,10 @@ class PaymentOrderView(FormView):
 | 
				
			||||||
            'site_url': reverse('datacenterlight:index'),
 | 
					            'site_url': reverse('datacenterlight:index'),
 | 
				
			||||||
            'login_form': HostingUserLoginForm(prefix='login_form'),
 | 
					            'login_form': HostingUserLoginForm(prefix='login_form'),
 | 
				
			||||||
            'billing_address_form': billing_address_form,
 | 
					            'billing_address_form': billing_address_form,
 | 
				
			||||||
            'cms_integration': get_cms_integration('default')
 | 
					            'cms_integration': get_cms_integration('default'),
 | 
				
			||||||
 | 
					            'vm_pricing': VMPricing.get_vm_pricing_by_name(
 | 
				
			||||||
 | 
					                self.request.session['specs']['pricing_name']
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,7 +422,7 @@ class OrderConfirmationView(DetailView):
 | 
				
			||||||
        cpu = specs.get('cpu')
 | 
					        cpu = specs.get('cpu')
 | 
				
			||||||
        memory = specs.get('memory')
 | 
					        memory = specs.get('memory')
 | 
				
			||||||
        disk_size = specs.get('disk_size')
 | 
					        disk_size = specs.get('disk_size')
 | 
				
			||||||
        amount_to_be_charged = specs.get('price')
 | 
					        amount_to_be_charged = specs.get('total_price')
 | 
				
			||||||
        plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
 | 
					        plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
 | 
				
			||||||
                                                     memory=memory,
 | 
					                                                     memory=memory,
 | 
				
			||||||
                                                     disk_size=disk_size)
 | 
					                                                     disk_size=disk_size)
 | 
				
			||||||
| 
						 | 
					@ -489,7 +518,7 @@ class OrderConfirmationView(DetailView):
 | 
				
			||||||
                             stripe_subscription_obj.id, card_details_dict)
 | 
					                             stripe_subscription_obj.id, card_details_dict)
 | 
				
			||||||
        for session_var in ['specs', 'template', 'billing_address',
 | 
					        for session_var in ['specs', 'template', 'billing_address',
 | 
				
			||||||
                            'billing_address_data',
 | 
					                            'billing_address_data',
 | 
				
			||||||
                            'token', 'customer']:
 | 
					                            'token', 'customer', 'pricing_name']:
 | 
				
			||||||
            if session_var in request.session:
 | 
					            if session_var in request.session:
 | 
				
			||||||
                del request.session[session_var]
 | 
					                del request.session[session_var]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ urlpatterns += i18n_patterns(
 | 
				
			||||||
        include('ungleich_page.urls',
 | 
					        include('ungleich_page.urls',
 | 
				
			||||||
                namespace='ungleich_page'),
 | 
					                namespace='ungleich_page'),
 | 
				
			||||||
        name='ungleich_page'),
 | 
					        name='ungleich_page'),
 | 
				
			||||||
 | 
					    url(r'^blog/', include('djangocms_blog.urls', namespace='djangocms_blog')),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns += [
 | 
					urlpatterns += [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								hosting/migrations/0044_hostingorder_vm_pricing.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								hosting/migrations/0044_hostingorder_vm_pricing.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.9.4 on 2018-04-16 00:22
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('datacenterlight', '0019_auto_20180415_2236'),
 | 
				
			||||||
 | 
					        ('hosting', '0043_vmdetail'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='hostingorder',
 | 
				
			||||||
 | 
					            name='vm_pricing',
 | 
				
			||||||
 | 
					            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='datacenterlight.VMPricing'),
 | 
				
			||||||
 | 
					            preserve_default=False,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,8 @@ from django.db import models
 | 
				
			||||||
from django.utils import timezone
 | 
					from django.utils import timezone
 | 
				
			||||||
from django.utils.functional import cached_property
 | 
					from django.utils.functional import cached_property
 | 
				
			||||||
from Crypto.PublicKey import RSA
 | 
					from Crypto.PublicKey import RSA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datacenterlight.models import VMPricing
 | 
				
			||||||
from membership.models import StripeCustomer, CustomUser
 | 
					from membership.models import StripeCustomer, CustomUser
 | 
				
			||||||
from utils.models import BillingAddress
 | 
					from utils.models import BillingAddress
 | 
				
			||||||
from utils.mixins import AssignPermissionsMixin
 | 
					from utils.mixins import AssignPermissionsMixin
 | 
				
			||||||
| 
						 | 
					@ -53,6 +55,7 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
    stripe_charge_id = models.CharField(max_length=100, null=True)
 | 
					    stripe_charge_id = models.CharField(max_length=100, null=True)
 | 
				
			||||||
    price = models.FloatField()
 | 
					    price = models.FloatField()
 | 
				
			||||||
    subscription_id = models.CharField(max_length=100, null=True)
 | 
					    subscription_id = models.CharField(max_length=100, null=True)
 | 
				
			||||||
 | 
					    vm_pricing = models.ForeignKey(VMPricing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    permissions = ('view_hostingorder',)
 | 
					    permissions = ('view_hostingorder',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,12 +73,13 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def create(cls, price=None, vm_id=None, customer=None,
 | 
					    def create(cls, price=None, vm_id=None, customer=None,
 | 
				
			||||||
               billing_address=None):
 | 
					               billing_address=None, vm_pricing=None):
 | 
				
			||||||
        instance = cls.objects.create(
 | 
					        instance = cls.objects.create(
 | 
				
			||||||
            price=price,
 | 
					            price=price,
 | 
				
			||||||
            vm_id=vm_id,
 | 
					            vm_id=vm_id,
 | 
				
			||||||
            customer=customer,
 | 
					            customer=customer,
 | 
				
			||||||
            billing_address=billing_address
 | 
					            billing_address=billing_address,
 | 
				
			||||||
 | 
					            vm_pricing=vm_pricing
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        instance.assign_permissions(customer.user)
 | 
					        instance.assign_permissions(customer.user)
 | 
				
			||||||
        return instance
 | 
					        return instance
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@
 | 
				
			||||||
    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
					    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td>
 | 
					            <td>
 | 
				
			||||||
                <img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
 | 
					                <img src="{{ base_url }}{% static 'datacenterlight/img/datacenterlight.png' %}" style="max-width: 200px;">
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@
 | 
				
			||||||
    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
					    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td>
 | 
					            <td>
 | 
				
			||||||
                <img src="{{base_url}}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
 | 
					                <img src="{{ base_url }}{% static 'datacenterlight/img/datacenterlight.png' %}" style="max-width: 200px;">
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@
 | 
				
			||||||
    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
					    <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td>
 | 
					            <td>
 | 
				
			||||||
                <img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
 | 
					                <img src="{{ base_url }}{% static 'datacenterlight/img/datacenterlight.png' %}" style="max-width: 200px;">
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,7 @@
 | 
				
			||||||
              <center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
 | 
					              <center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
 | 
				
			||||||
                <table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
 | 
					                <table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
 | 
				
			||||||
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
 | 
					<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
 | 
				
			||||||
                      <a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
 | 
					                      <a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static 'hosting/img/datacenterlight.png' %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
                    <td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
 | 
					                    <td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,9 +127,19 @@
 | 
				
			||||||
                            <span>{% trans "Disk space" %}: </span>
 | 
					                            <span>{% trans "Disk space" %}: </span>
 | 
				
			||||||
                            <span class="pull-right">{{vm.disk_size}} GB</span>
 | 
					                            <span class="pull-right">{{vm.disk_size}} GB</span>
 | 
				
			||||||
                        </p>
 | 
					                        </p>
 | 
				
			||||||
 | 
					                        {% if vm.vat > 0 %}
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                                <strong>{% trans "Subtotal" %}: </strong>
 | 
				
			||||||
 | 
					                                <span class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</span>
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                                <span>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%): </span>
 | 
				
			||||||
 | 
					                                <span class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</span>
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                        {% endif %}
 | 
				
			||||||
                        <p>
 | 
					                        <p>
 | 
				
			||||||
                            <span>{% trans "Total" %}</span>
 | 
					                            <strong>{% trans "Total" %}</strong>
 | 
				
			||||||
                            <span class="pull-right">{{vm.price|intcomma}} CHF</span>
 | 
					                            <span class="pull-right">{% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} CHF</span>
 | 
				
			||||||
                        </p>
 | 
					                        </p>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <td class="xs-td-inline" data-header="{% trans 'Order Nr.' %}">{{ order.id }}</td>
 | 
					                    <td class="xs-td-inline" data-header="{% trans 'Order Nr.' %}">{{ order.id }}</td>
 | 
				
			||||||
                    <td class="xs-td-bighalf" data-header="{% trans 'Date' %}">{{ order.created_at | date:"M d, Y H:i" }}</td>
 | 
					                    <td class="xs-td-bighalf" data-header="{% trans 'Date' %}">{{ order.created_at | date:"M d, Y H:i" }}</td>
 | 
				
			||||||
                    <td class="xs-td-smallhalf" data-header="{% trans 'Amount' %}">{{ order.price|intcomma }}</td>
 | 
					                    <td class="xs-td-smallhalf" data-header="{% trans 'Amount' %}">{{ order.price|floatformat:2|intcomma }}</td>
 | 
				
			||||||
                    <td class="text-right last-td">
 | 
					                    <td class="text-right last-td">
 | 
				
			||||||
                        <a class="btn btn-order-detail" href="{% url 'hosting:orders' order.pk %}">{% trans 'See Invoice' %}</a>
 | 
					                        <a class="btn btn-order-detail" href="{% url 'hosting:orders' order.pk %}">{% trans 'See Invoice' %}</a>
 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@
 | 
				
			||||||
				<h2 class="vm-detail-title">{% trans "Billing" %} <img src="{% static 'hosting/img/billing.svg' %}" class="un-icon"></h2>
 | 
									<h2 class="vm-detail-title">{% trans "Billing" %} <img src="{% static 'hosting/img/billing.svg' %}" class="un-icon"></h2>
 | 
				
			||||||
				<div class="vm-vmid">
 | 
									<div class="vm-vmid">
 | 
				
			||||||
					<div class="vm-item-subtitle">{% trans "Current Pricing" %}</div>
 | 
										<div class="vm-item-subtitle">{% trans "Current Pricing" %}</div>
 | 
				
			||||||
					<div class="vm-item-lg">{{virtual_machine.price|floatformat|intcomma}} CHF/{% trans "Month" %}</div>
 | 
										<div class="vm-item-lg">{{order.price|floatformat:2|intcomma}} CHF/{% trans "Month" %}</div>
 | 
				
			||||||
					<a class="btn btn-vm-invoice" href="{% url 'hosting:orders' order.pk %}">{% trans "See Invoice" %}</a>
 | 
										<a class="btn btn-vm-invoice" href="{% url 'hosting:orders' order.pk %}">{% trans "See Invoice" %}</a>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ from utils.forms import (
 | 
				
			||||||
    BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
 | 
					    BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
 | 
				
			||||||
    ResendActivationEmailForm
 | 
					    ResendActivationEmailForm
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from utils.hosting_utils import get_vm_price
 | 
					from utils.hosting_utils import get_vm_price, get_vm_price_with_vat
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
from utils.stripe_utils import StripeUtils
 | 
					from utils.stripe_utils import StripeUtils
 | 
				
			||||||
from utils.tasks import send_plain_email_task
 | 
					from utils.tasks import send_plain_email_task
 | 
				
			||||||
| 
						 | 
					@ -749,11 +749,17 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
                context['vm'] = vm_detail.__dict__
 | 
					                context['vm'] = vm_detail.__dict__
 | 
				
			||||||
                context['vm']['name'] = '{}-{}'.format(
 | 
					                context['vm']['name'] = '{}-{}'.format(
 | 
				
			||||||
                    context['vm']['configuration'], context['vm']['vm_id'])
 | 
					                    context['vm']['configuration'], context['vm']['vm_id'])
 | 
				
			||||||
                context['vm']['price'] = get_vm_price(
 | 
					                price, vat, vat_percent = get_vm_price_with_vat(
 | 
				
			||||||
                    cpu=context['vm']['cores'],
 | 
					                    cpu=context['vm']['cores'],
 | 
				
			||||||
                    disk_size=context['vm']['disk_size'],
 | 
					                    ssd_size=context['vm']['disk_size'],
 | 
				
			||||||
                    memory=context['vm']['memory']
 | 
					                    memory=context['vm']['memory'],
 | 
				
			||||||
 | 
					                    pricing_name=(obj.vm_pricing.name
 | 
				
			||||||
 | 
					                                  if obj.vm_pricing else 'default')
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					                context['vm']['vat'] = vat
 | 
				
			||||||
 | 
					                context['vm']['price'] = price
 | 
				
			||||||
 | 
					                context['vm']['vat_percent'] = vat_percent
 | 
				
			||||||
 | 
					                context['vm']['total_price'] = price + vat
 | 
				
			||||||
                context['subscription_end_date'] = vm_detail.end_date()
 | 
					                context['subscription_end_date'] = vm_detail.end_date()
 | 
				
			||||||
            except VMDetail.DoesNotExist:
 | 
					            except VMDetail.DoesNotExist:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
| 
						 | 
					@ -762,6 +768,17 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    vm = manager.get_vm(obj.vm_id)
 | 
					                    vm = manager.get_vm(obj.vm_id)
 | 
				
			||||||
                    context['vm'] = VirtualMachineSerializer(vm).data
 | 
					                    context['vm'] = VirtualMachineSerializer(vm).data
 | 
				
			||||||
 | 
					                    price, vat, vat_percent = get_vm_price_with_vat(
 | 
				
			||||||
 | 
					                        cpu=context['vm']['cores'],
 | 
				
			||||||
 | 
					                        ssd_size=context['vm']['disk_size'],
 | 
				
			||||||
 | 
					                        memory=context['vm']['memory'],
 | 
				
			||||||
 | 
					                        pricing_name=(obj.vm_pricing.name
 | 
				
			||||||
 | 
					                                      if obj.vm_pricing else 'default')
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    context['vm']['vat'] = vat
 | 
				
			||||||
 | 
					                    context['vm']['price'] = price
 | 
				
			||||||
 | 
					                    context['vm']['vat_percent'] = vat_percent
 | 
				
			||||||
 | 
					                    context['vm']['total_price'] = price + vat
 | 
				
			||||||
                except WrongIdError:
 | 
					                except WrongIdError:
 | 
				
			||||||
                    messages.error(
 | 
					                    messages.error(
 | 
				
			||||||
                        self.request,
 | 
					                        self.request,
 | 
				
			||||||
| 
						 | 
					@ -1100,7 +1117,8 @@ class VirtualMachineView(LoginRequiredMixin, View):
 | 
				
			||||||
            context = {
 | 
					            context = {
 | 
				
			||||||
                'virtual_machine': serializer.data,
 | 
					                'virtual_machine': serializer.data,
 | 
				
			||||||
                'order': HostingOrder.objects.get(
 | 
					                'order': HostingOrder.objects.get(
 | 
				
			||||||
                    vm_id=serializer.data['vm_id'])
 | 
					                    vm_id=serializer.data['vm_id']
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        except Exception as ex:
 | 
					        except Exception as ex:
 | 
				
			||||||
            logger.debug("Exception generated {}".format(str(ex)))
 | 
					            logger.debug("Exception generated {}".format(str(ex)))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
 | 
					import decimal
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
from oca.pool import WrongIdError
 | 
					from oca.pool import WrongIdError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datacenterlight.models import VMPricing
 | 
				
			||||||
from hosting.models import UserHostingKey, VMDetail
 | 
					from hosting.models import UserHostingKey, VMDetail
 | 
				
			||||||
from opennebula_api.serializers import VirtualMachineSerializer
 | 
					from opennebula_api.serializers import VirtualMachineSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,14 +51,74 @@ def get_or_create_vm_detail(user, manager, vm_id):
 | 
				
			||||||
    return vm_detail_obj
 | 
					    return vm_detail_obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_vm_price(cpu, memory, disk_size):
 | 
					def get_vm_price(cpu, memory, disk_size, hdd_size=0, pricing_name='default'):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    A helper function that computes price of a VM from given cpu, ram and
 | 
					    A helper function that computes price of a VM from given cpu, ram and
 | 
				
			||||||
    ssd parameters
 | 
					    ssd parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :param cpu: Number of cores of the VM
 | 
					    :param cpu: Number of cores of the VM
 | 
				
			||||||
    :param memory: RAM of the VM
 | 
					    :param memory: RAM of the VM
 | 
				
			||||||
    :param disk_size: Disk space of the VM
 | 
					    :param disk_size: Disk space of the VM (SSD)
 | 
				
			||||||
 | 
					    :param hdd_size: The HDD size
 | 
				
			||||||
 | 
					    :param pricing_name: The pricing name to be used
 | 
				
			||||||
    :return: The price of the VM
 | 
					    :return: The price of the VM
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    return (cpu * 5) + (memory * 2) + (disk_size * 0.6)
 | 
					    try:
 | 
				
			||||||
 | 
					        pricing = VMPricing.objects.get(name=pricing_name)
 | 
				
			||||||
 | 
					    except Exception as ex:
 | 
				
			||||||
 | 
					        logger.error(
 | 
				
			||||||
 | 
					            "Error getting VMPricing object for {pricing_name}."
 | 
				
			||||||
 | 
					            "Details: {details}".format(
 | 
				
			||||||
 | 
					                pricing_name=pricing_name, details=str(ex)
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    price = ((decimal.Decimal(cpu) * pricing.cores_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(memory) * pricing.ram_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(disk_size) * pricing.ssd_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(hdd_size) * pricing.hdd_unit_price))
 | 
				
			||||||
 | 
					    cents = decimal.Decimal('.01')
 | 
				
			||||||
 | 
					    price = price.quantize(cents, decimal.ROUND_HALF_UP)
 | 
				
			||||||
 | 
					    return float(price)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
 | 
				
			||||||
 | 
					                          pricing_name='default'):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A helper function that computes price of a VM from given cpu, ram and
 | 
				
			||||||
 | 
					    ssd, hdd and the pricing parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param cpu: Number of cores of the VM
 | 
				
			||||||
 | 
					    :param memory: RAM of the VM
 | 
				
			||||||
 | 
					    :param ssd_size: Disk space of the VM (SSD)
 | 
				
			||||||
 | 
					    :param hdd_size: The HDD size
 | 
				
			||||||
 | 
					    :param pricing_name: The pricing name to be used
 | 
				
			||||||
 | 
					    :return: The a tuple containing the price of the VM, the VAT and the
 | 
				
			||||||
 | 
					             VAT percentage
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        pricing = VMPricing.objects.get(name=pricing_name)
 | 
				
			||||||
 | 
					    except Exception as ex:
 | 
				
			||||||
 | 
					        logger.error(
 | 
				
			||||||
 | 
					            "Error getting VMPricing object for {pricing_name}."
 | 
				
			||||||
 | 
					            "Details: {details}".format(
 | 
				
			||||||
 | 
					                pricing_name=pricing_name, details=str(ex)
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    price = ((decimal.Decimal(cpu) * pricing.cores_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(memory) * pricing.ram_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
 | 
				
			||||||
 | 
					             (decimal.Decimal(hdd_size) * pricing.hdd_unit_price))
 | 
				
			||||||
 | 
					    if pricing.vat_inclusive:
 | 
				
			||||||
 | 
					        vat = decimal.Decimal(0)
 | 
				
			||||||
 | 
					        vat_percent = decimal.Decimal(0)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        vat = price * pricing.vat_percentage * decimal.Decimal(0.01)
 | 
				
			||||||
 | 
					        vat_percent = pricing.vat_percentage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cents = decimal.Decimal('.01')
 | 
				
			||||||
 | 
					    price = price.quantize(cents, decimal.ROUND_HALF_UP)
 | 
				
			||||||
 | 
					    vat = vat.quantize(cents, decimal.ROUND_HALF_UP)
 | 
				
			||||||
 | 
					    return float(price), float(vat), float(vat_percent)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue