diff --git a/Changelog b/Changelog
index 5700852e..a4840758 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,10 @@
+2.10.5: 2020-03-17
+ * Introduce base price for VMs and let admins add stripe_coupon_id (MR!730)
+ Notes for deployment:
+ 1. Add env variable `VM_BASE_PRICE`
+ 2. Migrate datacenterlight app. This introduces the stripe_coupon_code field in the VMPricing.
+ 3. Create a coupon in stripe with the desired value and note down the stripe's coupon id
+ 4. Update the discount amount and set the corresponding coupon id in the admin
2.10.3b: 2020-03-05
* #7773: Use username for communicating with opennebula all the time
2.10.2b: 2020-02-25
diff --git a/datacenterlight/cms_plugins.py b/datacenterlight/cms_plugins.py
index c3ec974f..52b4f19f 100644
--- a/datacenterlight/cms_plugins.py
+++ b/datacenterlight/cms_plugins.py
@@ -1,5 +1,6 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
+from django.conf import settings
from .cms_models import (
DCLBannerItemPluginModel, DCLBannerListPluginModel, DCLContactPluginModel,
@@ -100,6 +101,7 @@ class DCLCalculatorPlugin(CMSPluginBase):
vm_type=instance.vm_type
).order_by('name')
context['instance'] = instance
+ context['vm_base_price'] = settings.VM_BASE_PRICE
context['min_ram'] = 0.5 if instance.enable_512mb_ram else 1
return context
diff --git a/datacenterlight/migrations/0031_vmpricing_stripe_coupon_id.py b/datacenterlight/migrations/0031_vmpricing_stripe_coupon_id.py
new file mode 100644
index 00000000..d2e45871
--- /dev/null
+++ b/datacenterlight/migrations/0031_vmpricing_stripe_coupon_id.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.4 on 2020-02-04 03:16
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('datacenterlight', '0030_dclnavbarpluginmodel_show_non_transparent_navbar_always'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='vmpricing',
+ name='stripe_coupon_id',
+ field=models.CharField(blank=True, max_length=255, null=True),
+ ),
+ ]
diff --git a/datacenterlight/models.py b/datacenterlight/models.py
index 6410254b..64d785a2 100644
--- a/datacenterlight/models.py
+++ b/datacenterlight/models.py
@@ -54,6 +54,7 @@ class VMPricing(models.Model):
discount_amount = models.DecimalField(
max_digits=6, decimal_places=2, default=0
)
+ stripe_coupon_id = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
display_str = self.name + ' => ' + ' - '.join([
diff --git a/datacenterlight/static/datacenterlight/js/main.js b/datacenterlight/static/datacenterlight/js/main.js
index 8fea438a..c6869cda 100644
--- a/datacenterlight/static/datacenterlight/js/main.js
+++ b/datacenterlight/static/datacenterlight/js/main.js
@@ -225,8 +225,8 @@
}
var total = (cardPricing['cpu'].value * window.coresUnitPrice) +
(cardPricing['ram'].value * window.ramUnitPrice) +
- (cardPricing['storage'].value * window.ssdUnitPrice) -
- window.discountAmount;
+ (cardPricing['storage'].value * window.ssdUnitPrice) +
+ window.vmBasePrice - window.discountAmount;
total = parseFloat(total.toFixed(2));
$("#total").text(total);
}
diff --git a/datacenterlight/templates/datacenterlight/cms/calculator.html b/datacenterlight/templates/datacenterlight/cms/calculator.html
index 7b123a72..20a6664a 100644
--- a/datacenterlight/templates/datacenterlight/cms/calculator.html
+++ b/datacenterlight/templates/datacenterlight/cms/calculator.html
@@ -1,5 +1,5 @@
- {% include "datacenterlight/includes/_calculator_form.html" with vm_pricing=instance.pricing %}
+ {% include "datacenterlight/includes/_calculator_form.html" with vm_pricing=instance.pricing vm_base_price=vm_base_price %}
\ No newline at end of file
diff --git a/datacenterlight/templates/datacenterlight/includes/_calculator_form.html b/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
index f64a9500..2c2b51dd 100644
--- a/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
+++ b/datacenterlight/templates/datacenterlight/includes/_calculator_form.html
@@ -9,6 +9,7 @@
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.vmBasePrice = {{vm_base_price|default:0}};
window.minRam = {{min_ram}};
window.minRamErr = '{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}';
diff --git a/datacenterlight/views.py b/datacenterlight/views.py
index aefaf6a8..2a55b96f 100644
--- a/datacenterlight/views.py
+++ b/datacenterlight/views.py
@@ -678,9 +678,9 @@ class OrderConfirmationView(DetailView, FormView):
vm_specs["vat_percent"] = vat_percent
vm_specs["vat_validation_status"] = request.session["vat_validation_status"] if "vat_validation_status" in request.session else ""
vm_specs["vat_country"] = user_vat_country
- vm_specs["price_with_vat"] = round_up(price * (1 + vm_specs["vat_percent"] * 0.01), 2)
- vm_specs["price_after_discount"] = round_up(price - discount['amount'], 2)
- vm_specs["price_after_discount_with_vat"] = round_up((price - discount['amount']) * (1 + vm_specs["vat_percent"] * 0.01), 2)
+ vm_specs["price_with_vat"] = round(price * (1 + vm_specs["vat_percent"] * 0.01), 2)
+ vm_specs["price_after_discount"] = round(price - discount['amount'], 2)
+ vm_specs["price_after_discount_with_vat"] = round((price - discount['amount']) * (1 + vm_specs["vat_percent"] * 0.01), 2)
discount["amount_with_vat"] = round(vm_specs["price_with_vat"] - vm_specs["price_after_discount_with_vat"], 2)
vm_specs["total_price"] = vm_specs["price_after_discount_with_vat"]
vm_specs["discount"] = discount
@@ -933,11 +933,11 @@ class OrderConfirmationView(DetailView, FormView):
subscription_result = stripe_utils.subscribe_customer_to_plan(
stripe_api_cus_id,
[{"plan": stripe_plan.get('response_object').stripe_plan_id}],
- coupon='ipv6-discount-8chf' if (
- 'name' in discount and
- discount['name'] is not None and
- 'ipv6' in discount['name'].lower()
- ) else "",
+ coupon=(discount['stripe_coupon_id']
+ if 'name' in discount and
+ 'ipv6' in discount['name'].lower() and
+ discount['stripe_coupon_id']
+ else ""),
tax_rates=[stripe_tax_rate.tax_rate_id] if stripe_tax_rate else [],
)
stripe_subscription_obj = subscription_result.get('response_object')
diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py
index c959c237..743d11c3 100644
--- a/dynamicweb/settings/base.py
+++ b/dynamicweb/settings/base.py
@@ -761,6 +761,7 @@ OTP_VERIFY_ENDPOINT = env('OTP_VERIFY_ENDPOINT')
FIRST_VM_ID_AFTER_EU_VAT = int_env('FIRST_VM_ID_AFTER_EU_VAT')
PRE_EU_VAT_RATE = float(env('PRE_EU_VAT_RATE'))
+VM_BASE_PRICE = float(env('VM_BASE_PRICE'))
if DEBUG:
from .local import * # flake8: noqa
diff --git a/hosting/static/hosting/js/initial.js b/hosting/static/hosting/js/initial.js
index 6b6d744d..36cf6d07 100644
--- a/hosting/static/hosting/js/initial.js
+++ b/hosting/static/hosting/js/initial.js
@@ -266,8 +266,8 @@ $( document ).ready(function() {
}
var total = (cardPricing['cpu'].value * window.coresUnitPrice) +
(cardPricing['ram'].value * window.ramUnitPrice) +
- (cardPricing['storage'].value * window.ssdUnitPrice) -
- window.discountAmount;
+ (cardPricing['storage'].value * window.ssdUnitPrice) +
+ window.vmBasePrice - window.discountAmount;
total = parseFloat(total.toFixed(2));
$("#total").text(total);
}
diff --git a/hosting/views.py b/hosting/views.py
index 8dd01906..969523b3 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -1185,7 +1185,11 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView):
subscription_result = stripe_utils.subscribe_customer_to_plan(
stripe_api_cus_id,
[{"plan": stripe_plan.get('response_object').stripe_plan_id}],
- coupon='ipv6-discount-8chf' if 'name' in discount and 'ipv6' in discount['name'].lower() else "",
+ coupon=(discount['stripe_coupon_id']
+ if 'name' in discount and
+ 'ipv6' in discount['name'].lower() and
+ discount['stripe_coupon_id']
+ else ""),
tax_rates=[stripe_tax_rate.tax_rate_id] if stripe_tax_rate else [],
)
stripe_subscription_obj = subscription_result.get('response_object')
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index 7bff9a89..b9e2eb8a 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -3,6 +3,8 @@ import logging
import math
import subprocess
+from django.conf import settings
+
from oca.pool import WrongIdError
from datacenterlight.models import VMPricing
@@ -79,7 +81,8 @@ def get_vm_price(cpu, memory, disk_size, hdd_size=0, pricing_name='default'):
price = ((decimal.Decimal(cpu) * pricing.cores_unit_price) +
(decimal.Decimal(memory) * pricing.ram_unit_price) +
(decimal.Decimal(disk_size) * pricing.ssd_unit_price) +
- (decimal.Decimal(hdd_size) * pricing.hdd_unit_price))
+ (decimal.Decimal(hdd_size) * pricing.hdd_unit_price) +
+ decimal.Decimal(settings.VM_BASE_PRICE))
cents = decimal.Decimal('.01')
price = price.quantize(cents, decimal.ROUND_HALF_UP)
return round(float(price), 2)
@@ -102,7 +105,8 @@ def get_vm_price_for_given_vat(cpu, memory, ssd_size, hdd_size=0,
(decimal.Decimal(cpu) * pricing.cores_unit_price) +
(decimal.Decimal(memory) * pricing.ram_unit_price) +
(decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
- (decimal.Decimal(hdd_size) * pricing.hdd_unit_price)
+ (decimal.Decimal(hdd_size) * pricing.hdd_unit_price) +
+ decimal.Decimal(settings.VM_BASE_PRICE)
)
discount_name = pricing.discount_name
@@ -118,7 +122,8 @@ def get_vm_price_for_given_vat(cpu, memory, ssd_size, hdd_size=0,
discount = {
'name': discount_name,
'amount': discount_amount,
- 'amount_with_vat': round(float(discount_amount_with_vat), 2)
+ 'amount_with_vat': round(float(discount_amount_with_vat), 2),
+ 'stripe_coupon_id': pricing.stripe_coupon_id
}
return (round(float(price), 2), round(float(vat), 2),
round(float(vat_percent), 2), discount)
@@ -154,7 +159,8 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
(decimal.Decimal(cpu) * pricing.cores_unit_price) +
(decimal.Decimal(memory) * pricing.ram_unit_price) +
(decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
- (decimal.Decimal(hdd_size) * pricing.hdd_unit_price)
+ (decimal.Decimal(hdd_size) * pricing.hdd_unit_price) +
+ decimal.Decimal(settings.VM_BASE_PRICE)
)
if pricing.vat_inclusive:
vat = decimal.Decimal(0)
@@ -168,7 +174,8 @@ 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': round(float(pricing.discount_amount), 2)
+ 'amount': round(float(pricing.discount_amount), 2),
+ 'stripe_coupon_id': pricing.stripe_coupon_id
}
return (round(float(price), 2), round(float(vat), 2),
round(float(vat_percent), 2), discount)
@@ -215,11 +222,6 @@ def get_ip_addresses(vm_id):
return "--"
-def round_up(n, decimals=0):
- multiplier = 10 ** decimals
- return math.ceil(n * multiplier) / multiplier
-
-
class HostingUtils:
@staticmethod
def clear_items_from_list(from_list, items_list):