tests and actions
Some checks failed
Pricing Tests / Pricing Model Tests (push) Failing after 4s
Pricing Tests / Pricing Documentation Check (push) Failing after 3s

This commit is contained in:
Tobias Brunner 2025-06-20 10:46:11 +02:00
parent c05feb37d3
commit 78f52ea7f4
No known key found for this signature in database
17 changed files with 4140 additions and 3 deletions

View file

@ -0,0 +1,125 @@
"""
Test utilities and fixtures for pricing tests
"""
from decimal import Decimal
from django.test import TestCase
from ..models.base import Currency, Term, Unit
from ..models.providers import CloudProvider
from ..models.services import Service, Category
from ..models.pricing import (
ProgressiveDiscountModel,
DiscountTier,
VSHNAppCatPrice,
VSHNAppCatBaseFee,
VSHNAppCatUnitRate,
)
class PricingTestMixin:
"""Mixin providing common setup for pricing tests"""
def create_test_cloud_provider(self, name="Test Provider"):
"""Create a test cloud provider"""
return CloudProvider.objects.create(
name=name,
slug=name.lower().replace(" ", "-"),
description=f"{name} description",
website=f"https://{name.lower().replace(' ', '')}.com",
)
def create_test_service(self, name="Test Service"):
"""Create a test service"""
return Service.objects.create(
name=name,
slug=name.lower().replace(" ", "-"),
description=f"{name} description",
features=f"{name} features",
)
def create_test_discount_model(self, name="Test Discount", tiers=None):
"""Create a test discount model with optional tiers"""
discount_model = ProgressiveDiscountModel.objects.create(
name=name, description=f"{name} description", active=True
)
if tiers is None:
# Default tiers: 0-9 (0%), 10-49 (10%), 50+ (20%)
tiers = [
(0, 10, Decimal("0.00")),
(10, 50, Decimal("10.00")),
(50, None, Decimal("20.00")),
]
for min_units, max_units, discount_percent in tiers:
DiscountTier.objects.create(
discount_model=discount_model,
min_units=min_units,
max_units=max_units,
discount_percent=discount_percent,
)
return discount_model
def create_test_appcat_price(
self,
service,
discount_model=None,
base_fee=Decimal("50.00"),
unit_rate=Decimal("5.0000"),
):
"""Create a test AppCat price configuration"""
appcat_price = VSHNAppCatPrice.objects.create(
service=service,
variable_unit=VSHNAppCatPrice.VariableUnit.RAM,
term=Term.MTH,
discount_model=discount_model,
)
# Create base fee
VSHNAppCatBaseFee.objects.create(
vshn_appcat_price_config=appcat_price,
currency=Currency.CHF,
amount=base_fee,
)
# Create unit rate
VSHNAppCatUnitRate.objects.create(
vshn_appcat_price_config=appcat_price,
currency=Currency.CHF,
service_level=VSHNAppCatPrice.ServiceLevel.GUARANTEED,
amount=unit_rate,
)
return appcat_price
def calculate_expected_discounted_price(base_rate, units, discount_tiers):
"""Helper function to calculate expected discounted price manually"""
final_price = Decimal("0")
remaining_units = units
# Sort tiers by min_units
sorted_tiers = sorted(discount_tiers, key=lambda x: x[0])
for min_units, max_units, discount_percent in sorted_tiers:
if remaining_units <= 0:
break
# Skip if we haven't reached this tier yet
if units < min_units:
continue
# Calculate units in this tier
tier_max = max_units if max_units else float("inf")
units_start = max(0, units - remaining_units)
units_end = min(units, tier_max if max_units else units)
tier_units = max(0, units_end - max(units_start, min_units - 1))
if tier_units > 0:
discounted_rate = base_rate * (1 - discount_percent / 100)
final_price += discounted_rate * tier_units
remaining_units -= tier_units
return final_price