diff --git a/Changelog b/Changelog
index 538a862d..b85dd4ff 100644
--- a/Changelog
+++ b/Changelog
@@ -1,4 +1,25 @@
 Next:
+    * bugfix: Use correct version of django-multisite (MR #676)
+2.4.1: 2018-10-18
+    * bugfix: Update pycryptodome module from 3.4 to 3.6.6 (PR #674)
+2.4: 2018-10-18
+    * #5681: [hosting,dcl] Allow admin to lower minimum RAM to 512 MB (PR #672)
+2.3.1: 2018-10-17
+    * bugfix: [hosting, dcl] Show VAT percent rounded to 2 decimal places in the order confirmation page (PR #673)
+2.3: 2018-10-08
+    * #5690: Generic payment page - allow admin to add a onetime/monthly product and the frontend for user to pay for this product (PR #666)
+2.2.2: 2018-09-28
+    * #5721: Set calculator OS list in alphabetical order and set `Devuan Ascii` as the default (PR #668)
+    * bugfix: Fix some typos and correct DE translations (PR #667)
+2.2.1: 2018-09-25
+    * feature: Change DCLNavbarPlugin to show login option only if set (PR #665)
+    * bugfix: Log opennebula errors and send proper message when vm terminate is not completed in the stipulated time (PR #648)
+2.2: 2018-09-06
+    * bugfix: Include price in the Stripe plan name to make it distinct and to correct pricing since version 1.9
+2.1.2: 2018-08-30
+    * bugfix: [blog, comic] Set blog rss feed for all blog templates
+2.1.1: 2018-08-24
+    * #5487: [hosting] Add explicit warning message for teminating VM (PR #656)
     * bugfix: [dg] Send email to admin on dg subscription and increase cc_brand field to 128 characters (PR #652)
     * #5458: [admin] Make hostingorder more readable (PR #657)
     * bugfix: [CMS templates] Set description meta field of ungleich template (was missing before) and set ungleich glarus ag uniformly as author of various CMS pages (PR #653)
diff --git a/datacenterlight/cms_models.py b/datacenterlight/cms_models.py
index 62a7b312..2d1a98b5 100644
--- a/datacenterlight/cms_models.py
+++ b/datacenterlight/cms_models.py
@@ -180,6 +180,10 @@ class DCLNavbarPluginModel(CMSPlugin):
         default=True,
         help_text='Select to include the language selection dropdown.'
     )
+    show_login_option = models.BooleanField(
+        default=True,
+        help_text='Uncheck this if you do not want to show login/dashboard.'
+    )
 
     def get_logo_dark(self):
         # used only if atleast one logo exists
@@ -350,3 +354,11 @@ class DCLCalculatorPluginModel(CMSPlugin):
                   "in the backend to be automatically listed in this "
                   "calculator instance."
     )
+    default_selected_template = models.CharField(
+        default="Devuan Ascii",
+        null=True,
+        max_length=128,
+        help_text="Write the name of the template that you need selected as"
+                  " default when the calculator loads"
+    )
+    enable_512mb_ram = models.BooleanField(default=False)
diff --git a/datacenterlight/cms_plugins.py b/datacenterlight/cms_plugins.py
index 95a496d8..c3ec974f 100644
--- a/datacenterlight/cms_plugins.py
+++ b/datacenterlight/cms_plugins.py
@@ -9,6 +9,7 @@ from .cms_models import (
     DCLSectionPromoPluginModel, DCLCalculatorPluginModel
 )
 from .models import VMTemplate
+from datacenterlight.utils import clear_all_session_vars
 
 
 @plugin_pool.register_plugin
@@ -85,6 +86,7 @@ class DCLCalculatorPlugin(CMSPluginBase):
     require_parent = True
 
     def render(self, context, instance, placeholder):
+        clear_all_session_vars(context['request'])
         context = super(DCLCalculatorPlugin, self).render(
             context, instance, placeholder
         )
@@ -92,11 +94,13 @@ class DCLCalculatorPlugin(CMSPluginBase):
         if ids:
             context['templates'] = VMTemplate.objects.filter(
                 vm_type=instance.vm_type
-            ).filter(opennebula_vm_template_id__in=ids)
+            ).filter(opennebula_vm_template_id__in=ids).order_by('name')
         else:
             context['templates'] = VMTemplate.objects.filter(
                 vm_type=instance.vm_type
-            )
+            ).order_by('name')
+        context['instance'] = instance
+        context['min_ram'] = 0.5 if instance.enable_512mb_ram else 1
         return context
 
 
diff --git a/datacenterlight/locale/de/LC_MESSAGES/django.po b/datacenterlight/locale/de/LC_MESSAGES/django.po
index 1b66b640..d43e91ea 100644
--- a/datacenterlight/locale/de/LC_MESSAGES/django.po
+++ b/datacenterlight/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-07-05 23:11+0000\n"
+"POT-Creation-Date: 2018-09-26 20:44+0000\n"
 "PO-Revision-Date: 2018-03-30 23:22+0000\n"
 "Last-Translator: b'Anonymous User <coder.purple+25@gmail.com>'\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -293,6 +293,9 @@ msgstr "Registrieren"
 msgid "Billing Address"
 msgstr "Rechnungsadresse"
 
+msgid "Make a payment"
+msgstr ""
+
 msgid "Your Order"
 msgstr "Deine Bestellung"
 
@@ -336,9 +339,9 @@ msgid ""
 "database."
 msgstr ""
 "Bitte wähle eine der zuvor genutzten Kreditkarten oder gib Deine "
-"Kreditkartendetails unten an. Die Bezahlung wird über "
-"<a href=\"https://stripe.com\" target=\"_blank\">Stripe</a> abgewickelt. "
-"Wir speichern Deine Kreditkartendetails nicht in unserer Datenbank."
+"Kreditkartendetails unten an. Die Bezahlung wird über <a href=\"https://"
+"stripe.com\" target=\"_blank\">Stripe</a> abgewickelt. Wir speichern Deine "
+"Kreditkartendetails nicht in unserer Datenbank."
 
 msgid ""
 "Please fill in your credit card information below. We are using <a href="
@@ -395,12 +398,35 @@ msgstr "Bestellungsübersicht"
 msgid "Product"
 msgstr "Produkt"
 
+msgid "Amount"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Recurring"
+msgstr ""
+
 msgid "Subtotal"
 msgstr "Zwischensumme"
 
 msgid "VAT"
 msgstr "Mehrwertsteuer"
 
+msgid ""
+"By clicking \"Place order\" this plan will charge your credit card account "
+"with %(total_price)s CHF/month"
+msgstr ""
+"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit "
+"%(vm_total_price)s CHF pro Monat belastet"
+
+msgid ""
+"By clicking \"Place order\" this payment will charge your credit card "
+"account with a one time amount of %(total_price)s CHF"
+msgstr ""
+"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit "
+"%(vm_total_price)s CHF pro Monat belastet"
+
 #, python-format
 msgid ""
 "By clicking \"Place order\" this plan will charge your credit card account "
@@ -541,8 +567,33 @@ msgstr ""
 
 #, python-brace-format
 msgid "An error occurred while associating the card. Details: {details}"
-msgstr "Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: "
-"{details}"
+msgstr ""
+"Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: {details}"
+
+msgid "Confirmation of your payment"
+msgstr ""
+
+msgid " This is a monthly recurring plan."
+msgstr ""
+
+#, python-brace-format
+msgid ""
+"Hi {name},\n"
+"\n"
+"thank you for your order!\n"
+"We have just received a payment of CHF {amount:.2f} from you.{recurring}\n"
+"\n"
+"Cheers,\n"
+"Your Data Center Light team"
+msgstr ""
+
+msgid "Thank you for the payment."
+msgstr "Danke für Deine Bestellung."
+
+msgid ""
+"You will soon receive a confirmation email of the payment. You can always "
+"contact us at info@ungleich.ch for any question that you may have."
+msgstr ""
 
 msgid "Thank you for the order."
 msgstr "Danke für Deine Bestellung."
diff --git a/datacenterlight/migrations/0025_dclnavbarpluginmodel_show_login_option.py b/datacenterlight/migrations/0025_dclnavbarpluginmodel_show_login_option.py
new file mode 100644
index 00000000..e9ec57ba
--- /dev/null
+++ b/datacenterlight/migrations/0025_dclnavbarpluginmodel_show_login_option.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-09-25 20:27
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('datacenterlight', '0024_dclcalculatorpluginmodel_vm_templates_to_show'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='dclnavbarpluginmodel',
+            name='show_login_option',
+            field=models.BooleanField(default=True, help_text='Uncheck this if you do not want to show login/dashboard.'),
+        ),
+    ]
diff --git a/datacenterlight/migrations/0026_dclcalculatorpluginmodel_default_selected_template.py b/datacenterlight/migrations/0026_dclcalculatorpluginmodel_default_selected_template.py
new file mode 100644
index 00000000..047d4096
--- /dev/null
+++ b/datacenterlight/migrations/0026_dclcalculatorpluginmodel_default_selected_template.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-09-27 20:32
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('datacenterlight', '0025_dclnavbarpluginmodel_show_login_option'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='dclcalculatorpluginmodel',
+            name='default_selected_template',
+            field=models.CharField(default='Devuan Ascii', help_text='Write the name of the template that you need selected as default when the calculator loads', max_length=128, null=True),
+        ),
+    ]
diff --git a/datacenterlight/migrations/0027_dclcalculatorpluginmodel_enable_512mb_ram.py b/datacenterlight/migrations/0027_dclcalculatorpluginmodel_enable_512mb_ram.py
new file mode 100644
index 00000000..bd639c9d
--- /dev/null
+++ b/datacenterlight/migrations/0027_dclcalculatorpluginmodel_enable_512mb_ram.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-09-29 05:36
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('datacenterlight', '0026_dclcalculatorpluginmodel_default_selected_template'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='dclcalculatorpluginmodel',
+            name='enable_512mb_ram',
+            field=models.BooleanField(default=False),
+        ),
+    ]
diff --git a/datacenterlight/static/datacenterlight/css/common.css b/datacenterlight/static/datacenterlight/css/common.css
index 28674b30..00ee52cc 100644
--- a/datacenterlight/static/datacenterlight/css/common.css
+++ b/datacenterlight/static/datacenterlight/css/common.css
@@ -179,4 +179,10 @@ footer .dcl-link-separator::before {
 .new-card-button-margin button{
     margin-top: 5px;
     margin-bottom: 5px;
-}
\ No newline at end of file
+}
+
+.input-no-border {
+  border: none !important;
+  background: transparent !important;
+  resize: none;
+}
diff --git a/datacenterlight/static/datacenterlight/js/main.js b/datacenterlight/static/datacenterlight/js/main.js
index 292e8c16..65db1d6b 100644
--- a/datacenterlight/static/datacenterlight/js/main.js
+++ b/datacenterlight/static/datacenterlight/js/main.js
@@ -5,6 +5,10 @@
     /* ---------------------------------------------
      Scripts initialization
      --------------------------------------------- */
+    var minRam = 1;
+    if(window.minRam){
+        minRam = window.minRam;
+    }
     var cardPricing = {
         'cpu': {
             'id': 'coreValue',
@@ -16,7 +20,7 @@
         'ram': {
             'id': 'ramValue',
             'value': 2,
-            'min': 1,
+            'min': minRam,
             'max': 200,
             'interval': 1
         },
@@ -40,6 +44,7 @@
         _initNavUrl();
         _initPricing();
         ajaxForms();
+        $('#ramValue').data('old-value', $('#ramValue').val());
     });
 
     $(window).resize(function() {
@@ -144,21 +149,54 @@
             var data = $(this).data('minus');
 
             if (cardPricing[data].value > cardPricing[data].min) {
-                cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval;
+                if(data === 'ram' && String(cardPricing[data].value) === "1" && minRam === 0.5){
+                    cardPricing[data].value = 0.5;
+                    $('#ramValue').val('0.5');
+                    $("#ramValue").attr('step', 0.5);
+                } else {
+                    cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval;
+                }
             }
             _fetchPricing();
+            $('#ramValue').data('old-value', $('#ramValue').val());
         });
         $('.fa-plus-circle.right').click(function(event) {
             var data = $(this).data('plus');
             if (cardPricing[data].value < cardPricing[data].max) {
-                cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval;
+                if(data === 'ram' && String(cardPricing[data].value) === "0.5" && minRam === 0.5){
+                    cardPricing[data].value = 1;
+                    $('#ramValue').val('1');
+                    $("#ramValue").attr('step', 1);
+                } else {
+                    cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval;
+                }
             }
             _fetchPricing();
+            $('#ramValue').data('old-value', $('#ramValue').val());
         });
 
         $('.input-price').change(function() {
             var data = $(this).attr("name");
-            cardPricing[data].value = $('input[name=' + data + ']').val();
+            var input = $('input[name=' + data + ']');
+            var inputValue = input.val();
+
+            if(data === 'ram') {
+                var ramInput = $('#ramValue');
+                if ($('#ramValue').data('old-value') < $('#ramValue').val()) {
+                    if($('#ramValue').val() === '1' && minRam === 0.5) {
+                        $("#ramValue").attr('step', 1);
+                        $('#ramValue').val('1');
+                    }
+                } else {
+                    if($('#ramValue').val() === '0' && minRam === 0.5) {
+                        $("#ramValue").attr('step', 0.5);
+                        $('#ramValue').val('0.5');
+                    }
+                }
+                inputValue = $('#ramValue').val();
+                $('#ramValue').data('old-value', $('#ramValue').val());
+            }
+            cardPricing[data].value = inputValue;
             _fetchPricing();
         });
     }
diff --git a/datacenterlight/templates/datacenterlight/cms/navbar.html b/datacenterlight/templates/datacenterlight/cms/navbar.html
index ae6643aa..886a5009 100644
--- a/datacenterlight/templates/datacenterlight/cms/navbar.html
+++ b/datacenterlight/templates/datacenterlight/cms/navbar.html
@@ -35,14 +35,16 @@
           {% endif %}
         </li>
       {% endif %}
-      {% if not request.user.is_authenticated %}
-        <li>
-          <a href="{% url 'hosting:login' %}">{% trans "Login" %}&nbsp;&nbsp;<span class="fa fa-sign-in"></span></a>
-        </li>
-      {% else %}
-        <li>
-          <a href="{% url 'hosting:dashboard' %}">{% trans "Dashboard" %}</a>
-        </li>
+      {% if instance.show_login_option %}
+        {% if not request.user.is_authenticated %}
+          <li>
+            <a href="{% url 'hosting:login' %}">{% trans "Login" %}&nbsp;&nbsp;<span class="fa fa-sign-in"></span></a>
+          </li>
+        {% else %}
+          <li>
+            <a href="{% url 'hosting:dashboard' %}">{% trans "Dashboard" %}</a>
+          </li>
+        {% endif %}
       {% endif %}
       {% comment %}
       <!-- to be used when more than one option for language -->
diff --git a/datacenterlight/templates/datacenterlight/includes/_calculator_form.html b/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
index 72ca5a05..f9896f17 100644
--- a/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
+++ b/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
@@ -9,11 +9,14 @@
         window.ssdUnitPrice = {{vm_pricing.ssd_unit_price|default:0}};
         window.hddUnitPrice = {{vm_pricing.hdd_unit_price|default:0}};
         window.discountAmount = {{vm_pricing.discount_amount|default:0}};
+        window.minRam = {{min_ram}};
+        window.minRamErr = '{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}';
     </script>
 {% endif %}
 
 <form id="order_form" method="POST" action="{{calculator_form_url}}" data-toggle="validator" role="form">
     {% csrf_token %}
+    <input type="hidden" name="pid" value="{{instance.id}}">
     <div class="title">
         <h3>{% trans "VM hosting" %} </h3>
     </div>
@@ -54,8 +57,8 @@
         <div class="form-group">
             <div class="description input">
                 <i class="fa fa-minus-circle left" data-minus="ram" aria-hidden="true"></i>
-                <input id="ramValue" class="input-price select-number" type="number" min="1" max="200" name="ram"
-                       data-error="{% trans 'Please enter a value in range 1 - 200.' %}" required>
+                <input id="ramValue" class="input-price select-number" type="number" min="{% if min_ram == 0.5 %}0{% else %}1{% endif %}" max="200" name="ram"
+                       data-error="{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}" required step="1">
                 <span> GB RAM</span>
                 <i class="fa fa-plus-circle right" data-plus="ram" aria-hidden="true"></i>
             </div>
@@ -91,11 +94,12 @@
             <label for="config">OS</label>
             <select name="config">
                 {% for template in templates %}
-                <option value="{{template.opennebula_vm_template_id}}">{{template.name}}</option>
+
+                <option value="{{template.opennebula_vm_template_id}}" {% if template.name|lower == instance.default_selected_template|lower %}selected="selected"{% endif %}>{{template.name}}</option>
                 {% endfor %}
             </select>
         </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>
-</form>
\ No newline at end of file
+</form>
diff --git a/datacenterlight/templates/datacenterlight/landing_payment.html b/datacenterlight/templates/datacenterlight/landing_payment.html
index 4c43f41c..fb6d51b0 100644
--- a/datacenterlight/templates/datacenterlight/landing_payment.html
+++ b/datacenterlight/templates/datacenterlight/landing_payment.html
@@ -67,36 +67,49 @@
             </div>
             <div class="dcl-payment-box">
                 <div class="dcl-payment-section">
-                    <h3>{%trans "Your Order" %}</h3>
-                    <hr class="top-hr">
-                    <div class="dcl-payment-order">
-                        <p>{% trans "Cores"%} <strong class="pull-right">{{request.session.specs.cpu|floatformat}}</strong></p>
-                        <hr>
-                        <p>{% trans "Memory"%} <strong class="pull-right">{{request.session.specs.memory|floatformat}} GB</strong></p>
-                        <hr>
-                        <p>{% trans "Disk space"%} <strong class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</strong></p>
-                        <hr>
-                        <p>{% trans "Configuration"%} <strong class="pull-right">{{request.session.template.name}}</strong></p>
-                        <hr>
-                        <p>
-                            <strong>{%trans "Total" %}</strong>&nbsp;&nbsp;
-                            <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>
-                        <hr>
-                        {% if vm_pricing.discount_amount %}
-                        <p class="mb-0">
-                            {%trans "Discount" as discount_name %}
-                            <strong>{{ vm_pricing.discount_name|default:discount_name }}</strong>&nbsp;&nbsp;
-                            <strong class="pull-right text-primary">- {{ vm_pricing.discount_amount }} CHF/{% trans "Month" %}</strong>
-                        </p>
-                        <p>
-                            ({% trans "Will be applied at checkout" %})
-                        </p>
-                        {% endif %}
-                    </div>
+                    {% if generic_payment_form %}
+                        <h3>{%trans "Make a payment" %}</h3>
+                        <hr class="top-hr">
+                        <form role="form" id="generic-payment-form" method="post" action="" novalidate>
+                            {% csrf_token %}
+                            <input type="hidden" name="product" value="1" />
+                            {% for field in generic_payment_form %}
+                            {% bootstrap_field field type='fields'%}
+                            {% endfor %}
+                            <p class="text-danger">{{generic_payment_form.non_field_errors|striptags}}</p>
+                        </form>
+                    {% else %}
+                        <h3>{%trans "Your Order" %}</h3>
+                        <hr class="top-hr">
+                        <div class="dcl-payment-order">
+                            <p>{% trans "Cores"%} <strong class="pull-right">{{request.session.specs.cpu|floatformat}}</strong></p>
+                            <hr>
+                            <p>{% trans "Memory"%} <strong class="pull-right">{{request.session.specs.memory|floatformat}} GB</strong></p>
+                            <hr>
+                            <p>{% trans "Disk space"%} <strong class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</strong></p>
+                            <hr>
+                            <p>{% trans "Configuration"%} <strong class="pull-right">{{request.session.template.name}}</strong></p>
+                            <hr>
+                            <p>
+                                <strong>{%trans "Total" %}</strong>&nbsp;&nbsp;
+                                <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>
+                            <hr>
+                            {% if vm_pricing.discount_amount %}
+                            <p class="mb-0">
+                                {%trans "Discount" as discount_name %}
+                                <strong>{{ vm_pricing.discount_name|default:discount_name }}</strong>&nbsp;&nbsp;
+                                <strong class="pull-right text-primary">- {{ vm_pricing.discount_amount }} CHF/{% trans "Month" %}</strong>
+                            </p>
+                            <p>
+                                ({% trans "Will be applied at checkout" %})
+                            </p>
+                            {% endif %}
+                        </div>
+                    {% endif %}
                 </div>
             </div>
             <div class="dcl-payment-box">
diff --git a/datacenterlight/templates/datacenterlight/order_detail.html b/datacenterlight/templates/datacenterlight/order_detail.html
index 49347ba2..31933e12 100644
--- a/datacenterlight/templates/datacenterlight/order_detail.html
+++ b/datacenterlight/templates/datacenterlight/order_detail.html
@@ -47,61 +47,88 @@
             <hr>
             <div>
                 <h4>{% trans "Order summary" %}</h4>
-                <p>
-                    <strong>{% trans "Product" %}:</strong>&nbsp;
-                    {{ request.session.template.name }}
-                </p>
-                <div class="row">
-                    <div class="col-sm-6">
+                    {% if generic_payment_details %}
                         <p>
-                            <span>{% trans "Cores" %}: </span>
-                            <strong class="pull-right">{{vm.cpu|floatformat}}</strong>
+                            <strong>{% trans "Product" %}:</strong>&nbsp;
+                            {{ generic_payment_details.product_name }}
                         </p>
-                        <p>
-                            <span>{% trans "Memory" %}: </span>
-                            <strong class="pull-right">{{vm.memory|intcomma}} GB</strong>
-                        </p>
-                        <p>
-                            <span>{% trans "Disk space" %}: </span>
-                            <strong class="pull-right">{{vm.disk_size|intcomma}} GB</strong>
-                        </p>
-                    </div>
-                    <div class="col-sm-12">
-                        <hr class="thin-hr">
-                    </div>
-                    {% if vm.vat > 0 or vm.discount.amount > 0 %}
-                        <div class="col-sm-6">
-                            <div class="subtotal-price">
-                                {% if vm.vat > 0 %}
+                        <div class="row">
+                            <div class="col-sm-6">
+                                <p>
+                                    <span>{% trans "Amount" %}: </span>
+                                    <strong class="pull-right">CHF {{generic_payment_details.amount|floatformat:2|intcomma}}</strong>
+                                </p>
+                                {% if generic_payment_details.description %}
                                     <p>
-                                        <strong class="text-lg">{% trans "Subtotal" %} </strong>
-                                        <strong class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</strong>
-                                    </p>
-                                    <p>
-                                        <small>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) </small>
-                                        <strong class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</strong>
+                                        <span>{% trans "Description" %}: </span>
+                                        <strong class="pull-right">{{generic_payment_details.description}}</strong>
                                     </p>
                                 {% endif %}
-                                {% if vm.discount.amount > 0 %}
-                                    <p class="text-primary">
-                                        {%trans "Discount" as discount_name %}
-                                        <strong>{{ vm.discount.name|default:discount_name }} </strong>
-                                        <strong class="pull-right">- {{ vm.discount.amount }} CHF</strong>
+                                {% if generic_payment_details.recurring %}
+                                    <p>
+                                        <span>{% trans "Recurring" %}: </span>
+                                        <strong class="pull-right">Yes</strong>
                                     </p>
                                 {% endif %}
                             </div>
                         </div>
-                        <div class="col-sm-12">
-                            <hr class="thin-hr">
+                    {% else %}
+                        <p>
+                            <strong>{% trans "Product" %}:</strong>&nbsp;
+                            {{ request.session.template.name }}
+                        </p>
+                        <div class="row">
+                            <div class="col-sm-6">
+                                <p>
+                                    <span>{% trans "Cores" %}: </span>
+                                    <strong class="pull-right">{{vm.cpu|floatformat}}</strong>
+                                </p>
+                                <p>
+                                    <span>{% trans "Memory" %}: </span>
+                                    <strong class="pull-right">{{vm.memory|intcomma}} GB</strong>
+                                </p>
+                                <p>
+                                    <span>{% trans "Disk space" %}: </span>
+                                    <strong class="pull-right">{{vm.disk_size|intcomma}} GB</strong>
+                                </p>
+                            </div>
+                            <div class="col-sm-12">
+                                <hr class="thin-hr">
+                            </div>
+                            {% if vm.vat > 0 or vm.discount.amount > 0 %}
+                                <div class="col-sm-6">
+                                    <div class="subtotal-price">
+                                        {% if vm.vat > 0 %}
+                                            <p>
+                                                <strong class="text-lg">{% trans "Subtotal" %} </strong>
+                                                <strong class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</strong>
+                                            </p>
+                                            <p>
+                                                <small>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) </small>
+                                                <strong class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</strong>
+                                            </p>
+                                        {% endif %}
+                                        {% if vm.discount.amount > 0 %}
+                                            <p class="text-primary">
+                                                {%trans "Discount" as discount_name %}
+                                                <strong>{{ vm.discount.name|default:discount_name }} </strong>
+                                                <strong class="pull-right">- {{ vm.discount.amount }} CHF</strong>
+                                            </p>
+                                        {% endif %}
+                                    </div>
+                                </div>
+                                <div class="col-sm-12">
+                                    <hr class="thin-hr">
+                                </div>
+                            {% endif %}
+                            <div class="col-sm-6">
+                                <p class="total-price">
+                                    <strong>{% trans "Total" %} </strong>
+                                    <strong class="pull-right">{{vm.total_price|floatformat:2|intcomma}} CHF</strong>
+                                </p>
+                            </div>
                         </div>
                     {% endif %}
-                    <div class="col-sm-6">
-                        <p class="total-price">
-                            <strong>{% trans "Total" %} </strong>
-                            <strong class="pull-right">{{vm.total_price|floatformat:2|intcomma}} CHF</strong>
-                        </p>
-                    </div>
-                </div>
             </div>
             <hr class="thin-hr">
         </div>
@@ -109,7 +136,15 @@
             {% csrf_token %}
             <div class="row">
                 <div class="col-sm-8">
-                    <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 {{vm_total_price}} CHF/month{% endblocktrans %}.</div>
+                    {% if generic_payment_details %}
+                        {% if generic_payment_details.recurring %}
+                            <div class="dcl-place-order-text">{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{total_price}} CHF/month{% endblocktrans %}.</div>
+                        {% else %}
+                            <div class="dcl-place-order-text">{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this payment will charge your credit card account with a one time amount of {{total_price}} CHF{% endblocktrans %}.</div>
+                        {% endif %}
+                    {% else %}
+                        <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 {{vm_total_price}} CHF/month{% endblocktrans %}.</div>
+                    {% endif %}
                 </div>
                 <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">
@@ -151,16 +186,5 @@
 <script type="text/javascript">
     {% trans "Some problem encountered. Please try again later." as err_msg %}
     var create_vm_error_message = '{{err_msg|safe}}';
-    window.onload = function () {
-        var locale_dates = document.getElementsByClassName("locale_date");
-        var formats = ['YYYY-MM-DD hh:mm a']
-        var i;
-        for (i = 0; i < locale_dates.length; i++) {
-            var oldDate = moment.utc(locale_dates[i].textContent, formats);
-            var outputFormat = locale_dates[i].getAttribute('data-format') || oldDate._f;
-            locale_dates[i].innerHTML = oldDate.local().format(outputFormat);
-            locale_dates[i].className += ' done';
-        }
-    };
 </script>
 {%endblock%}
\ No newline at end of file
diff --git a/datacenterlight/tests.py b/datacenterlight/tests.py
index c755cc6f..ca1bb930 100644
--- a/datacenterlight/tests.py
+++ b/datacenterlight/tests.py
@@ -105,7 +105,8 @@ class CeleryTaskTestCase(TestCase):
                                             disk_size=disk_size)
         plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
                                                      memory=memory,
-                                                     disk_size=disk_size)
+                                                     disk_size=disk_size,
+                                                     price=amount_to_be_charged)
         stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu,
                                                         ram=memory,
                                                         ssd=disk_size,
diff --git a/datacenterlight/utils.py b/datacenterlight/utils.py
index 8da408a0..bbcb16ab 100644
--- a/datacenterlight/utils.py
+++ b/datacenterlight/utils.py
@@ -89,8 +89,14 @@ def create_vm(billing_address_data, stripe_customer_id, specs,
 
     create_vm_task.delay(vm_template_id, user, specs, template, order.id)
 
-    for session_var in ['specs', 'template', 'billing_address',
-                        'billing_address_data', 'card_id',
-                        'token', 'customer']:
-        if session_var in request.session:
-            del request.session[session_var]
+    clear_all_session_vars(request)
+
+
+def clear_all_session_vars(request):
+    if request.session is not None:
+        for session_var in ['specs', 'template', 'billing_address',
+                            'billing_address_data', 'card_id',
+                            'token', 'customer', 'generic_payment_type',
+                            'generic_payment_details', 'product_id']:
+            if session_var in request.session:
+                del request.session[session_var]
diff --git a/datacenterlight/views.py b/datacenterlight/views.py
index bf87d9b9..445ff7cf 100644
--- a/datacenterlight/views.py
+++ b/datacenterlight/views.py
@@ -6,23 +6,31 @@ from django.contrib import messages
 from django.contrib.auth import login, authenticate
 from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect, JsonResponse
+from django.http import HttpResponseRedirect, JsonResponse, Http404
 from django.shortcuts import render
 from django.utils.translation import get_language, ugettext_lazy as _
 from django.views.decorators.cache import cache_control
 from django.views.generic import FormView, CreateView, DetailView
 
-from hosting.forms import HostingUserLoginForm
-from hosting.models import HostingOrder, UserCardDetail
+from hosting.forms import (
+    HostingUserLoginForm, GenericPaymentForm, ProductPaymentForm
+)
+from hosting.models import (
+    HostingBill, HostingOrder, UserCardDetail, GenericProduct
+)
 from membership.models import CustomUser, StripeCustomer
 from opennebula_api.serializers import VMTemplateSerializer
-from utils.forms import BillingAddressForm, BillingAddressFormSignup
+from utils.forms import (
+    BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
+    BillingAddress
+)
 from utils.hosting_utils import get_vm_price_with_vat
 from utils.stripe_utils import StripeUtils
 from utils.tasks import send_plain_email_task
+from .cms_models import DCLCalculatorPluginModel
 from .forms import ContactForm
 from .models import VMTemplate, VMPricing
-from .utils import get_cms_integration, create_vm
+from .utils import get_cms_integration, create_vm, clear_all_session_vars
 
 logger = logging.getLogger(__name__)
 
@@ -82,7 +90,29 @@ class IndexView(CreateView):
             raise ValidationError(_('Invalid number of cores'))
 
     def validate_memory(self, value):
-        if (value > 200) or (value < 1):
+        if 'pid' in self.request.POST:
+            try:
+                plugin = DCLCalculatorPluginModel.objects.get(
+                             id=self.request.POST['pid']
+                         )
+            except DCLCalculatorPluginModel.DoesNotExist as dne:
+                logger.error(
+                    str(dne) + " plugin_id: " + self.request.POST['pid']
+                )
+                raise ValidationError(_('Invalid calculator properties'))
+            if plugin.enable_512mb_ram:
+                if value % 1 == 0 or value == 0.5:
+                    logger.debug(
+                        "Given ram {value} is either 0.5 or a"
+                        " whole number".format(value=value)
+                    )
+                    if (value > 200) or (value < 0.5):
+                        raise ValidationError(_('Invalid RAM size'))
+                else:
+                    raise ValidationError(_('Invalid RAM size'))
+            elif (value > 200) or (value < 1) or (value % 1 != 0):
+                raise ValidationError(_('Invalid RAM size'))
+        else:
             raise ValidationError(_('Invalid RAM size'))
 
     def validate_storage(self, value):
@@ -91,17 +121,14 @@ class IndexView(CreateView):
 
     @cache_control(no_cache=True, must_revalidate=True, no_store=True)
     def get(self, request, *args, **kwargs):
-        for session_var in ['specs', 'user', 'billing_address_data',
-                            'pricing_name']:
-            if session_var in request.session:
-                del request.session[session_var]
+        clear_all_session_vars(request)
         return HttpResponseRedirect(reverse('datacenterlight:cms_index'))
 
     def post(self, request):
         cores = request.POST.get('cpu')
         cores_field = forms.IntegerField(validators=[self.validate_cores])
         memory = request.POST.get('ram')
-        memory_field = forms.IntegerField(validators=[self.validate_memory])
+        memory_field = forms.FloatField(validators=[self.validate_memory])
         storage = request.POST.get('storage')
         storage_field = forms.IntegerField(validators=[self.validate_storage])
         template_id = int(request.POST.get('config'))
@@ -170,7 +197,7 @@ class IndexView(CreateView):
             'vat': vat,
             'vat_percent': vat_percent,
             'discount': discount,
-            'total_price': price + vat - discount['amount'],
+            'total_price': round(price + vat - discount['amount'], 2),
             'pricing_name': vm_pricing_name
         }
         request.session['specs'] = specs
@@ -242,19 +269,93 @@ class PaymentOrderView(FormView):
             'login_form': HostingUserLoginForm(prefix='login_form'),
             'billing_address_form': billing_address_form,
             'cms_integration': get_cms_integration('default'),
-            'vm_pricing': VMPricing.get_vm_pricing_by_name(
-                self.request.session['specs']['pricing_name']
-            )
         })
+
+        if ('generic_payment_type' in self.request.session and
+                self.request.session['generic_payment_type'] == 'generic'):
+            if 'product_id' in self.request.session:
+                product = GenericProduct.objects.get(
+                    id=self.request.session['product_id']
+                )
+                context.update({'generic_payment_form': ProductPaymentForm(
+                    prefix='generic_payment_form',
+                    initial={'product_name': product.product_name,
+                             'amount': float(product.get_actual_price()),
+                             'recurring': product.product_is_subscription,
+                             'description': product.product_description,
+                             },
+                    product_id=product.id
+                ), })
+            else:
+                context.update({'generic_payment_form': GenericPaymentForm(
+                    prefix='generic_payment_form',
+                ), })
+        else:
+            context.update({
+                'vm_pricing': VMPricing.get_vm_pricing_by_name(
+                    self.request.session['specs']['pricing_name']
+                )
+            })
+
         return context
 
     @cache_control(no_cache=True, must_revalidate=True, no_store=True)
     def get(self, request, *args, **kwargs):
-        if 'specs' not in request.session:
+        if (('type' in request.GET and request.GET['type'] == 'generic')
+                or 'product_slug' in kwargs):
+            request.session['generic_payment_type'] = 'generic'
+            if 'generic_payment_details' in request.session:
+                request.session.pop('generic_payment_details')
+                request.session.pop('product_id')
+            if 'product_slug' in kwargs:
+                logger.debug("Product slug is " + kwargs['product_slug'])
+                try:
+                    product = GenericProduct.objects.get(
+                        product_slug=kwargs['product_slug']
+                    )
+                except GenericProduct.DoesNotExist as dne:
+                    logger.error(
+                        "Product '{}' does "
+                        "not exist".format(kwargs['product_slug'])
+                    )
+                    raise Http404()
+                request.session['product_id'] = product.id
+        elif 'specs' not in request.session:
             return HttpResponseRedirect(reverse('datacenterlight:index'))
         return self.render_to_response(self.get_context_data())
 
     def post(self, request, *args, **kwargs):
+        if 'product' in request.POST:
+            # query for the supplied product
+            product = None
+            try:
+                product = GenericProduct.objects.get(
+                    id=request.POST['generic_payment_form-product_name']
+                )
+            except GenericProduct.DoesNotExist as dne:
+                logger.error(
+                    "The requested product '{}' does not exist".format(
+                        request.POST['generic_payment_form-product_name']
+                    )
+                )
+            except GenericProduct.MultipleObjectsReturned as mpe:
+                logger.error(
+                    "There seem to be more than one product with "
+                    "the name {}".format(
+                        request.POST['generic_payment_form-product_name']
+                    )
+                )
+                product = GenericProduct.objects.all(
+                    product_name=request.
+                    POST['generic_payment_form-product_name']
+                ).first()
+            if product is None:
+                return JsonResponse({})
+            else:
+                return JsonResponse({
+                    'amount': product.get_actual_price(),
+                    'isSubscription': product.product_is_subscription
+                })
         if 'login_form' in request.POST:
             login_form = HostingUserLoginForm(
                 data=request.POST, prefix='login_form'
@@ -265,6 +366,13 @@ class PaymentOrderView(FormView):
                 auth_user = authenticate(email=email, password=password)
                 if auth_user:
                     login(self.request, auth_user)
+                    if 'product_slug' in kwargs:
+                        return HttpResponseRedirect(
+                            reverse('show_product',
+                                    kwargs={
+                                        'product_slug': kwargs['product_slug']}
+                                    )
+                        )
                     return HttpResponseRedirect(
                         reverse('datacenterlight:payment')
                     )
@@ -281,6 +389,50 @@ class PaymentOrderView(FormView):
                 data=request.POST,
             )
         if address_form.is_valid():
+            # Check if we are in a generic payment case and handle the generic
+            # payment details form before we go on to verify payment
+            if ('generic_payment_type' in request.session and
+                    self.request.session['generic_payment_type'] == 'generic'):
+                if 'product_id' in request.session:
+                    generic_payment_form = ProductPaymentForm(
+                        data=request.POST, prefix='generic_payment_form',
+                        product_id=request.session['product_id']
+                    )
+                else:
+                    generic_payment_form = GenericPaymentForm(
+                        data=request.POST, prefix='generic_payment_form'
+                    )
+                if generic_payment_form.is_valid():
+                    logger.debug("Generic payment form is valid.")
+                    if 'product_id' in request.session:
+                        product = generic_payment_form.product
+                    else:
+                        product = generic_payment_form.cleaned_data.get(
+                            'product_name'
+                        )
+                    gp_details = {
+                        "product_name": product.product_name,
+                        "amount": generic_payment_form.cleaned_data.get(
+                            'amount'
+                        ),
+                        "recurring": generic_payment_form.cleaned_data.get(
+                            'recurring'
+                        ),
+                        "description": generic_payment_form.cleaned_data.get(
+                            'description'
+                        ),
+                        "product_id": product.id,
+                        "product_slug": product.product_slug
+                    }
+                    request.session["generic_payment_details"] = (
+                        gp_details
+                    )
+                else:
+                    logger.debug("Generic payment form invalid")
+                    context = self.get_context_data()
+                    context['generic_payment_form'] = generic_payment_form
+                    context['billing_address_form'] = address_form
+                    return self.render_to_response(context)
             token = address_form.cleaned_data.get('token')
             if token is '':
                 card_id = address_form.cleaned_data.get('card')
@@ -296,8 +448,8 @@ class PaymentOrderView(FormView):
                 except UserCardDetail.DoesNotExist as e:
                     ex = str(e)
                     logger.error("Card Id: {card_id}, Exception: {ex}".format(
-                            card_id=card_id, ex=ex
-                        )
+                        card_id=card_id, ex=ex
+                    )
                     )
                     msg = _("An error occurred. Details: {}".format(ex))
                     messages.add_message(
@@ -386,7 +538,8 @@ class OrderConfirmationView(DetailView):
     @cache_control(no_cache=True, must_revalidate=True, no_store=True)
     def get(self, request, *args, **kwargs):
         context = {}
-        if 'specs' not in request.session or 'user' not in request.session:
+        if (('specs' not in request.session or 'user' not in request.session)
+                and 'generic_payment_type' not in request.session):
             return HttpResponseRedirect(reverse('datacenterlight:index'))
         if 'token' in self.request.session:
             token = self.request.session['token']
@@ -404,9 +557,19 @@ class OrderConfirmationView(DetailView):
             card_detail = UserCardDetail.objects.get(id=card_id)
             context['cc_last4'] = card_detail.last4
             context['cc_brand'] = card_detail.brand
+
+        if ('generic_payment_type' in request.session and
+                self.request.session['generic_payment_type'] == 'generic'):
+            context.update({
+                'generic_payment_details':
+                    request.session['generic_payment_details'],
+            })
+        else:
+            context.update({
+                'vm': request.session.get('specs'),
+            })
         context.update({
             'site_url': reverse('datacenterlight:index'),
-            'vm': request.session.get('specs'),
             'page_header_text': _('Confirm Order'),
             'billing_address_data': (
                 request.session.get('billing_address_data')
@@ -416,11 +579,8 @@ class OrderConfirmationView(DetailView):
         return render(request, self.template_name, context)
 
     def post(self, request, *args, **kwargs):
-        template = request.session.get('template')
-        specs = request.session.get('specs')
         user = request.session.get('user')
         stripe_api_cus_id = request.session.get('customer')
-        vm_template_id = template.get('id', 1)
         stripe_utils = StripeUtils()
 
         if 'token' in request.session:
@@ -434,7 +594,14 @@ class OrderConfirmationView(DetailView):
                 response = {
                     'status': False,
                     'redirect': "{url}#{section}".format(
-                        url=reverse('datacenterlight:payment'),
+                        url=(reverse(
+                            'show_product',
+                            kwargs={'product_slug':
+                                    request.session['generic_payment_details']
+                                    ['product_slug']}
+                        ) if 'generic_payment_details' in request.session else
+                                reverse('datacenterlight:payment')
+                        ),
                         section='payment_error'),
                     'msg_title': str(_('Error.')),
                     'msg_body': str(
@@ -450,7 +617,8 @@ class OrderConfirmationView(DetailView):
                 'brand': card_details_response['brand'],
                 'card_id': card_details_response['card_id']
             }
-            stripe_customer_obj = StripeCustomer.objects.filter(stripe_id=stripe_api_cus_id).first()
+            stripe_customer_obj = StripeCustomer.objects.filter(
+                stripe_id=stripe_api_cus_id).first()
             if stripe_customer_obj:
                 ucd = UserCardDetail.get_user_card_details(
                     stripe_customer_obj, card_details_response
@@ -472,7 +640,16 @@ class OrderConfirmationView(DetailView):
                         response = {
                             'status': False,
                             'redirect': "{url}#{section}".format(
-                                url=reverse('hosting:payment'),
+                                url=(reverse(
+                                    'show_product',
+                                    kwargs={'product_slug':
+                                            request.session
+                                            ['generic_payment_details']
+                                            ['product_slug']}
+                                    ) if 'generic_payment_details' in
+                                     request.session else
+                                     reverse('datacenterlight:payment')
+                                ),
                                 section='payment_error'),
                             'msg_title': str(_('Error.')),
                             'msg_body': str(
@@ -504,51 +681,122 @@ class OrderConfirmationView(DetailView):
             }
             return JsonResponse(response)
 
-        cpu = specs.get('cpu')
-        memory = specs.get('memory')
-        disk_size = specs.get('disk_size')
-        amount_to_be_charged = specs.get('total_price')
-        plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
-                                                     memory=memory,
-                                                     disk_size=disk_size)
-        stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu,
-                                                        ram=memory,
-                                                        ssd=disk_size,
-                                                        version=1,
-                                                        app='dcl')
-        stripe_plan = stripe_utils.get_or_create_stripe_plan(
-            amount=amount_to_be_charged,
-            name=plan_name,
-            stripe_plan_id=stripe_plan_id)
-        subscription_result = stripe_utils.subscribe_customer_to_plan(
-            stripe_api_cus_id,
-            [{"plan": stripe_plan.get(
-                'response_object').stripe_plan_id}])
-        stripe_subscription_obj = subscription_result.get('response_object')
-        # Check if the subscription was approved and is active
-        if (stripe_subscription_obj is None
-                or stripe_subscription_obj.status != 'active'):
-            # At this point, we have created a Stripe API card and
-            # associated it with the customer; but the transaction failed
-            # due to some reason. So, we would want to dissociate this card
-            # here.
-            # ...
+        if ('generic_payment_type' in request.session and
+                self.request.session['generic_payment_type'] == 'generic'):
+            gp_details = self.request.session['generic_payment_details']
+            if gp_details['recurring']:
+                # generic recurring payment
+                logger.debug("Commencing a generic recurring payment")
+            else:
+                # generic one time payment
+                logger.debug("Commencing a one time payment")
+                charge_response = stripe_utils.make_charge(
+                    amount=gp_details['amount'],
+                    customer=stripe_api_cus_id
+                )
+                stripe_onetime_charge = charge_response.get('response_object')
 
-            msg = subscription_result.get('error')
-            messages.add_message(self.request, messages.ERROR, msg,
-                                 extra_tags='failed_payment')
-            response = {
-                'status': False,
-                'redirect': "{url}#{section}".format(
-                    url=reverse('datacenterlight:payment'),
-                    section='payment_error'),
-                'msg_title': str(_('Error.')),
-                'msg_body': str(
-                    _('There was a payment related error.'
-                      ' On close of this popup, you will be redirected back to'
-                      ' the payment page.'))
-            }
-            return JsonResponse(response)
+                # Check if the payment was approved
+                if not stripe_onetime_charge:
+                    msg = charge_response.get('error')
+                    messages.add_message(self.request, messages.ERROR, msg,
+                                         extra_tags='failed_payment')
+                    response = {
+                        'status': False,
+                        'redirect': "{url}#{section}".format(
+                            url=(reverse('show_product', kwargs={
+                                'product_slug': gp_details['product_slug']}
+                                         ) if 'generic_payment_details' in
+                                              request.session else
+                                 reverse('datacenterlight:payment')
+                                 ),
+                            section='payment_error'),
+                        'msg_title': str(_('Error.')),
+                        'msg_body': str(
+                            _('There was a payment related error.'
+                              ' On close of this popup, you will be redirected'
+                              ' back to the payment page.'))
+                    }
+                    return JsonResponse(response)
+
+        if ('generic_payment_type' not in request.session or
+                (request.session['generic_payment_details']['recurring'])):
+            if 'generic_payment_details' in request.session:
+                amount_to_be_charged = (
+                    round(
+                        request.session['generic_payment_details']['amount'],
+                        2
+                    )
+                )
+                plan_name = "generic-{0}-{1:.2f}".format(
+                    request.session['generic_payment_details']['product_id'],
+                    amount_to_be_charged
+                )
+                stripe_plan_id = plan_name
+            else:
+                template = request.session.get('template')
+                specs = request.session.get('specs')
+                vm_template_id = template.get('id', 1)
+
+                cpu = specs.get('cpu')
+                memory = specs.get('memory')
+                disk_size = specs.get('disk_size')
+                amount_to_be_charged = specs.get('total_price')
+                plan_name = StripeUtils.get_stripe_plan_name(
+                    cpu=cpu,
+                    memory=memory,
+                    disk_size=disk_size,
+                    price=amount_to_be_charged
+                )
+                stripe_plan_id = StripeUtils.get_stripe_plan_id(
+                    cpu=cpu,
+                    ram=memory,
+                    ssd=disk_size,
+                    version=1,
+                    app='dcl',
+                    price=amount_to_be_charged
+                )
+            stripe_plan = stripe_utils.get_or_create_stripe_plan(
+                amount=amount_to_be_charged,
+                name=plan_name,
+                stripe_plan_id=stripe_plan_id)
+            subscription_result = stripe_utils.subscribe_customer_to_plan(
+                stripe_api_cus_id,
+                [{"plan": stripe_plan.get(
+                    'response_object').stripe_plan_id}])
+            stripe_subscription_obj = subscription_result.get('response_object')
+            # Check if the subscription was approved and is active
+            if (stripe_subscription_obj is None
+                    or stripe_subscription_obj.status != 'active'):
+                # At this point, we have created a Stripe API card and
+                # associated it with the customer; but the transaction failed
+                # due to some reason. So, we would want to dissociate this card
+                # here.
+                # ...
+
+                msg = subscription_result.get('error')
+                messages.add_message(self.request, messages.ERROR, msg,
+                                     extra_tags='failed_payment')
+                response = {
+                    'status': False,
+                    'redirect': "{url}#{section}".format(
+                        url=(reverse(
+                            'show_product',
+                            kwargs={'product_slug':
+                                    request.session['generic_payment_details']
+                                    ['product_slug']}
+                        ) if 'generic_payment_details' in request.session else
+                                reverse('datacenterlight:payment')
+                        ),
+                        section='payment_error'
+                    ),
+                    'msg_title': str(_('Error.')),
+                    'msg_body': str(
+                        _('There was a payment related error.'
+                          ' On close of this popup, you will be redirected back to'
+                          ' the payment page.'))
+                }
+                return JsonResponse(response)
 
         # Create user if the user is not logged in and if he is not already
         # registered
@@ -618,6 +866,118 @@ class OrderConfirmationView(DetailView):
             'user': custom_user.id
         })
 
+        if 'generic_payment_type' in request.session:
+            stripe_cus = StripeCustomer.objects.filter(
+                stripe_id=stripe_api_cus_id
+            ).first()
+            billing_address = BillingAddress(
+                cardholder_name=billing_address_data['cardholder_name'],
+                street_address=billing_address_data['street_address'],
+                city=billing_address_data['city'],
+                postal_code=billing_address_data['postal_code'],
+                country=billing_address_data['country']
+            )
+            billing_address.save()
+
+            order = HostingOrder.create(
+                price=self.request
+                          .session['generic_payment_details']['amount'],
+                customer=stripe_cus,
+                billing_address=billing_address,
+                vm_pricing=VMPricing.get_default_pricing()
+            )
+
+            # Create a Hosting Bill
+            HostingBill.create(customer=stripe_cus,
+                               billing_address=billing_address)
+
+            # Create Billing Address for User if he does not have one
+            if not stripe_cus.user.billing_addresses.count():
+                billing_address_data.update({
+                    'user': stripe_cus.user.id
+                })
+                billing_address_user_form = UserBillingAddressForm(
+                    billing_address_data
+                )
+                billing_address_user_form.is_valid()
+                billing_address_user_form.save()
+
+            if self.request.session['generic_payment_details']['recurring']:
+                # Associate the given stripe subscription with the order
+                order.set_subscription_id(
+                    stripe_subscription_obj.id, card_details_dict
+                )
+            else:
+                # Associate the given stripe charge id with the order
+                order.set_stripe_charge(stripe_onetime_charge)
+
+            # Set order status approved
+            order.set_approved()
+            order.generic_payment_description = gp_details["description"]
+            order.generic_product_id = gp_details["product_id"]
+            order.save()
+            # send emails
+            context = {
+                'name': user.get('name'),
+                'email': user.get('email'),
+                'amount': gp_details['amount'],
+                'description': gp_details['description'],
+                'recurring': gp_details['recurring'],
+                'product_name': gp_details['product_name'],
+                'product_id': gp_details['product_id'],
+                'order_id': order.id
+            }
+
+            email_data = {
+                'subject': (settings.DCL_TEXT +
+                            " Payment received from %s" % context['email']),
+                'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
+                'to': ['info@ungleich.ch'],
+                'body': "\n".join(
+                    ["%s=%s" % (k, v) for (k, v) in context.items()]),
+                'reply_to': [context['email']],
+            }
+            send_plain_email_task.delay(email_data)
+
+            email_data = {
+                'subject': _("Confirmation of your payment"),
+                'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
+                'to': [user.get('email')],
+                'body': _("Hi {name},\n\n"
+                          "thank you for your order!\n"
+                          "We have just received a payment of CHF {amount:.2f}"
+                          " from you.{recurring}\n\n"
+                          "Cheers,\nYour Data Center Light team".format(
+                                 name=user.get('name'),
+                                 amount=gp_details['amount'],
+                                 recurring=(
+                                     _(' This is a monthly recurring plan.')
+                                     if gp_details['recurring'] else ''
+                                 )
+                             )
+                          ),
+                'reply_to': ['info@ungleich.ch'],
+            }
+            send_plain_email_task.delay(email_data)
+
+            response = {
+                'status': True,
+                'redirect': (
+                    reverse('hosting:orders')
+                    if request.user.is_authenticated()
+                    else reverse('datacenterlight:index')
+                ),
+                'msg_title': str(_('Thank you for the payment.')),
+                'msg_body': str(
+                    _('You will soon receive a confirmation email of the '
+                      'payment. You can always contact us at '
+                      'info@ungleich.ch for any question that you may have.')
+                )
+            }
+            clear_all_session_vars(request)
+
+            return JsonResponse(response)
+
         user = {
             'name': custom_user.name,
             'email': custom_user.email,
diff --git a/dynamicweb/urls.py b/dynamicweb/urls.py
index 7e2d58a1..37bb69a4 100644
--- a/dynamicweb/urls.py
+++ b/dynamicweb/urls.py
@@ -10,6 +10,7 @@ from django.conf import settings
 from hosting.views import (
     RailsHostingView, DjangoHostingView, NodeJSHostingView
 )
+from datacenterlight.views import PaymentOrderView
 from membership import urls as membership_urls
 from ungleich_page.views import LandingView
 from django.views.generic import RedirectView
@@ -29,6 +30,9 @@ urlpatterns = [
     url(r'^nosystemd/', include('nosystemd.urls', namespace="nosystemd")),
     url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')),
     url(r'^jsi18n/(?P<packages>\S+?)/$', i18n.javascript_catalog),
+    url(r'^product/(?P<product_slug>[\w-]+)/$',
+        PaymentOrderView.as_view(),
+        name='show_product'),
 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
 
 urlpatterns += i18n_patterns(
diff --git a/hosting/admin.py b/hosting/admin.py
index 6ebe461d..dc476b43 100644
--- a/hosting/admin.py
+++ b/hosting/admin.py
@@ -1,8 +1,8 @@
 from django.contrib import admin
 
-from .models import HostingOrder, HostingBill, HostingPlan
-
+from .models import HostingOrder, HostingBill, HostingPlan, GenericProduct
 
 admin.site.register(HostingOrder)
 admin.site.register(HostingBill)
 admin.site.register(HostingPlan)
+admin.site.register(GenericProduct)
diff --git a/hosting/forms.py b/hosting/forms.py
index 7beab60f..16b06fe0 100644
--- a/hosting/forms.py
+++ b/hosting/forms.py
@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
 
 from membership.models import CustomUser
 from utils.hosting_utils import get_all_public_keys
-from .models import UserHostingKey
+from .models import UserHostingKey, GenericProduct
 
 logger = logging.getLogger(__name__)
 
@@ -52,6 +52,93 @@ class HostingUserLoginForm(forms.Form):
             raise forms.ValidationError(_("User does not exist"))
 
 
+class ProductModelChoiceField(forms.ModelChoiceField):
+    def label_from_instance(self, obj):
+        return obj.product_name
+
+
+class GenericPaymentForm(forms.Form):
+    product_name = ProductModelChoiceField(
+        queryset=GenericProduct.objects.all().order_by('product_name'),
+        empty_label=_("Choose a product"),
+    )
+    amount = forms.FloatField(
+        widget=forms.TextInput(
+            attrs={'placeholder': _('Amount in CHF'),
+                   'readonly': 'readonly', }
+        ),
+        max_value=999999,
+        min_value=1,
+        label=_('Amount in CHF')
+    )
+    recurring = forms.BooleanField(required=False,
+                                   label=_("Recurring monthly"), )
+    description = forms.CharField(
+        widget=forms.Textarea(attrs={'style': "height: 60px;"}),
+        required=False
+    )
+
+    class Meta:
+        model = GenericProduct
+        fields = ['product_name', 'amount', 'recurring', 'description']
+
+    def clean_amount(self):
+        amount = self.cleaned_data.get('amount')
+        if (float(self.cleaned_data.get('product_name').get_actual_price()) !=
+                amount):
+            raise forms.ValidationError(_("Amount field does not match"))
+        return amount
+
+    def clean_recurring(self):
+        recurring = self.cleaned_data.get('recurring')
+        if (self.cleaned_data.get('product_name').product_is_subscription !=
+                (True if recurring else False)):
+            raise forms.ValidationError(_("Recurring field does not match"))
+        return recurring
+
+
+class ProductPaymentForm(GenericPaymentForm):
+    def __init__(self, *args, **kwargs):
+        product_id = kwargs.pop('product_id', None)
+        if product_id is not None:
+            self.product = GenericProduct.objects.get(id=product_id)
+        super(ProductPaymentForm, self).__init__(*args, **kwargs)
+        self.fields['product_name'] = forms.CharField(
+            widget=forms.TextInput(
+                attrs={'placeholder': _('Product name'),
+                       'readonly': 'readonly'}
+            )
+        )
+        if self.product.product_is_subscription:
+            self.fields['amount'].label = "{amt} ({payment_type})".format(
+                amt=_('Amount in CHF'),
+                payment_type=_('Monthly subscription')
+            )
+        else:
+            self.fields['amount'].label = "{amt} ({payment_type})".format(
+                amt=_('Amount in CHF'),
+                payment_type=_('One time payment')
+            )
+        self.fields['recurring'].widget = forms.HiddenInput()
+        self.fields['product_name'].widget.attrs['class'] = 'input-no-border'
+        self.fields['amount'].widget.attrs['class'] = 'input-no-border'
+        self.fields['description'].widget.attrs['class'] = 'input-no-border'
+
+    def clean_amount(self):
+        amount = self.cleaned_data.get('amount')
+        if (self.product is None or
+                float(self.product.get_actual_price()) != amount):
+            raise forms.ValidationError(_("Amount field does not match"))
+        return amount
+
+    def clean_recurring(self):
+        recurring = self.cleaned_data.get('recurring')
+        if (self.product.product_is_subscription !=
+                (True if recurring else False)):
+            raise forms.ValidationError(_("Recurring field does not match"))
+        return recurring
+
+
 class HostingUserSignupForm(forms.ModelForm):
     confirm_password = forms.CharField(label=_("Confirm Password"),
                                        widget=forms.PasswordInput())
@@ -111,7 +198,7 @@ class UserHostingKeyForm(forms.ModelForm):
                 public_key=openssh_pubkey_str).first().name
             KEY_EXISTS_MESSAGE = _(
                 "This key exists already with the name \"%(name)s\"") % {
-                'name': key_name}
+                                     'name': key_name}
             raise forms.ValidationError(KEY_EXISTS_MESSAGE)
 
         with tempfile.NamedTemporaryFile(delete=True) as tmp_public_key_file:
diff --git a/hosting/locale/de/LC_MESSAGES/django.po b/hosting/locale/de/LC_MESSAGES/django.po
index 95515355..0e337cfb 100644
--- a/hosting/locale/de/LC_MESSAGES/django.po
+++ b/hosting/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-07-05 23:15+0000\n"
+"POT-Creation-Date: 2018-09-08 08:45+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -209,7 +209,7 @@ msgstr "Du hast eine neue virtuelle Maschine bestellt!"
 
 #, python-format
 msgid "Your order of <strong>%(vm_name)s</strong> has been charged."
-msgstr "Deine Bestellung von <strong>%(vm_name)s</strong> wurde erhoben."
+msgstr "Deine Bestellung von <strong>%(vm_name)s</strong> wurde entgegengenommen."
 
 msgid "You can view your VM detail by clicking the button below."
 msgstr "Um die Rechnung zu sehen, klicke auf den Button unten."
@@ -222,7 +222,7 @@ msgstr "Dein Data Center Light Team"
 
 #, python-format
 msgid "Your order of %(vm_name)s has been charged."
-msgstr "Deine Bestellung von %(vm_name)s wurde erhoben."
+msgstr "Deine Bestellung von %(vm_name)s wurde entgegengenommen."
 
 msgid "You can view your VM detail by following the link below."
 msgstr "Um die Rechnung zu sehen, klicke auf den Link unten."
@@ -249,7 +249,7 @@ msgstr "VM Kündigung"
 
 #, python-format
 msgid ""
-"You are receiving this email because your virutal machine <strong>"
+"You are receiving this email because your virtual machine <strong>"
 "%(vm_name)s</strong> has been cancelled."
 msgstr ""
 "Du erhälst diese E-Mail, da deine virtuelle Maschine <strong>%(vm_name)s</"
@@ -265,7 +265,7 @@ msgstr "NEUE VM"
 
 #, python-format
 msgid ""
-"You are receiving this email because your virutal machine %(vm_name)s has "
+"You are receiving this email because your virtual machine %(vm_name)s has "
 "been cancelled."
 msgstr ""
 "Du erhälst diese E-Mail, da deine virtuelle Maschine %(vm_name)s gekündigt "
@@ -290,9 +290,8 @@ msgid ""
 "You are not making any payment yet. After placing your order, you will be "
 "taken to the Submit Payment Page."
 msgstr ""
-"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst "
-"ausgelöst, nachdem Du die Bestellung auf der nächsten Seite bestätigt "
-"hast."
+"Es wird noch keine Bezahlung vorgenommen. Die Bezahlung wird erst ausgelöst, "
+"nachdem Du die Bestellung auf der nächsten Seite bestätigt hast."
 
 msgid "SUBMIT"
 msgstr "ABSENDEN"
@@ -469,9 +468,9 @@ msgid ""
 "database."
 msgstr ""
 "Bitte wähle eine der zuvor genutzten Kreditkarten oder gib Deine "
-"Kreditkartendetails unten an. Die Bezahlung wird über "
-"<a href=\"https://stripe.com\" target=\"_blank\">Stripe</a> abgewickelt. "
-"Wir speichern Deine Kreditkartendetails nicht in unserer Datenbank."
+"Kreditkartendetails unten an. Die Bezahlung wird über <a href=\"https://"
+"stripe.com\" target=\"_blank\">Stripe</a> abgewickelt. Wir speichern Deine "
+"Kreditkartendetails nicht in unserer Datenbank."
 
 msgid ""
 "Please fill in your credit card information below. We are using <a href="
@@ -631,6 +630,12 @@ msgstr ""
 "Bitte entschuldige, es scheint ein unerwarteter Fehler aufgetreten zu sein. "
 "Versuche es doch bitte noch einmal."
 
+msgid "Attention:"
+msgstr "Achtung:"
+
+msgid "terminating VM can not be reverted."
+msgstr "Das Beenden kann nicht rückgängig gemacht werden."
+
 msgid "Something doesn't work?"
 msgstr "Etwas funktioniert nicht?"
 
@@ -643,8 +648,12 @@ msgstr "KONTAKT"
 msgid "Terminate your Virtual Machine"
 msgstr "Deine Virtuelle Maschine beenden"
 
-msgid "Do you want to cancel your Virtual Machine"
-msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst"
+msgid ""
+"Terminated VMs can not be revived and will not be refunded. Do you want to "
+"terminate your VM?"
+msgstr ""
+"Beendete VMs können nicht wiederhergestellt oder erstattet werden. Möchtest "
+"du die VM beenden?"
 
 #, python-format
 msgid ""
@@ -723,8 +732,8 @@ msgstr "Es scheint, als hättest du diese Karte bereits hinzugefügt"
 
 #, python-brace-format
 msgid "An error occurred while associating the card. Details: {details}"
-msgstr "Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: "
-"{details}"
+msgstr ""
+"Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: {details}"
 
 msgid "Successfully associated the card with your account"
 msgstr "Die Karte wurde erfolgreich mit deinem Konto verbunden"
@@ -798,6 +807,11 @@ msgstr ""
 msgid "Error terminating VM"
 msgstr "Fehler beenden VM"
 
+msgid ""
+"VM terminate action timed out. Please contact support@datacenterlight.ch for "
+"further information."
+msgstr ""
+
 #, python-format
 msgid "Virtual Machine %(vm_name)s Cancelled"
 msgstr "Virtuelle Maschine %(vm_name)s Kündigung"
@@ -807,6 +821,9 @@ msgstr ""
 "Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte versuche es "
 "noch einmal."
 
+#~ msgid "Do you want to cancel your Virtual Machine"
+#~ msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst"
+
 #~ msgid "Reset your password"
 #~ msgstr "Passwort zurücksetzen"
 
diff --git a/hosting/migrations/0048_auto_20181003_0757.py b/hosting/migrations/0048_auto_20181003_0757.py
new file mode 100644
index 00000000..7b80958a
--- /dev/null
+++ b/hosting/migrations/0048_auto_20181003_0757.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-10-03 07:57
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import utils.mixins
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('hosting', '0047_auto_20180821_1240'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='GenericProduct',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('product_name', models.CharField(default='', max_length=128)),
+                ('product_slug', models.SlugField(help_text='An optional html id for the Section. Required to set as target of a link on page', unique=True)),
+                ('product_description', models.CharField(default='', max_length=500)),
+                ('created_at', models.DateTimeField(auto_now_add=True)),
+                ('product_price', models.DecimalField(decimal_places=2, max_digits=6)),
+                ('product_vat', models.DecimalField(decimal_places=4, default=0, max_digits=6)),
+                ('product_is_subscription', models.BooleanField(default=True)),
+            ],
+            bases=(utils.mixins.AssignPermissionsMixin, models.Model),
+        ),
+        migrations.AddField(
+            model_name='hostingorder',
+            name='generic_payment_description',
+            field=models.CharField(max_length=500, null=True),
+        ),
+        migrations.AddField(
+            model_name='hostingorder',
+            name='generic_product',
+            field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='hosting.GenericProduct'),
+        ),
+    ]
diff --git a/hosting/migrations/0049_auto_20181005_0736.py b/hosting/migrations/0049_auto_20181005_0736.py
new file mode 100644
index 00000000..b091ef45
--- /dev/null
+++ b/hosting/migrations/0049_auto_20181005_0736.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2018-10-05 07:36
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('hosting', '0048_auto_20181003_0757'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='genericproduct',
+            name='product_slug',
+            field=models.SlugField(help_text='An mandatory unique slug for the product', unique=True),
+        ),
+    ]
diff --git a/hosting/models.py b/hosting/models.py
index abc4c428..707b072d 100644
--- a/hosting/models.py
+++ b/hosting/models.py
@@ -9,8 +9,8 @@ from django.utils.functional import cached_property
 
 from datacenterlight.models import VMPricing, VMTemplate
 from membership.models import StripeCustomer, CustomUser
-from utils.models import BillingAddress
 from utils.mixins import AssignPermissionsMixin
+from utils.models import BillingAddress
 from utils.stripe_utils import StripeUtils
 
 logger = logging.getLogger(__name__)
@@ -61,6 +61,30 @@ class OrderDetail(AssignPermissionsMixin, models.Model):
         )
 
 
+class GenericProduct(AssignPermissionsMixin, models.Model):
+    permissions = ('view_genericproduct',)
+    product_name = models.CharField(max_length=128, default="")
+    product_slug = models.SlugField(
+        unique=True,
+        help_text=(
+            'An mandatory unique slug for the product'
+        )
+    )
+    product_description = models.CharField(max_length=500, default="")
+    created_at = models.DateTimeField(auto_now_add=True)
+    product_price = models.DecimalField(max_digits=6, decimal_places=2)
+    product_vat = models.DecimalField(max_digits=6, decimal_places=4, default=0)
+    product_is_subscription = models.BooleanField(default=True)
+
+    def __str__(self):
+        return self.product_name
+
+    def get_actual_price(self):
+        return round(
+            self.product_price + (self.product_price * self.product_vat), 2
+        )
+
+
 class HostingOrder(AssignPermissionsMixin, models.Model):
     ORDER_APPROVED_STATUS = 'Approved'
     ORDER_DECLINED_STATUS = 'Declined'
@@ -80,7 +104,13 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
         OrderDetail, null=True, blank=True, default=None,
         on_delete=models.SET_NULL
     )
-
+    generic_product = models.ForeignKey(
+        GenericProduct, null=True, blank=True, default=None,
+        on_delete=models.SET_NULL
+    )
+    generic_payment_description = models.CharField(
+        max_length=500, null=True
+    )
     permissions = ('view_hostingorder',)
 
     class Meta:
@@ -89,11 +119,18 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
         )
 
     def __str__(self):
-        return ("Order Nr: #{} - VM_ID: {} - {} - {} - "
-                "Specs: {} - Price: {}").format(
+        hosting_order_str = ("Order Nr: #{} - VM_ID: {} - {} - {} - "
+                             "Specs: {} - Price: {}").format(
             self.id, self.vm_id, self.customer.user.email, self.created_at,
             self.order_detail, self.price
         )
+        if self.generic_product_id is not None:
+            hosting_order_str += " - Generic Payment"
+            if self.stripe_charge_id is not None:
+                hosting_order_str += " - One time charge"
+            else:
+                hosting_order_str += " - Recurring"
+        return hosting_order_str
 
     @cached_property
     def status(self):
diff --git a/hosting/static/hosting/css/virtual-machine.css b/hosting/static/hosting/css/virtual-machine.css
index 1c50776d..726b0f35 100644
--- a/hosting/static/hosting/css/virtual-machine.css
+++ b/hosting/static/hosting/css/virtual-machine.css
@@ -146,9 +146,13 @@
   text-align: center;
 }
 
+.vm-vmid-with-warning {
+  padding: 50px 0 33px !important;
+}
+
 .vm-vmid .alert {
   margin-top: 15px;
-  margin-bottom: -60px;
+  margin-bottom: -25px;
 }
 
 .vm-item-lg {
@@ -183,6 +187,13 @@
   margin-top: 25px;
 }
 
+.vm-terminate-warning {
+  letter-spacing: 0.6px;
+  font-size: 12px;
+  font-weight: 400;
+  color: #373636;
+}
+
 .vm-contact-us {
   margin: 25px 0 30px;
   /* text-align: center; */
diff --git a/hosting/static/hosting/js/initial.js b/hosting/static/hosting/js/initial.js
index 9c1c226e..6b6d744d 100644
--- a/hosting/static/hosting/js/initial.js
+++ b/hosting/static/hosting/js/initial.js
@@ -157,6 +157,10 @@ $( document ).ready(function() {
     /* ---------------------------------------------
      Scripts initialization
      --------------------------------------------- */
+    var minRam = 1;
+    if(window.minRam){
+        minRam = window.minRam;
+    }
     var cardPricing = {
         'cpu': {
             'id': 'coreValue',
@@ -168,7 +172,7 @@ $( document ).ready(function() {
         'ram': {
             'id': 'ramValue',
             'value': 2,
-            'min': 1,
+            'min': minRam,
             'max': 200,
             'interval': 1
         },
@@ -188,21 +192,54 @@ $( document ).ready(function() {
             var data = $(this).data('minus');
 
             if (cardPricing[data].value > cardPricing[data].min) {
-                cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval;
+                if(data === 'ram' && String(cardPricing[data].value) === "1" && minRam === 0.5){
+                    cardPricing[data].value = 0.5;
+                    $('#ramValue').val('0.5');
+                    $("#ramValue").attr('step', 0.5);
+                } else {
+                    cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval;
+                }
             }
             _fetchPricing();
+            $('#ramValue').data('old-value', $('#ramValue').val());
         });
         $('.fa-plus-circle.right').click(function(event) {
             var data = $(this).data('plus');
             if (cardPricing[data].value < cardPricing[data].max) {
-                cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval;
+                if(data === 'ram' && String(cardPricing[data].value) === "0.5" && minRam === 0.5){
+                    cardPricing[data].value = 1;
+                    $('#ramValue').val('1');
+                    $("#ramValue").attr('step', 1);
+                } else {
+                    cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval;
+                }
             }
             _fetchPricing();
+            $('#ramValue').data('old-value', $('#ramValue').val());
         });
 
         $('.input-price').change(function() {
             var data = $(this).attr("name");
-            cardPricing[data].value = $('input[name=' + data + ']').val();
+            var input = $('input[name=' + data + ']');
+            var inputValue = input.val();
+
+            if(data === 'ram') {
+                var ramInput = $('#ramValue');
+                if ($('#ramValue').data('old-value') < $('#ramValue').val()) {
+                    if($('#ramValue').val() === '1' && minRam === 0.5) {
+                        $("#ramValue").attr('step', 1);
+                        $('#ramValue').val('1');
+                    }
+                } else {
+                    if($('#ramValue').val() === '0' && minRam === 0.5) {
+                        $("#ramValue").attr('step', 0.5);
+                        $('#ramValue').val('0.5');
+                    }
+                }
+                inputValue = $('#ramValue').val();
+                $('#ramValue').data('old-value', $('#ramValue').val());
+            }
+            cardPricing[data].value = inputValue;
             _fetchPricing();
         });
     }
@@ -236,4 +273,5 @@ $( document ).ready(function() {
     }
 
     _initPricing();
-});
\ No newline at end of file
+    $('#ramValue').data('old-value', $('#ramValue').val());
+});
diff --git a/hosting/static/hosting/js/payment.js b/hosting/static/hosting/js/payment.js
index 4934fdd3..fa89f218 100644
--- a/hosting/static/hosting/js/payment.js
+++ b/hosting/static/hosting/js/payment.js
@@ -22,6 +22,39 @@ function setBrandIcon(brand) {
 
 
 $(document).ready(function () {
+    $(function () {
+        $("select#id_generic_payment_form-product_name").change(function () {
+            var gp_form = $('#generic-payment-form');
+            $.ajax({
+                url: gp_form.attr('action'),
+                type: 'POST',
+                data: gp_form.serialize(),
+                init: function () {
+                    console.log("init")
+                },
+                success: function (data) {
+                    if (data.amount !== undefined) {
+                        $("#id_generic_payment_form-amount").val(data.amount);
+                        if (data.isSubscription) {
+                            $('#id_generic_payment_form-recurring').prop('checked', true);
+                        } else {
+                            $('#id_generic_payment_form-recurring').prop('checked', false);
+                        }
+                    } else {
+                        $("#id_generic_payment_form-amount").val('');
+                        $('#id_generic_payment_form-recurring').prop('checked', false);
+                        console.log("No product found")
+                    }
+                },
+                error: function (xmlhttprequest, textstatus, message) {
+                    $("#id_generic_payment_form-amount").val('');
+                    $('#id_generic_payment_form-recurring').prop('checked', false);
+                    console.log("Error fetching product")
+                }
+            });
+        })
+    });
+
     $.ajaxSetup({
         beforeSend: function (xhr, settings) {
             function getCookie(name) {
@@ -124,17 +157,35 @@ $(document).ready(function () {
         $('#billing-form').submit();
     }
 
+    function getCookie(name) {
+        var value = "; " + document.cookie;
+        var parts = value.split("; " + name + "=");
+        if (parts.length === 2) return parts.pop().split(";").shift();
+    }
+
+    function submitBillingForm() {
+        var billing_form = $('#billing-form');
+        var recurring_input = $('#id_generic_payment_form-recurring');
+        billing_form.append('<input type="hidden" name="generic_payment_form-product_name" value="' + $('#id_generic_payment_form-product_name').val() + '" />');
+        billing_form.append('<input type="hidden" name="generic_payment_form-amount" value="' + $('#id_generic_payment_form-amount').val() + '" />');
+        if (recurring_input.attr('type') === 'hidden') {
+            billing_form.append('<input type="hidden" name="generic_payment_form-recurring" value="' + (recurring_input.val() === 'True' ? 'on' : '') + '" />');
+        } else {
+            billing_form.append('<input type="hidden" name="generic_payment_form-recurring" value="' + (recurring_input.prop('checked') ? 'on' : '') + '" />');
+        }
+        billing_form.append('<input type="hidden" name="generic_payment_form-description" value="' + $('#id_generic_payment_form-description').val() + '" />');
+        billing_form.submit();
+    }
 
     var $form_new = $('#payment-form-new');
     $form_new.submit(payWithStripe_new);
-
     function payWithStripe_new(e) {
         e.preventDefault();
 
         function stripeTokenHandler(token) {
             // Insert the token ID into the form so it gets submitted to the server
             $('#id_token').val(token.id);
-            $('#billing-form').submit();
+            submitBillingForm();
         }
 
 
@@ -196,10 +247,10 @@ $(document).ready(function () {
         }
     });
 
-    $('.credit-card-info .btn.choice-btn').click(function(){
-            var id = this.dataset['id_card'];
-            $('#id_card').val(id);
-            $('#billing-form').submit();
+    $('.credit-card-info .btn.choice-btn').click(function () {
+        var id = this.dataset['id_card'];
+        $('#id_card').val(id);
+        submitBillingForm();
     });
 });
 
diff --git a/hosting/static/hosting/js/virtual_machine_detail.js b/hosting/static/hosting/js/virtual_machine_detail.js
index 43a5a01d..8f90933b 100644
--- a/hosting/static/hosting/js/virtual_machine_detail.js
+++ b/hosting/static/hosting/js/virtual_machine_detail.js
@@ -134,3 +134,15 @@ $(document).ready(function() {
         $(this).find('.modal-footer .btn').addClass('hide');
     })
 });
+
+window.onload = function () {
+    var locale_dates = document.getElementsByClassName("locale_date");
+    var formats = ['YYYY-MM-DD hh:mm a'];
+    var i;
+    for (i = 0; i < locale_dates.length; i++) {
+        var oldDate = moment.utc(locale_dates[i].textContent, formats);
+        var outputFormat = locale_dates[i].getAttribute('data-format') || oldDate._f;
+        locale_dates[i].innerHTML = oldDate.local().format(outputFormat);
+        locale_dates[i].className += ' done';
+    }
+};
\ No newline at end of file
diff --git a/hosting/templates/hosting/emails/vm_canceled.html b/hosting/templates/hosting/emails/vm_canceled.html
index 9c2ec4c2..78781d5c 100644
--- a/hosting/templates/hosting/emails/vm_canceled.html
+++ b/hosting/templates/hosting/emails/vm_canceled.html
@@ -25,7 +25,7 @@
         <tr>
             <td style="padding-top: 25px; font-size: 16px;">
                 <p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
-                    {% blocktrans %}You are receiving this email because your virutal machine <strong>{{ vm_name }}</strong> has been cancelled.{% endblocktrans %}
+                    {% blocktrans %}You are receiving this email because your virtual machine <strong>{{ vm_name }}</strong> has been cancelled.{% endblocktrans %}
                 </p>
                 <p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
                     {% blocktrans %}You can always order a new VM by clicking the button below.{% endblocktrans %}
diff --git a/hosting/templates/hosting/emails/vm_canceled.txt b/hosting/templates/hosting/emails/vm_canceled.txt
index 9149a554..43263c40 100644
--- a/hosting/templates/hosting/emails/vm_canceled.txt
+++ b/hosting/templates/hosting/emails/vm_canceled.txt
@@ -2,7 +2,7 @@
 
 {% trans "Virtual Machine Cancellation" %}
 
-{% blocktrans %}You are receiving this email because your virutal machine {{vm_name}} has been cancelled.{% endblocktrans %}
+{% blocktrans %}You are receiving this email because your virtual machine {{vm_name}} has been cancelled.{% endblocktrans %}
 {% blocktrans %}You can always order a new VM by following the link below.{% endblocktrans %}
 
 {{ base_url }}{% url 'hosting:create_virtual_machine' %}
diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html
index e2e38c35..4a62e9fa 100644
--- a/hosting/templates/hosting/order_detail.html
+++ b/hosting/templates/hosting/order_detail.html
@@ -39,7 +39,7 @@
                     {% endif %}
                 </span>
             </p>
-            {% if order %}
+            {% if order and vm %}
                 <p>
                     <strong>{% trans "Status" %}: </strong>
                     <strong>
@@ -93,77 +93,104 @@
             <hr>
             <div>
                 <h4>{% trans "Order summary" %}</h4>
-                <p>
-                    <strong>{% trans "Product" %}:</strong>&nbsp;
-                    {% if vm.name %}
-                        {{ vm.name }}
-                    {% else %}
-                        {{ request.session.template.name }}
-                    {% endif %}
-                </p>
-                <div class="row">
-                    <div class="col-sm-6">
-                        {% if vm.created_at %}
-                            <p>
-                                <span>{% trans "Period" %}: </span>
-                                <span>
-                                    <span class="locale_date" data-format="YYYY/MM/DD">{{ vm.created_at|date:'Y-m-d h:i a' }}</span> - <span class="locale_date" data-format="YYYY/MM/DD">{{ subscription_end_date|date:'Y-m-d h:i a' }}</span>
-                                </span>
-                            </p>
+                {% if vm %}
+                    <p>
+                        <strong>{% trans "Product" %}:</strong>&nbsp;
+                        {% if vm.name %}
+                            {{ vm.name }}
+                        {% else %}
+                            {{ request.session.template.name }}
                         {% endif %}
-                        <p>
-                            <span>{% trans "Cores" %}: </span>
-                            {% if vm.cores %}
-                                <strong class="pull-right">{{vm.cores|floatformat}}</strong>
-                            {% else %}
-                                <strong class="pull-right">{{vm.cpu|floatformat}}</strong>
-                            {% endif %}
-                        </p>
-                        <p>
-                            <span>{% trans "Memory" %}: </span>
-                            <strong class="pull-right">{{vm.memory}} GB</strong>
-                        </p>
-                        <p>
-                            <span>{% trans "Disk space" %}: </span>
-                            <strong class="pull-right">{{vm.disk_size}} GB</strong>
-                        </p>
-                    </div>
-                    <div class="col-sm-12">
-                        <hr class="thin-hr">
-                    </div>
-                    {% if vm.vat > 0 or vm.discount.amount > 0 %}
+                    </p>
+                    <div class="row">
                         <div class="col-sm-6">
-                            <div class="subtotal-price">
-                                {% if vm.vat > 0 %}
-                                    <p>
-                                        <strong>{% trans "Subtotal" %} </strong>
-                                        <strong class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</strong>
-                                    </p>
-                                    <p>
-                                        <small>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) </small>
-                                        <strong class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</strong>
-                                    </p>
+                            {% if vm.created_at %}
+                                <p>
+                                    <span>{% trans "Period" %}: </span>
+                                    <span>
+                                        <span class="locale_date" data-format="YYYY/MM/DD">{{ vm.created_at|date:'Y-m-d h:i a' }}</span> - <span class="locale_date" data-format="YYYY/MM/DD">{{ subscription_end_date|date:'Y-m-d h:i a' }}</span>
+                                    </span>
+                                </p>
+                            {% endif %}
+                            <p>
+                                <span>{% trans "Cores" %}: </span>
+                                {% if vm.cores %}
+                                    <strong class="pull-right">{{vm.cores|floatformat}}</strong>
+                                {% else %}
+                                    <strong class="pull-right">{{vm.cpu|floatformat}}</strong>
                                 {% endif %}
-                                {% if vm.discount.amount > 0 %}
-                                    <p class="text-primary">
-                                        {%trans "Discount" as discount_name %}
-                                        <strong>{{ vm.discount.name|default:discount_name }} </strong>
-                                        <strong class="pull-right">- {{ vm.discount.amount }} CHF</strong>
-                                    </p>
-                                {% endif %}
-                            </div>
+                            </p>
+                            <p>
+                                <span>{% trans "Memory" %}: </span>
+                                <strong class="pull-right">{{vm.memory}} GB</strong>
+                            </p>
+                            <p>
+                                <span>{% trans "Disk space" %}: </span>
+                                <strong class="pull-right">{{vm.disk_size}} GB</strong>
+                            </p>
                         </div>
                         <div class="col-sm-12">
                             <hr class="thin-hr">
                         </div>
-                    {% endif %}
-                    <div class="col-sm-6">
-                        <p class="total-price">
-                            <strong>{% trans "Total" %} </strong>
-                            <strong class="pull-right">{% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} CHF</strong>
-                        </p>
+                        {% if vm.vat > 0 or vm.discount.amount > 0 %}
+                            <div class="col-sm-6">
+                                <div class="subtotal-price">
+                                    {% if vm.vat > 0 %}
+                                        <p>
+                                            <strong>{% trans "Subtotal" %} </strong>
+                                            <strong class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</strong>
+                                        </p>
+                                        <p>
+                                            <small>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) </small>
+                                            <strong class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</strong>
+                                        </p>
+                                    {% endif %}
+                                    {% if vm.discount.amount > 0 %}
+                                        <p class="text-primary">
+                                            {%trans "Discount" as discount_name %}
+                                            <strong>{{ vm.discount.name|default:discount_name }} </strong>
+                                            <strong class="pull-right">- {{ vm.discount.amount }} CHF</strong>
+                                        </p>
+                                    {% endif %}
+                                </div>
+                            </div>
+                            <div class="col-sm-12">
+                                <hr class="thin-hr">
+                            </div>
+                        {% endif %}
+                        <div class="col-sm-6">
+                            <p class="total-price">
+                                <strong>{% trans "Total" %} </strong>
+                                <strong class="pull-right">{% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} CHF</strong>
+                            </p>
+                        </div>
                     </div>
-                </div>
+                {% else %}
+                    <p>
+                        <strong>{% trans "Product" %}:</strong>&nbsp;
+                        {{ product_name }}
+                    </p>
+                    <div class="row">
+                        <div class="col-sm-6">
+                            <p>
+                                <span>{% trans "Amount" %}: </span>
+                                <strong class="pull-right">{{order.price|floatformat:2|intcomma}} CHF</strong>
+                            </p>
+                            {% if order.generic_payment_description %}
+                                <p>
+                                    <span>{% trans "Description" %}: </span>
+                                    <strong class="pull-right">{{order.generic_payment_description}}</strong>
+                                </p>
+                            {% endif %}
+                            {% if order.subscription_id %}
+                            <p>
+                                <span>{% trans "Recurring" %}: </span>
+                                <strong class="pull-right">{{order.created_at|date:'d'|ordinal}} {% trans "of every month" %}</strong>
+                            </p>
+                            {% endif %}
+                        </div>
+                    </div>
+                {% endif %}
             </div>
             <hr class="thin-hr">
         </div>
@@ -229,17 +256,6 @@
 <script type="text/javascript">
     {% trans "Some problem encountered. Please try again later." as err_msg %}
     var create_vm_error_message = '{{err_msg|safe}}';
-    window.onload = function () {
-        var locale_dates = document.getElementsByClassName("locale_date");
-        var formats = ['YYYY-MM-DD hh:mm a']
-        var i;
-        for (i = 0; i < locale_dates.length; i++) {
-            var oldDate = moment.utc(locale_dates[i].textContent, formats);
-            var outputFormat = locale_dates[i].getAttribute('data-format') || oldDate._f;
-            locale_dates[i].innerHTML = oldDate.local().format(outputFormat);
-            locale_dates[i].className += ' done';
-        }
-    };
 </script>
 {%endblock%}
 
diff --git a/hosting/templates/hosting/orders.html b/hosting/templates/hosting/orders.html
index 140cc4c6..96d9e9e3 100644
--- a/hosting/templates/hosting/orders.html
+++ b/hosting/templates/hosting/orders.html
@@ -28,7 +28,7 @@
             {% for order in orders %}
                 <tr>
                     <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 locale_date" data-header="{% trans 'Date' %}">{{ order.created_at | date:'Y-m-d h:i a' }}</td>
                     <td class="xs-td-smallhalf" data-header="{% trans 'Amount' %}">{{ order.price|floatformat:2|intcomma }}</td>
                     <td class="text-right last-td">
                         <a class="btn btn-order-detail" href="{% url 'hosting:orders' order.pk %}">{% trans 'See Invoice' %}</a>
diff --git a/hosting/templates/hosting/settings.html b/hosting/templates/hosting/settings.html
index 62dcc947..56818cbf 100644
--- a/hosting/templates/hosting/settings.html
+++ b/hosting/templates/hosting/settings.html
@@ -18,8 +18,8 @@
                     <h3>{%trans "Billing Address" %}</h3>
                     <hr>
                     <form role="form" id="billing-form" method="post" action="" novalidate>
+                        {% csrf_token %}
                         {% for field in form %}
-                            {% csrf_token %}
                             {% bootstrap_field field show_label=False type='fields' bound_css_class='' %}
                         {% endfor %}
                         <div class="form-group text-right">
diff --git a/hosting/templates/hosting/virtual_machine_detail.html b/hosting/templates/hosting/virtual_machine_detail.html
index 68894851..ce02036f 100644
--- a/hosting/templates/hosting/virtual_machine_detail.html
+++ b/hosting/templates/hosting/virtual_machine_detail.html
@@ -51,7 +51,7 @@
 			</div>
 			<div class="vm-detail-item">
 				<h2 class="vm-detail-title">{% trans "Status" %} <img src="{% static 'hosting/img/connected.svg' %}" class="un-icon"></h2>
-				<div class="vm-vmid">
+				<div class="vm-vmid vm-vmid-with-warning">
 					<div class="vm-item-subtitle">{% trans "Your VM is" %}</div>
 						<div id="terminate-VM" data-alt="{% trans 'Terminating' %}">
 							{% if virtual_machine.state == 'PENDING' %}
@@ -74,6 +74,10 @@
 							{% endif %}
 						</div>
 				</div>
+				<div class="vm-terminate-warning text-center">
+					<p>{% trans "Attention:" %}</p>
+					<p>{% trans "terminating VM can not be reverted." %}</p>
+				</div>
 			</div>
 		</div>
 		<div class="vm-contact-us">
@@ -105,7 +109,7 @@
 					<div class="modal-icon"><i class="fa fa-ban" aria-hidden="true"></i></div>
 					<h4 class="modal-title" id="ModalLabel">{% trans "Terminate your Virtual Machine" %}</h4>
 					<div class="modal-text">
-						<p>{% trans "Do you want to cancel your Virtual Machine" %} ?</p>
+						<p>{% trans "Terminated VMs can not be revived and will not be refunded. Do you want to terminate your VM?" %}</p>
 						<p><strong>{{virtual_machine.name}}</strong></p>
 					</div>
           <div class="modal-footer">
diff --git a/hosting/views.py b/hosting/views.py
index 6af1885b..32de4e54 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -32,6 +32,7 @@ from stored_messages.api import mark_read
 from stored_messages.models import Message
 from stored_messages.settings import stored_messages_settings
 
+from datacenterlight.cms_models import DCLCalculatorPluginModel
 from datacenterlight.models import VMTemplate, VMPricing
 from datacenterlight.utils import create_vm, get_cms_integration
 from hosting.models import UserCardDetail
@@ -59,7 +60,8 @@ from .forms import (
 )
 from .mixins import ProcessVMSelectionMixin, HostingContextMixin
 from .models import (
-    HostingOrder, HostingBill, HostingPlan, UserHostingKey, VMDetail
+    HostingOrder, HostingBill, HostingPlan, UserHostingKey, VMDetail,
+    GenericProduct
 )
 
 logger = logging.getLogger(__name__)
@@ -862,32 +864,20 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
                 raise Http404
 
         if obj is not None:
-            # invoice for previous order
-            try:
-                vm_detail = VMDetail.objects.get(vm_id=obj.vm_id)
-                context['vm'] = vm_detail.__dict__
-                context['vm']['name'] = '{}-{}'.format(
-                    context['vm']['configuration'], context['vm']['vm_id'])
-                price, vat, vat_percent, discount = 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']['discount'] = discount
-                context['vm']['vat_percent'] = vat_percent
-                context['vm']['total_price'] = price + vat - discount['amount']
-                context['subscription_end_date'] = vm_detail.end_date()
-            except VMDetail.DoesNotExist:
+            if obj.generic_product_id is not None:
+                # generic payment case
+                logger.debug("Generic payment case")
+                context['product_name'] = GenericProduct.objects.get(
+                    id=obj.generic_product_id
+                ).product_name
+            else:
+                # invoice for previous order
+                logger.debug("Invoice of VM order")
                 try:
-                    manager = OpenNebulaManager(
-                        email=owner.email, password=owner.password
-                    )
-                    vm = manager.get_vm(obj.vm_id)
-                    context['vm'] = VirtualMachineSerializer(vm).data
+                    vm_detail = VMDetail.objects.get(vm_id=obj.vm_id)
+                    context['vm'] = vm_detail.__dict__
+                    context['vm']['name'] = '{}-{}'.format(
+                        context['vm']['configuration'], context['vm']['vm_id'])
                     price, vat, vat_percent, discount = get_vm_price_with_vat(
                         cpu=context['vm']['cores'],
                         ssd_size=context['vm']['disk_size'],
@@ -899,23 +889,43 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
                     context['vm']['price'] = price
                     context['vm']['discount'] = discount
                     context['vm']['vat_percent'] = vat_percent
-                    context['vm']['total_price'] = (
-                            price + vat - discount['amount']
-                    )
-                except WrongIdError:
-                    messages.error(
-                        self.request,
-                        _('The VM you are looking for is unavailable at the '
-                          'moment. Please contact Data Center Light support.')
-                    )
-                    self.kwargs['error'] = 'WrongIdError'
-                    context['error'] = 'WrongIdError'
-                except ConnectionRefusedError:
-                    messages.error(
-                        self.request,
-                        _('In order to create a VM, you need to create/upload '
-                          'your SSH KEY first.')
-                    )
+                    context['vm']['total_price'] = price + vat - discount['amount']
+                    context['subscription_end_date'] = vm_detail.end_date()
+                except VMDetail.DoesNotExist:
+                    try:
+                        manager = OpenNebulaManager(
+                            email=owner.email, password=owner.password
+                        )
+                        vm = manager.get_vm(obj.vm_id)
+                        context['vm'] = VirtualMachineSerializer(vm).data
+                        price, vat, vat_percent, discount = 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']['discount'] = discount
+                        context['vm']['vat_percent'] = vat_percent
+                        context['vm']['total_price'] = (
+                                price + vat - discount['amount']
+                        )
+                    except WrongIdError:
+                        messages.error(
+                            self.request,
+                            _('The VM you are looking for is unavailable at the '
+                              'moment. Please contact Data Center Light support.')
+                        )
+                        self.kwargs['error'] = 'WrongIdError'
+                        context['error'] = 'WrongIdError'
+                    except ConnectionRefusedError:
+                        messages.error(
+                            self.request,
+                            _('In order to create a VM, you need to create/upload '
+                              'your SSH KEY first.')
+                        )
         else:
             # new order, confirm payment
             if 'token' in self.request.session:
@@ -1032,14 +1042,20 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
         memory = specs.get('memory')
         disk_size = specs.get('disk_size')
         amount_to_be_charged = specs.get('total_price')
-        plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
-                                                     memory=memory,
-                                                     disk_size=disk_size)
-        stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu,
-                                                        ram=memory,
-                                                        ssd=disk_size,
-                                                        version=1,
-                                                        app='dcl')
+        plan_name = StripeUtils.get_stripe_plan_name(
+            cpu=cpu,
+            memory=memory,
+            disk_size=disk_size,
+            price=amount_to_be_charged
+        )
+        stripe_plan_id = StripeUtils.get_stripe_plan_id(
+            cpu=cpu,
+            ram=memory,
+            ssd=disk_size,
+            version=1,
+            app='dcl',
+            price=amount_to_be_charged
+        )
         stripe_plan = stripe_utils.get_or_create_stripe_plan(
             amount=amount_to_be_charged,
             name=plan_name,
@@ -1183,7 +1199,29 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
             raise ValidationError(_('Invalid number of cores'))
 
     def validate_memory(self, value):
-        if (value > 200) or (value < 1):
+        if 'pid' in self.request.POST:
+            try:
+                plugin = DCLCalculatorPluginModel.objects.get(
+                             id=self.request.POST['pid']
+                         )
+            except DCLCalculatorPluginModel.DoesNotExist as dne:
+                logger.error(
+                    str(dne) + " plugin_id: " + self.request.POST['pid']
+                )
+                raise ValidationError(_('Invalid calculator properties'))
+            if plugin.enable_512mb_ram:
+                if value % 1 == 0 or value == 0.5:
+                    logger.debug(
+                        "Given ram {value} is either 0.5 or a"
+                        " whole number".format(value=value)
+                    )
+                    if (value > 200) or (value < 0.5):
+                        raise ValidationError(_('Invalid RAM size'))
+                else:
+                    raise ValidationError(_('Invalid RAM size'))
+            elif (value > 200) or (value < 1) or (value % 1 != 0):
+                raise ValidationError(_('Invalid RAM size'))
+        else:
             raise ValidationError(_('Invalid RAM size'))
 
     def validate_storage(self, value):
@@ -1203,7 +1241,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
         cores = request.POST.get('cpu')
         cores_field = forms.IntegerField(validators=[self.validate_cores])
         memory = request.POST.get('ram')
-        memory_field = forms.IntegerField(validators=[self.validate_memory])
+        memory_field = forms.FloatField(validators=[self.validate_memory])
         storage = request.POST.get('storage')
         storage_field = forms.IntegerField(validators=[self.validate_storage])
         template_id = int(request.POST.get('config'))
@@ -1267,7 +1305,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
             'price': price,
             'vat': vat,
             'vat_percent': vat_percent,
-            'total_price': price + vat - discount['amount'],
+            'total_price': round(price + vat - discount['amount'], 2),
             'pricing_name': vm_pricing_name
         }
 
@@ -1394,7 +1432,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
         terminated = manager.delete_vm(vm.id)
 
         if not terminated:
-            logger.debug(
+            logger.error(
                 "manager.delete_vm returned False. Hence, error making "
                 "xml-rpc call to delete vm failed."
             )
@@ -1404,6 +1442,9 @@ class VirtualMachineView(LoginRequiredMixin, View):
                 try:
                     manager.get_vm(vm.id)
                 except WrongIdError:
+                    logger.error(
+                        "VM {} not found. So, its terminated.".format(vm.id)
+                    )
                     response['status'] = True
                     response['text'] = ugettext('Terminated')
                     vm_detail_obj = VMDetail.objects.filter(
@@ -1421,6 +1462,10 @@ class VirtualMachineView(LoginRequiredMixin, View):
                     break
                 else:
                     sleep(2)
+            if not response['status']:
+                response['text'] = _("VM terminate action timed out. Please "
+                                     "contact support@datacenterlight.ch for "
+                                     "further information.")
             context = {
                 'vm_name': vm_name,
                 'base_url': "{0}://{1}".format(
@@ -1441,11 +1486,13 @@ class VirtualMachineView(LoginRequiredMixin, View):
             email = BaseEmail(**email_data)
             email.send()
         admin_email_body.update(response)
+        admin_msg_sub = "VM and Subscription for VM {} and user: {}".format(
+            vm.id,
+            owner.email
+        )
         email_to_admin_data = {
-            'subject': "Deleted VM and Subscription for VM {vm_id} and "
-                       "user: {user}".format(
-                           vm_id=vm.id, user=owner.email
-                       ),
+            'subject': ("Deleted " if response['status']
+                        else "ERROR deleting ") + admin_msg_sub,
             'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
             'to': ['info@ungleich.ch'],
             'body': "\n".join(
diff --git a/opennebula_api/models.py b/opennebula_api/models.py
index 3682c5da..adc39bf0 100644
--- a/opennebula_api/models.py
+++ b/opennebula_api/models.py
@@ -110,7 +110,7 @@ class OpenNebulaManager():
                 raise UserExistsError()
             except OpenNebulaException as err:
                 logger.error('OpenNebulaException error: {0}'.format(err))
-                logger.debug('User exists but password is wrong')
+                logger.error('User exists but password is wrong')
                 raise UserCredentialError()
 
         except WrongNameError:
@@ -148,7 +148,7 @@ class OpenNebulaManager():
             )
             return opennebula_user
         except ConnectionRefusedError:
-            logger.info(
+            logger.error(
                 'Could not connect to host: {host} via protocol {protocol}'.format(
                     host=settings.OPENNEBULA_DOMAIN,
                     protocol=settings.OPENNEBULA_PROTOCOL)
@@ -160,7 +160,7 @@ class OpenNebulaManager():
             user_pool = oca.UserPool(self.oneadmin_client)
             user_pool.info()
         except ConnectionRefusedError:
-            logger.info(
+            logger.error(
                 'Could not connect to host: {host} via protocol {protocol}'.format(
                     host=settings.OPENNEBULA_DOMAIN,
                     protocol=settings.OPENNEBULA_PROTOCOL)
@@ -174,7 +174,7 @@ class OpenNebulaManager():
             vm_pool.info()
             return vm_pool
         except AttributeError:
-            logger.info('Could not connect via client, using oneadmin instead')
+            logger.error('Could not connect via client, using oneadmin instead')
             try:
                 vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
                 vm_pool.info(filter=-2)
@@ -183,7 +183,7 @@ class OpenNebulaManager():
                 raise ConnectionRefusedError
 
         except ConnectionRefusedError:
-            logger.info(
+            logger.error(
                 'Could not connect to host: {host} via protocol {protocol}'.format(
                     host=settings.OPENNEBULA_DOMAIN,
                     protocol=settings.OPENNEBULA_PROTOCOL)
@@ -249,8 +249,8 @@ class OpenNebulaManager():
             vm_specs = vm_specs_formatter.format(
                 vcpu=int(specs['cpu']),
                 cpu=0.1 * int(specs['cpu']),
-                memory=1024 * int(specs['memory']),
-
+                memory=(512 if specs['memory'] == 0.5 else
+                        1024 * int(specs['memory'])),
             )
             vm_specs += """<DISK>
                                   <TYPE>fs</TYPE>
@@ -269,8 +269,8 @@ class OpenNebulaManager():
             vm_specs = vm_specs_formatter.format(
                 vcpu=int(specs['cpu']),
                 cpu=0.1 * int(specs['cpu']),
-                memory=1024 * int(specs['memory']),
-
+                memory=(512 if specs['memory'] == 0.5 else
+                        1024 * int(specs['memory'])),
             )
             vm_specs += """<DISK>
                                   <TYPE>fs</TYPE>
@@ -325,14 +325,14 @@ class OpenNebulaManager():
             )
             vm_terminated = True
         except socket.timeout as socket_err:
-            logger.info("Socket timeout error: {0}".format(socket_err))
+            logger.error("Socket timeout error: {0}".format(socket_err))
         except OpenNebulaException as opennebula_err:
-            logger.info(
+            logger.error(
                 "OpenNebulaException error: {0}".format(opennebula_err))
         except OSError as os_err:
-            logger.info("OSError : {0}".format(os_err))
+            logger.error("OSError : {0}".format(os_err))
         except ValueError as value_err:
-            logger.info("ValueError : {0}".format(value_err))
+            logger.error("ValueError : {0}".format(value_err))
 
         return vm_terminated
 
@@ -342,7 +342,7 @@ class OpenNebulaManager():
             template_pool.info()
             return template_pool
         except ConnectionRefusedError:
-            logger.info(
+            logger.error(
                 """Could not connect to host: {host} via protocol
                  {protocol}""".format(
                     host=settings.OPENNEBULA_DOMAIN,
diff --git a/requirements.txt b/requirements.txt
index 85a41841..a14617a9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -34,7 +34,6 @@ django-meta==1.2
 django-meta-mixin==0.3.0
 django-model-utils==2.5
 django-mptt==0.8.4
-django-multisite==1.4.1
 django-parler==1.6.3
 django-phonenumber-field==1.1.0
 django-polymorphic==0.9.2
@@ -69,7 +68,7 @@ model-mommy==1.2.6
 phonenumbers==7.4.0
 phonenumberslite==7.4.0
 psycopg2==2.7.3.2
-pycryptodome==3.4
+pycryptodome==3.6.6
 pylibmc==1.5.1
 python-dateutil==2.5.3
 python-slugify==1.2.0
diff --git a/ungleich/templates/cms/ungleichch/_footer.html b/ungleich/templates/cms/ungleichch/_footer.html
index 94832ed4..21c96b54 100644
--- a/ungleich/templates/cms/ungleichch/_footer.html
+++ b/ungleich/templates/cms/ungleichch/_footer.html
@@ -31,7 +31,7 @@
 	    </a>
 	  </li>
 	  <li>
-	    <a href="{% url 'djangocms_blog:posts-latest-feed' %}">
+	    <a href="https://blog.ungleich.ch/en-us/cms/blog/feed/">
 	      <span class="fa-stack fa-lg">
 		<i class="fa fa-circle fa-stack-2x"></i>
 		<i class="fa fa-rss fa-stack-1x fa-inverse"></i>
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index 1859a82c..ec97a320 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -1,6 +1,7 @@
 import decimal
 import logging
 import subprocess
+
 from oca.pool import WrongIdError
 
 from datacenterlight.models import VMPricing
@@ -80,7 +81,7 @@ def get_vm_price(cpu, memory, disk_size, hdd_size=0, pricing_name='default'):
              (decimal.Decimal(hdd_size) * pricing.hdd_unit_price))
     cents = decimal.Decimal('.01')
     price = price.quantize(cents, decimal.ROUND_HALF_UP)
-    return float(price)
+    return round(float(price), 2)
 
 
 def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
@@ -126,9 +127,10 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
     vat = vat.quantize(cents, decimal.ROUND_HALF_UP)
     discount = {
         'name': pricing.discount_name,
-        'amount': float(pricing.discount_amount),
+        'amount': round(float(pricing.discount_amount), 2)
     }
-    return float(price), float(vat), float(vat_percent), discount
+    return (round(float(price), 2), round(float(vat), 2),
+            round(float(vat_percent), 2), discount)
 
 
 def ping_ok(host_ipv6):
diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py
index 2045df8e..a3224a0e 100644
--- a/utils/stripe_utils.py
+++ b/utils/stripe_utils.py
@@ -291,7 +291,8 @@ class StripeUtils(object):
         return charge
 
     @staticmethod
-    def get_stripe_plan_id(cpu, ram, ssd, version, app='dcl', hdd=None):
+    def get_stripe_plan_id(cpu, ram, ssd, version, app='dcl', hdd=None,
+                           price=None):
         """
         Returns the Stripe plan id string of the form
         `dcl-v1-cpu-2-ram-5gb-ssd-10gb` based on the input parameters
@@ -303,6 +304,7 @@ class StripeUtils(object):
         :param version: The version of the Stripe plans
         :param app: The application to which the stripe plan belongs
         to. By default it is 'dcl'
+        :param price: The price for this plan
         :return: A string of the form `dcl-v1-cpu-2-ram-5gb-ssd-10gb`
         """
         dcl_plan_string = 'cpu-{cpu}-ram-{ram}gb-ssd-{ssd}gb'.format(cpu=cpu,
@@ -314,19 +316,30 @@ class StripeUtils(object):
         stripe_plan_id_string = '{app}-v{version}-{plan}'.format(
             app=app,
             version=version,
-            plan=dcl_plan_string)
-        return stripe_plan_id_string
+            plan=dcl_plan_string
+        )
+        if price is not None:
+            stripe_plan_id_string_with_price = '{}-{}chf'.format(
+                stripe_plan_id_string,
+                round(price, 2)
+            )
+            return stripe_plan_id_string_with_price
+        else:
+            return stripe_plan_id_string
 
     @staticmethod
-    def get_stripe_plan_name(cpu, memory, disk_size):
+    def get_stripe_plan_name(cpu, memory, disk_size, price):
         """
         Returns the Stripe plan name
         :return:
         """
-        return "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format(
-            cpu=cpu,
-            memory=memory,
-            disk_size=disk_size)
+        return "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD, " \
+               "{price} CHF".format(
+                    cpu=cpu,
+                    memory=memory,
+                    disk_size=disk_size,
+                    price=round(price, 2)
+                )
 
     @handleStripeError
     def set_subscription_meta_data(self, subscription_id, meta_data):