website/hub/services/templates/services/pricelist.html

440 lines
No EOL
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'base.html' %}
{% load static %}
{% block title %}Complete Price List{% endblock %}
{% block extra_js %}
<script src="{% static "js/chart.js" %}"></script>
{% endblock %}
{% block content %}
<div class="container-fluid mt-4">
<div class="row">
<div class="col-12">
<h1 class="mb-4">Complete Price List - All Service Variants</h1>
<!-- Filter Form -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">Filters</h5>
</div>
<div class="card-body">
<form method="get" class="row g-3" id="filter-form">
<div class="col-md-3">
<label for="cloud_provider" class="form-label">Cloud Provider</label>
<select name="cloud_provider" id="cloud_provider" class="form-select filter-select">
<option value="">All Providers</option>
{% for provider in all_cloud_providers %}
<option value="{{ provider }}" {% if provider == filter_cloud_provider %}selected{% endif %}>
{{ provider }}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label for="service" class="form-label">Service</label>
<select name="service" id="service" class="form-select filter-select">
<option value="">All Services</option>
{% for service in all_services %}
<option value="{{ service }}" {% if service == filter_service %}selected{% endif %}>
{{ service }}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label for="compute_plan_group" class="form-label">Compute Plan Group</label>
<select name="compute_plan_group" id="compute_plan_group" class="form-select filter-select">
<option value="">All Groups</option>
{% for group in all_compute_plan_groups %}
<option value="{{ group }}" {% if group == filter_compute_plan_group %}selected{% endif %}>
{{ group }}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label for="service_level" class="form-label">Service Level</label>
<select name="service_level" id="service_level" class="form-select filter-select">
<option value="">All Service Levels</option>
{% for level in all_service_levels %}
<option value="{{ level }}" {% if level == filter_service_level %}selected{% endif %}>
{{ level }}
</option>
{% endfor %}
</select>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="discount_details" value="true" id="discount_details" {% if show_discount_details %}checked{% endif %}>
<label class="form-check-label" for="discount_details">
Show discount details
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="price_comparison" value="true" id="price_comparison" {% if show_price_comparison %}checked{% endif %}>
<label class="form-check-label" for="price_comparison">
Show external price comparisons
</label>
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Apply Filters</button>
<a href="{% url 'services:pricelist' %}" class="btn btn-secondary">Clear Filters</a>
</div>
</form>
</div>
</div>
<!-- Active Filters Display -->
{% if filter_cloud_provider or filter_service or filter_compute_plan_group or filter_service_level %}
<div class="alert alert-info">
<strong>Active Filters:</strong>
{% if filter_cloud_provider %}<span class="badge me-1">Cloud Provider: {{ filter_cloud_provider }}</span>{% endif %}
{% if filter_service %}<span class="badge me-1">Service: {{ filter_service }}</span>{% endif %}
{% if filter_compute_plan_group %}<span class="badge me-1">Group: {{ filter_compute_plan_group }}</span>{% endif %}
{% if filter_service_level %}<span class="badge me-1">Service Level: {{ filter_service_level }}</span>{% endif %}
</div>
{% endif %}
{% if pricing_data_by_group_and_service_level %}
{% for group_name, service_levels in pricing_data_by_group_and_service_level.items %}
<div class="mb-5 border rounded p-3">
<h2 class="mb-3 text-primary">{{ group_name }}</h2>
{# Display group description and node_label from first available plan #}
{% for service_level, pricing_data in service_levels.items %}
{% if pricing_data and forloop.first %}
{% with pricing_data.0 as representative_plan %}
{% if representative_plan.compute_plan_group_description %}
<p class="text-muted mb-2"><strong>Description:</strong> {{ representative_plan.compute_plan_group_description }}</p>
{% endif %}
{% if representative_plan.compute_plan_group_node_label %}
<p class="text-muted mb-3"><strong>Node Label:</strong> <code>{{ representative_plan.compute_plan_group_node_label }}</code></p>
{% endif %}
{# Display storage pricing for this cloud provider #}
{% if representative_plan.storage_plans %}
<div class="mb-3">
<p class="text-muted mb-2"><strong>Storage Options:</strong></p>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead class="table-secondary">
<tr>
<th>Storage Plan</th>
<th>Term</th>
<th>Unit</th>
<th>Prices</th>
</tr>
</thead>
<tbody>
{% for storage_plan in representative_plan.storage_plans %}
<tr>
<td>{{ storage_plan.name }}</td>
<td>{{ storage_plan.get_term_display }}</td>
<td>{{ storage_plan.get_unit_display }}</td>
<td>
{% for price in storage_plan.prices.all %}
<span class="badge bg-light text-dark me-1">{{ price.amount }} {{ price.currency }}</span>
{% empty %}
<span class="text-muted">No prices</span>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% endwith %}
{% endif %}
{% endfor %}
{% for service_level, pricing_data in service_levels.items %}
<div class="mb-4">
<h3 class="mb-3">SLA: {{ service_level }}</h3>
{% if pricing_data %}
{# Display common values for this service level #}
{% with pricing_data.0 as first_row %}
<div class="row mb-3">
<div class="col-md-2">
<strong>Cloud Provider:</strong> {{ first_row.cloud_provider }}
</div>
<div class="col-md-2">
<strong>Service:</strong> {{ first_row.service }}
</div>
<div class="col-md-2">
<strong>CPU/Memory Ratio:</strong> {{ first_row.cpu_mem_ratio }}
</div>
<div class="col-md-2">
<strong>Variable Unit:</strong> {{ first_row.variable_unit }}
</div>
<div class="col-md-2">
<strong>Replica Enforce:</strong> {{ first_row.replica_enforce }}
</div>
</div>
{% endwith %}
<div class="table-responsive">
<table class="table table-striped table-bordered table-sm pricing-table">
<thead class="table-dark">
<tr>
<th>Compute Plan</th>
<th>Cloud Provider</th>
<th>vCPUs</th>
<th>RAM (GB)</th>
<th>Term</th>
<th>Currency</th>
<th>Compute Plan Price</th>
<th>Units</th>
<th>SLA Base</th>
<th>SLA Per Unit</th>
<th>SLA Price</th>
{% if show_discount_details %}
<th>Discount Model</th>
<th>Discount Details</th>
{% endif %}
{% if show_price_comparison %}
<th>External Comparisons</th>
{% endif %}
<th class="final-price-header">Final Price</th>
</tr>
</thead>
<tbody>
{% for row in pricing_data %}
<tr class="servala-row">
<td>{{ row.compute_plan }}</td>
<td>{{ row.cloud_provider }}</td>
<td>{{ row.vcpus }}</td>
<td>{{ row.ram }}</td>
<td>{{ row.term }}</td>
<td>{{ row.currency }}</td>
<td>{{ row.compute_plan_price|floatformat:2 }}</td>
<td>{{ row.units }}</td>
<td>{{ row.sla_base|floatformat:2 }}</td>
<td>{{ row.sla_per_unit|floatformat:4 }}</td>
<td>{{ row.sla_price|floatformat:2 }}</td>
{% if show_discount_details %}
<td>
{% if row.has_discount %}
{{ row.discount_model }}
{% else %}
None
{% endif %}
</td>
<td>
{% if row.has_discount %}
<small class="text-muted">
<strong>Total Units:</strong> {{ row.total_units }}<br>
<strong>Standard Price:</strong> {{ row.standard_sla_price|floatformat:2 }}<br>
<strong>Discounted Price:</strong> {{ row.discounted_sla_price|floatformat:2 }}<br>
<strong>Savings:</strong> {{ row.discount_savings|floatformat:2 }} ({{ row.discount_percentage|floatformat:1 }}%)<br>
{% if row.discount_breakdown %}
<strong>Breakdown:</strong><br>
{% for tier in row.discount_breakdown %}
{{ tier.tier_range }} units: {{ tier.units }} × {{ tier.rate|floatformat:4 }} = {{ tier.subtotal|floatformat:2 }}<br>
{% endfor %}
{% endif %}
</small>
{% else %}
<small class="text-muted">No discount applied</small>
{% endif %}
</td>
{% endif %}
{% if show_price_comparison %}
<td>
<span class="badge">-</span>
</td>
{% endif %}
<td class="final-price-cell fw-bold">{{ row.final_price|floatformat:2 }}</td>
</tr>
{% if show_price_comparison and row.external_comparisons %}
{% for comparison in row.external_comparisons %}
<tr class="table-light comparison-row">
<td class="text-muted">{{ comparison.plan_name }}</td>
<td class="text-muted">{{ comparison.provider }}</td>
<td class="text-muted">
{% if comparison.vcpus %}{{ comparison.vcpus }}{% else %}-{% endif %}
</td>
<td class="text-muted">
{% if comparison.ram %}{{ comparison.ram }}{% else %}-{% endif %}
</td>
<td class="text-muted">{{ row.term }}</td>
<td class="text-muted">{{ comparison.currency }}</td>
<td class="text-muted">-</td>
<td class="text-muted">-</td>
<td class="text-muted">-</td>
<td class="text-muted">-</td>
<td class="text-muted">-</td>
{% if show_discount_details %}
<td class="text-muted">-</td>
<td class="text-muted">-</td>
{% endif %}
<td>
<small>
<span class="badge bg-secondary">{% if comparison.source %}<span class="text-muted"><a href="{{ comparison.source }}" target="_blank">{{ comparison.provider }}</a></span>{% else %}{{ comparison.provider }}{% endif %}</span><br>
{% if comparison.description %}
<span class="text-muted">{{ comparison.description }}</span><br>
{% endif %}
{% if comparison.storage %}
<span class="text-muted">Storage: {{ comparison.storage }} GB</span><br>
{% endif %}
{% if comparison.replicas %}
<span class="text-muted">Replicas: {{ comparison.replicas }}</span><br>
{% endif %}
{% if comparison.ratio %}
<span class="text-muted">Price ratio: {{ comparison.ratio|floatformat:2 }}x</span><br>
{% endif %}
</small>
</td>
<td class="fw-bold">
{{ comparison.amount|floatformat:2 }} {{ comparison.currency }}
{% if comparison.difference > 0 %}
<span class="badge bg-success ms-1">+{{ comparison.difference|floatformat:2 }}</span>
{% elif comparison.difference < 0 %}
<span class="badge bg-danger ms-1">{{ comparison.difference|floatformat:2 }}</span>
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{# Price Chart #}
<div class="price-chart mt-3">
<h5 class="text-muted">Price Chart - Units vs Final Price</h5>
<div style="height: 400px;">
<canvas id="chart-{{ group_name|slugify }}-{{ service_level|slugify }}" width="400" height="200"></canvas>
</div>
</div>
<p class="text-muted"><strong>{{ pricing_data|length }}</strong> variants for {{ service_level }} in {{ group_name }}</p>
{% else %}
<p class="text-muted">No pricing variants available for {{ service_level }} in {{ group_name }}.</p>
{% endif %}
</div>
{% empty %}
<p class="text-muted">No service levels with pricing data found for group: {{ group_name }}.</p>
{% endfor %}
</div>
{% endfor %}
{% else %}
<div class="alert alert-info">
<h4>No pricing data available</h4>
<p>{% if filter_cloud_provider or filter_service or filter_compute_plan_group or filter_service_level %}No data matches the selected filters. Try adjusting your filter criteria.{% else %}Please ensure you have active compute plans with prices and VSHNAppCat price configurations.{% endif %}</p>
</div>
{% endif %}
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-submit form when filter dropdowns change
const filterForm = document.getElementById('filter-form');
const filterSelects = document.querySelectorAll('.filter-select');
const discountCheckbox = document.getElementById('discount_details');
// Add change event listeners to all filter dropdowns
filterSelects.forEach(function(select) {
select.addEventListener('change', function() {
filterForm.submit();
});
});
// Add change event listener to discount details checkbox
discountCheckbox.addEventListener('change', function() {
filterForm.submit();
});
// Add change event listener to price comparison checkbox
const priceComparisonCheckbox = document.getElementById('price_comparison');
priceComparisonCheckbox.addEventListener('change', function() {
filterForm.submit();
});
// 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 %}
// Prepare data for {{ group_name }} - {{ service_level }}
const chartData{{ forloop.parentloop.counter }}{{ forloop.counter }} = {
labels: [{% for row in pricing_data %}{{ row.units }}{% if not forloop.last %}, {% endif %}{% endfor %}],
datasets: [
{
label: 'Final Price',
data: [{% for row in pricing_data %}{{ row.final_price|floatformat:2 }}{% if not forloop.last %}, {% endif %}{% endfor %}],
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
tension: 0.1,
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)',
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)',
tension: 0.1,
fill: false
}
]
};
// Create chart for {{ group_name }} - {{ service_level }}
const ctx{{ forloop.parentloop.counter }}{{ forloop.counter }} = document.getElementById('chart-{{ group_name|slugify }}-{{ service_level|slugify }}').getContext('2d');
new Chart(ctx{{ forloop.parentloop.counter }}{{ forloop.counter }}, {
type: 'line',
data: chartData{{ forloop.parentloop.counter }}{{ forloop.counter }},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
title: {
display: true,
text: 'Units'
}
},
y: {
title: {
display: true,
text: 'Price ({{ pricing_data.0.currency|default:"CHF" }})'
},
beginAtZero: true
}
},
plugins: {
title: {
display: true,
text: '{{ group_name }} - {{ service_level }} Pricing'
},
legend: {
display: true
}
},
elements: {
point: {
radius: 4,
hoverRadius: 6
}
}
}
});
{% endif %}
{% endfor %}
{% endfor %}
});
</script>
{% endblock %}