diff --git a/hub/services/templates/services/pricelist.html b/hub/services/templates/services/pricelist.html index 4901cae..bc90f6d 100644 --- a/hub/services/templates/services/pricelist.html +++ b/hub/services/templates/services/pricelist.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load static %} +{% load math_tags %} {% block title %}Complete Price List{% endblock %} @@ -51,6 +52,69 @@ .servala-row { border-bottom: 2px solid #007bff; } + + /* Price calculation breakdown styling */ + .price-breakdown-header { + background: linear-gradient(135deg, #28a745, #20b2aa); + } + + .compute-plan-col { + background-color: rgba(13, 110, 253, 0.1); + border-right: 2px solid #0d6efd; + } + + .sla-base-col { + background-color: rgba(111, 66, 193, 0.1); + border-right: 2px solid #6f42c1; + } + + .sla-units-col { + background-color: rgba(253, 126, 20, 0.1); + border-right: 2px solid #fd7e14; + } + + .mandatory-addons-col { + background-color: rgba(220, 53, 69, 0.1); + border-right: 2px solid #dc3545; + } + + .total-sla-col { + background-color: rgba(25, 135, 84, 0.2); + border-right: 3px solid #198754; + } + + /* Mathematical operator styling */ + .math-operator { + font-size: 1.2em; + font-weight: bold; + color: #666; + padding: 0 5px; + } + + /* Price calculation formula helper */ + .price-formula { + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + padding: 10px; + margin-bottom: 20px; + font-family: monospace; + text-align: center; + } + + .price-formula .formula-part { + display: inline-block; + padding: 2px 8px; + margin: 0 5px; + border-radius: 3px; + font-weight: bold; + } + + .price-formula .compute-part { background-color: rgba(13, 110, 253, 0.2); color: #0d6efd; } + .price-formula .sla-base-part { background-color: rgba(111, 66, 193, 0.2); color: #6f42c1; } + .price-formula .sla-units-part { background-color: rgba(253, 126, 20, 0.2); color: #fd7e14; } + .price-formula .addons-part { background-color: rgba(220, 53, 69, 0.2); color: #dc3545; } + .price-formula .equals-part { background-color: rgba(25, 135, 84, 0.2); color: #198754; } {% endblock %} @@ -60,6 +124,61 @@

Complete Price List - All Service Variants

+ +
+ +
+
+
+
+
Price Components
+
    +
  • + Compute Plan Price + Base infrastructure cost for CPU, memory, and storage +
  • +
  • + SLA Base + Fixed cost for the service level agreement +
  • +
  • + Units × SLA Per Unit + Variable cost based on scale/usage +
  • +
  • + Mandatory Add-ons + Required additional services (backup, monitoring, etc.) +
  • +
+
+
+
Final Price Formula
+
+ + Compute Plan Price + + SLA Base + + (Units × SLA Per Unit) + + Mandatory Add-ons = + Final Price + +
+

+ + This transparent pricing model ensures you understand exactly what you're paying for. + The table below breaks down each component for every service variant we offer. + +

+
+
+
+
+
+
@@ -278,32 +397,49 @@ {% endif %} {% endwith %} + +
+ Final Price Calculation:
+ Compute Plan Price + + + SLA Base + + + Units × SLA Per Unit + + + Mandatory Add-ons + = + Final Price +
+
- - - - - - - - - - - + + + + + + + {% if show_addon_details %} - + {% endif %} {% if show_discount_details %} - - + + {% endif %} {% if show_price_comparison %} - + {% endif %} - + + + + + + + + @@ -315,11 +451,44 @@ - - - - - + + + + + + {% if show_addon_details %} + @@ -462,7 +632,7 @@ {# Price Chart #}
-
Price Chart - Units vs Final Price
+
Price Breakdown Chart - Units vs Price Components
@@ -517,9 +687,7 @@ document.addEventListener('DOMContentLoaded', function() { const priceComparisonCheckbox = document.getElementById('price_comparison'); priceComparisonCheckbox.addEventListener('change', function() { filterForm.submit(); - }); - - // Chart data for each service level + }); // Chart data for each service level {% for group_name, service_levels in pricing_data_by_group_and_service_level.items %} {% for service_level, pricing_data in service_levels.items %} {% if pricing_data %} @@ -536,18 +704,42 @@ document.addEventListener('DOMContentLoaded', function() { fill: false }, { - label: 'SLA Price', - data: [{% for row in pricing_data %}{{ row.sla_price|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], - borderColor: 'rgb(255, 99, 132)', - backgroundColor: 'rgba(255, 99, 132, 0.2)', + label: 'Compute Plan Price', + data: [{% for row in pricing_data %}{{ row.compute_plan_price|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], + borderColor: 'rgb(13, 110, 253)', + backgroundColor: 'rgba(13, 110, 253, 0.2)', tension: 0.1, fill: false }, { - label: 'Compute Plan Price', - data: [{% for row in pricing_data %}{{ row.compute_plan_price|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], - borderColor: 'rgb(54, 162, 235)', - backgroundColor: 'rgba(54, 162, 235, 0.2)', + label: 'SLA Base', + data: [{% for row in pricing_data %}{{ row.sla_base|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], + borderColor: 'rgb(111, 66, 193)', + backgroundColor: 'rgba(111, 66, 193, 0.2)', + tension: 0.1, + fill: false + }, + { + label: 'Units × SLA Per Unit', + data: [{% for row in pricing_data %}{{ row.units|multiply:row.sla_per_unit|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], + borderColor: 'rgb(253, 126, 20)', + backgroundColor: 'rgba(253, 126, 20, 0.2)', + tension: 0.1, + fill: false + }, + { + label: 'Mandatory Add-ons', + data: [{% for row in pricing_data %}{{ row.mandatory_addons|calculate_addon_total:row.units|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], + borderColor: 'rgb(220, 53, 69)', + backgroundColor: 'rgba(220, 53, 69, 0.2)', + tension: 0.1, + fill: false + }, + { + label: 'Total SLA Price', + data: [{% for row in pricing_data %}{{ row.sla_price|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}], + borderColor: 'rgb(25, 135, 84)', + backgroundColor: 'rgba(25, 135, 84, 0.2)', tension: 0.1, fill: false } @@ -580,7 +772,7 @@ document.addEventListener('DOMContentLoaded', function() { plugins: { title: { display: true, - text: '{{ group_name }} - {{ service_level }} Pricing' + text: '{{ group_name }} - {{ service_level }} Price Breakdown' }, legend: { display: true diff --git a/hub/services/templatetags/math_tags.py b/hub/services/templatetags/math_tags.py new file mode 100644 index 0000000..b3d0d35 --- /dev/null +++ b/hub/services/templatetags/math_tags.py @@ -0,0 +1,45 @@ +from django import template + +register = template.Library() + + +@register.filter(name="multiply") +def multiply(value, arg): + """Multiply two numbers in Django templates""" + try: + return float(value) * float(arg) + except (ValueError, TypeError): + return 0 + + +@register.filter(name="add_float") +def add_float(value, arg): + """Add two numbers in Django templates""" + try: + return float(value) + float(arg) + except (ValueError, TypeError): + return 0 + + +@register.filter(name="sum_addon_prices") +def sum_addon_prices(addons): + """Sum the prices of addons""" + try: + return sum(addon.price for addon in addons) + except (AttributeError, TypeError): + return 0 + + +@register.filter(name="calculate_addon_total") +def calculate_addon_total(addons, units): + """Calculate total cost of addons based on their type and units""" + try: + total = 0 + for addon in addons: + if addon.addon_type == "Unit Rate": + total += float(addon.price) * float(units) + else: # Base Fee or other types + total += float(addon.price) + return total + except (AttributeError, TypeError, ValueError): + return 0
Compute PlanCloud ProvidervCPUsRAM (GB)TermCurrencyCompute Plan PriceUnitsSLA BaseSLA Per UnitSLA PriceCompute PlanCloud ProvidervCPUsRAM (GB)TermCurrencyPrice Calculation BreakdownAdd-onsAdd-onsDiscount ModelDiscount DetailsDiscount ModelDiscount DetailsExternal ComparisonsExternal ComparisonsFinal PriceFinal Price
Compute Plan PriceSLA BaseUnits × SLA Per UnitMandatory Add-ons= Total SLA Price
{{ row.ram }} {{ row.term }} {{ row.currency }}{{ row.compute_plan_price|floatformat:2 }}{{ row.units }}{{ row.sla_base|floatformat:2 }}{{ row.sla_per_unit|floatformat:4 }}{{ row.sla_price|floatformat:2 }} + {{ row.compute_plan_price|floatformat:2 }} + + {{ row.sla_base|floatformat:2 }} + + {{ row.units|floatformat:0 }} × {{ row.sla_per_unit|floatformat:4 }}
+ = {{ row.units|multiply:row.sla_per_unit|floatformat:2 }} +
+ {% if row.mandatory_addons %} + {% for addon in row.mandatory_addons %} +
+ {% if addon.addon_type == "Unit Rate" %} + {{ addon.name }}
+ {{ row.units|floatformat:0 }} × {{ addon.price|floatformat:4 }}
+ = {{ row.units|multiply:addon.price|floatformat:2 }} + {% elif addon.addon_type == "Base Fee" %} + {{ addon.name }}
+ {{ addon.price|floatformat:2 }} + {% else %} + {{ addon.name }}
+ {{ addon.price|floatformat:2 }} + {% endif %} +
+ {% if not forloop.last %}
{% endif %} + {% endfor %} + {% else %} + n/a + {% endif %} +
+ {% with addon_total=row.mandatory_addons|calculate_addon_total:row.units %} + {{ row.sla_price|add_float:addon_total|floatformat:2 }} + {% endwith %} + {% if row.mandatory_addons or row.optional_addons %} @@ -415,6 +584,7 @@ {{ row.term }} {{ comparison.currency }} - - -