Merge tag '2.10.2' into branch-2.10.3b
Introduce base price for VMs and let admins add stripe_coupon_id
This commit is contained in:
		
				commit
				
					
						580960548e
					
				
			
		
					 12 changed files with 62 additions and 24 deletions
				
			
		|  | @ -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 | 2.10.3b: 2020-03-05 | ||||||
|    * #7773: Use username for communicating with opennebula all the time |    * #7773: Use username for communicating with opennebula all the time | ||||||
| 2.10.2b: 2020-02-25 | 2.10.2b: 2020-02-25 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| from cms.plugin_base import CMSPluginBase | from cms.plugin_base import CMSPluginBase | ||||||
| from cms.plugin_pool import plugin_pool | from cms.plugin_pool import plugin_pool | ||||||
|  | from django.conf import settings | ||||||
| 
 | 
 | ||||||
| from .cms_models import ( | from .cms_models import ( | ||||||
|     DCLBannerItemPluginModel, DCLBannerListPluginModel, DCLContactPluginModel, |     DCLBannerItemPluginModel, DCLBannerListPluginModel, DCLContactPluginModel, | ||||||
|  | @ -100,6 +101,7 @@ class DCLCalculatorPlugin(CMSPluginBase): | ||||||
|                 vm_type=instance.vm_type |                 vm_type=instance.vm_type | ||||||
|             ).order_by('name') |             ).order_by('name') | ||||||
|         context['instance'] = instance |         context['instance'] = instance | ||||||
|  |         context['vm_base_price'] = settings.VM_BASE_PRICE | ||||||
|         context['min_ram'] = 0.5 if instance.enable_512mb_ram else 1 |         context['min_ram'] = 0.5 if instance.enable_512mb_ram else 1 | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -54,6 +54,7 @@ class VMPricing(models.Model): | ||||||
|     discount_amount = models.DecimalField( |     discount_amount = models.DecimalField( | ||||||
|         max_digits=6, decimal_places=2, default=0 |         max_digits=6, decimal_places=2, default=0 | ||||||
|     ) |     ) | ||||||
|  |     stripe_coupon_id = models.CharField(max_length=255, null=True, blank=True) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         display_str = self.name + ' => ' + ' - '.join([ |         display_str = self.name + ' => ' + ' - '.join([ | ||||||
|  |  | ||||||
|  | @ -225,8 +225,8 @@ | ||||||
|         } |         } | ||||||
|         var total = (cardPricing['cpu'].value * window.coresUnitPrice) + |         var total = (cardPricing['cpu'].value * window.coresUnitPrice) + | ||||||
|                     (cardPricing['ram'].value * window.ramUnitPrice) + |                     (cardPricing['ram'].value * window.ramUnitPrice) + | ||||||
|                     (cardPricing['storage'].value * window.ssdUnitPrice) - |                     (cardPricing['storage'].value * window.ssdUnitPrice) + | ||||||
|                     window.discountAmount; |                     window.vmBasePrice - window.discountAmount; | ||||||
|         total = parseFloat(total.toFixed(2)); |         total = parseFloat(total.toFixed(2)); | ||||||
|         $("#total").text(total); |         $("#total").text(total); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| <div class="price-calc-section"> | <div class="price-calc-section"> | ||||||
|   <div class="card"> |   <div class="card"> | ||||||
|     {% 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 %} | ||||||
|   </div> |   </div> | ||||||
| </div> | </div> | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
|         window.ssdUnitPrice = {{vm_pricing.ssd_unit_price|default:0}}; |         window.ssdUnitPrice = {{vm_pricing.ssd_unit_price|default:0}}; | ||||||
|         window.hddUnitPrice = {{vm_pricing.hdd_unit_price|default:0}}; |         window.hddUnitPrice = {{vm_pricing.hdd_unit_price|default:0}}; | ||||||
|         window.discountAmount = {{vm_pricing.discount_amount|default:0}}; |         window.discountAmount = {{vm_pricing.discount_amount|default:0}}; | ||||||
|  |         window.vmBasePrice = {{vm_base_price|default:0}}; | ||||||
|         window.minRam = {{min_ram}}; |         window.minRam = {{min_ram}}; | ||||||
|         window.minRamErr = '{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}'; |         window.minRamErr = '{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}'; | ||||||
|     </script> |     </script> | ||||||
|  |  | ||||||
|  | @ -678,9 +678,9 @@ class OrderConfirmationView(DetailView, FormView): | ||||||
|                 vm_specs["vat_percent"] = vat_percent |                 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_validation_status"] = request.session["vat_validation_status"] if "vat_validation_status" in request.session else "" | ||||||
|             vm_specs["vat_country"] = user_vat_country |             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_with_vat"] = round(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"] = round(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_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) |             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["total_price"] = vm_specs["price_after_discount_with_vat"] | ||||||
|             vm_specs["discount"] = discount |             vm_specs["discount"] = discount | ||||||
|  | @ -933,11 +933,11 @@ class OrderConfirmationView(DetailView, FormView): | ||||||
|             subscription_result = stripe_utils.subscribe_customer_to_plan( |             subscription_result = stripe_utils.subscribe_customer_to_plan( | ||||||
|                 stripe_api_cus_id, |                 stripe_api_cus_id, | ||||||
|                 [{"plan": stripe_plan.get('response_object').stripe_plan_id}], |                 [{"plan": stripe_plan.get('response_object').stripe_plan_id}], | ||||||
|                 coupon='ipv6-discount-8chf' if ( |                 coupon=(discount['stripe_coupon_id'] | ||||||
|                     'name' in discount and |                     if 'name' in discount and | ||||||
|                     discount['name'] is not None and |                        'ipv6' in discount['name'].lower() and | ||||||
|                     'ipv6' in discount['name'].lower() |                        discount['stripe_coupon_id'] | ||||||
|                 ) else "", |                     else ""), | ||||||
|                 tax_rates=[stripe_tax_rate.tax_rate_id] if stripe_tax_rate else [], |                 tax_rates=[stripe_tax_rate.tax_rate_id] if stripe_tax_rate else [], | ||||||
|             ) |             ) | ||||||
|             stripe_subscription_obj = subscription_result.get('response_object') |             stripe_subscription_obj = subscription_result.get('response_object') | ||||||
|  |  | ||||||
|  | @ -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') | FIRST_VM_ID_AFTER_EU_VAT = int_env('FIRST_VM_ID_AFTER_EU_VAT') | ||||||
| PRE_EU_VAT_RATE = float(env('PRE_EU_VAT_RATE')) | PRE_EU_VAT_RATE = float(env('PRE_EU_VAT_RATE')) | ||||||
| 
 | 
 | ||||||
|  | VM_BASE_PRICE = float(env('VM_BASE_PRICE')) | ||||||
| 
 | 
 | ||||||
| if DEBUG: | if DEBUG: | ||||||
|     from .local import *  # flake8: noqa |     from .local import *  # flake8: noqa | ||||||
|  |  | ||||||
|  | @ -266,8 +266,8 @@ $( document ).ready(function() { | ||||||
|         } |         } | ||||||
|         var total = (cardPricing['cpu'].value * window.coresUnitPrice) + |         var total = (cardPricing['cpu'].value * window.coresUnitPrice) + | ||||||
|                     (cardPricing['ram'].value * window.ramUnitPrice) + |                     (cardPricing['ram'].value * window.ramUnitPrice) + | ||||||
|                     (cardPricing['storage'].value * window.ssdUnitPrice) - |                     (cardPricing['storage'].value * window.ssdUnitPrice) + | ||||||
|                     window.discountAmount; |                     window.vmBasePrice - window.discountAmount; | ||||||
|         total = parseFloat(total.toFixed(2)); |         total = parseFloat(total.toFixed(2)); | ||||||
|         $("#total").text(total); |         $("#total").text(total); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1185,7 +1185,11 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView): | ||||||
|         subscription_result = stripe_utils.subscribe_customer_to_plan( |         subscription_result = stripe_utils.subscribe_customer_to_plan( | ||||||
|             stripe_api_cus_id, |             stripe_api_cus_id, | ||||||
|             [{"plan": stripe_plan.get('response_object').stripe_plan_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 [], |             tax_rates=[stripe_tax_rate.tax_rate_id] if stripe_tax_rate else [], | ||||||
|         ) |         ) | ||||||
|         stripe_subscription_obj = subscription_result.get('response_object') |         stripe_subscription_obj = subscription_result.get('response_object') | ||||||
|  |  | ||||||
|  | @ -3,6 +3,8 @@ import logging | ||||||
| import math | import math | ||||||
| import subprocess | import subprocess | ||||||
| 
 | 
 | ||||||
|  | from django.conf import settings | ||||||
|  | 
 | ||||||
| from oca.pool import WrongIdError | from oca.pool import WrongIdError | ||||||
| 
 | 
 | ||||||
| from datacenterlight.models import VMPricing | 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) + |     price = ((decimal.Decimal(cpu) * pricing.cores_unit_price) + | ||||||
|              (decimal.Decimal(memory) * pricing.ram_unit_price) + |              (decimal.Decimal(memory) * pricing.ram_unit_price) + | ||||||
|              (decimal.Decimal(disk_size) * pricing.ssd_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') |     cents = decimal.Decimal('.01') | ||||||
|     price = price.quantize(cents, decimal.ROUND_HALF_UP) |     price = price.quantize(cents, decimal.ROUND_HALF_UP) | ||||||
|     return round(float(price), 2) |     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(cpu) * pricing.cores_unit_price) + | ||||||
|         (decimal.Decimal(memory) * pricing.ram_unit_price) + |         (decimal.Decimal(memory) * pricing.ram_unit_price) + | ||||||
|         (decimal.Decimal(ssd_size) * pricing.ssd_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 |     discount_name = pricing.discount_name | ||||||
|  | @ -118,7 +122,8 @@ def get_vm_price_for_given_vat(cpu, memory, ssd_size, hdd_size=0, | ||||||
|     discount = { |     discount = { | ||||||
|         'name': discount_name, |         'name': discount_name, | ||||||
|         'amount': discount_amount, |         '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), |     return (round(float(price), 2), round(float(vat), 2), | ||||||
|             round(float(vat_percent), 2), discount) |             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(cpu) * pricing.cores_unit_price) + | ||||||
|         (decimal.Decimal(memory) * pricing.ram_unit_price) + |         (decimal.Decimal(memory) * pricing.ram_unit_price) + | ||||||
|         (decimal.Decimal(ssd_size) * pricing.ssd_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: |     if pricing.vat_inclusive: | ||||||
|         vat = decimal.Decimal(0) |         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) |     vat = vat.quantize(cents, decimal.ROUND_HALF_UP) | ||||||
|     discount = { |     discount = { | ||||||
|         'name': pricing.discount_name, |         '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), |     return (round(float(price), 2), round(float(vat), 2), | ||||||
|             round(float(vat_percent), 2), discount) |             round(float(vat_percent), 2), discount) | ||||||
|  | @ -215,11 +222,6 @@ def get_ip_addresses(vm_id): | ||||||
|         return "--" |         return "--" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def round_up(n, decimals=0): |  | ||||||
|     multiplier = 10 ** decimals |  | ||||||
|     return math.ceil(n * multiplier) / multiplier |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class HostingUtils: | class HostingUtils: | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def clear_items_from_list(from_list, items_list): |     def clear_items_from_list(from_list, items_list): | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue