177 lines
7.2 KiB
Python
177 lines
7.2 KiB
Python
from django.shortcuts import render
|
|
import re
|
|
from collections import defaultdict
|
|
from hub.services.models import ComputePlan, VSHNAppCatPrice
|
|
|
|
|
|
def natural_sort_key(name):
|
|
match = re.search(r"compute-std-(\d+)", name)
|
|
return int(match.group(1)) if match else 0
|
|
|
|
|
|
def pricelist(request):
|
|
compute_plans = (
|
|
ComputePlan.objects.filter(active=True)
|
|
.select_related("cloud_provider")
|
|
.prefetch_related("prices")
|
|
.order_by("cloud_provider__name")
|
|
)
|
|
|
|
compute_plans = sorted(
|
|
compute_plans, key=lambda x: (x.cloud_provider.name, natural_sort_key(x.name))
|
|
)
|
|
|
|
appcat_prices = (
|
|
VSHNAppCatPrice.objects.all()
|
|
.select_related("service", "discount_model")
|
|
.prefetch_related("base_fees", "unit_rates", "discount_model__tiers")
|
|
.order_by("service__name")
|
|
)
|
|
|
|
pricing_data_by_service_level = defaultdict(list)
|
|
processed_combinations = set()
|
|
|
|
for plan in compute_plans:
|
|
plan_currencies = set(plan.prices.values_list("currency", flat=True))
|
|
|
|
for appcat_price in appcat_prices:
|
|
if appcat_price.variable_unit == VSHNAppCatPrice.VariableUnit.RAM:
|
|
units = int(plan.ram)
|
|
elif appcat_price.variable_unit == VSHNAppCatPrice.VariableUnit.CPU:
|
|
units = int(plan.vcpus)
|
|
else:
|
|
continue
|
|
|
|
base_fee_currencies = set(
|
|
appcat_price.base_fees.values_list("currency", flat=True)
|
|
)
|
|
|
|
service_levels = appcat_price.unit_rates.values_list(
|
|
"service_level", flat=True
|
|
).distinct()
|
|
|
|
for service_level in service_levels:
|
|
unit_rate_currencies = set(
|
|
appcat_price.unit_rates.filter(
|
|
service_level=service_level
|
|
).values_list("currency", flat=True)
|
|
)
|
|
|
|
matching_currencies = plan_currencies.intersection(
|
|
base_fee_currencies
|
|
).intersection(unit_rate_currencies)
|
|
|
|
if not matching_currencies:
|
|
continue
|
|
|
|
for currency in matching_currencies:
|
|
combination_key = (
|
|
plan.cloud_provider.name,
|
|
plan.name,
|
|
appcat_price.service.name,
|
|
service_level,
|
|
currency,
|
|
)
|
|
|
|
if combination_key in processed_combinations:
|
|
continue
|
|
|
|
processed_combinations.add(combination_key)
|
|
|
|
compute_plan_price = plan.get_price(currency)
|
|
if compute_plan_price is None:
|
|
continue
|
|
|
|
base_fee = appcat_price.get_base_fee(currency)
|
|
if base_fee is None:
|
|
continue
|
|
|
|
unit_rate = appcat_price.get_unit_rate(currency, service_level)
|
|
if unit_rate is None:
|
|
continue
|
|
|
|
if service_level == VSHNAppCatPrice.ServiceLevel.GUARANTEED:
|
|
replica_enforce = appcat_price.ha_replica_min
|
|
else:
|
|
replica_enforce = 1
|
|
|
|
total_units = units * replica_enforce
|
|
standard_sla_price = base_fee + (total_units * unit_rate)
|
|
|
|
discount_breakdown = None
|
|
if (
|
|
appcat_price.discount_model
|
|
and appcat_price.discount_model.active
|
|
):
|
|
discounted_price = (
|
|
appcat_price.discount_model.calculate_discount(
|
|
unit_rate, total_units
|
|
)
|
|
)
|
|
sla_price = base_fee + discounted_price
|
|
discount_savings = standard_sla_price - sla_price
|
|
discount_percentage = (
|
|
(discount_savings / standard_sla_price) * 100
|
|
if standard_sla_price > 0
|
|
else 0
|
|
)
|
|
discount_breakdown = (
|
|
appcat_price.discount_model.get_discount_breakdown(
|
|
unit_rate, total_units
|
|
)
|
|
)
|
|
else:
|
|
sla_price = standard_sla_price
|
|
discounted_price = total_units * unit_rate
|
|
discount_savings = 0
|
|
discount_percentage = 0
|
|
|
|
final_price = compute_plan_price + sla_price
|
|
service_level_display = dict(VSHNAppCatPrice.ServiceLevel.choices)[
|
|
service_level
|
|
]
|
|
|
|
pricing_data_by_service_level[service_level_display].append(
|
|
{
|
|
"cloud_provider": plan.cloud_provider.name,
|
|
"service": appcat_price.service.name,
|
|
"compute_plan": plan.name,
|
|
"vcpus": plan.vcpus,
|
|
"ram": plan.ram,
|
|
"cpu_mem_ratio": plan.cpu_mem_ratio,
|
|
"term": plan.get_term_display(),
|
|
"currency": currency,
|
|
"compute_plan_price": compute_plan_price,
|
|
"variable_unit": appcat_price.get_variable_unit_display(),
|
|
"units": units,
|
|
"replica_enforce": replica_enforce,
|
|
"total_units": total_units,
|
|
"service_level": service_level_display,
|
|
"sla_base": base_fee,
|
|
"sla_per_unit": unit_rate,
|
|
"sla_price": sla_price,
|
|
"standard_sla_price": standard_sla_price,
|
|
"discounted_sla_price": (
|
|
base_fee + discounted_price
|
|
if appcat_price.discount_model
|
|
and appcat_price.discount_model.active
|
|
else None
|
|
),
|
|
"discount_savings": discount_savings,
|
|
"discount_percentage": discount_percentage,
|
|
"discount_breakdown": discount_breakdown,
|
|
"final_price": final_price,
|
|
"discount_model": (
|
|
appcat_price.discount_model.name
|
|
if appcat_price.discount_model
|
|
else None
|
|
),
|
|
"has_discount": bool(
|
|
appcat_price.discount_model
|
|
and appcat_price.discount_model.active
|
|
),
|
|
}
|
|
)
|
|
|
|
context = {"pricing_data_by_service_level": dict(pricing_data_by_service_level)}
|
|
return render(request, "services/pricelist.html", context)
|