|
@@ -1,7 +1,83 @@
|
|
|
|
+import datetime
|
|
|
|
+
|
|
from django.test import TestCase
|
|
from django.test import TestCase
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.exceptions import ValidationError
|
|
|
|
|
|
-from ..models import Service, Cost, CostUse, Document
|
|
|
|
|
|
+from ..models import (
|
|
|
|
+ Cost, CostUse, Document, Good, GoodUse, Service, ServiceUse)
|
|
|
|
+
|
|
|
|
+THREE_YEARS = datetime.timedelta(days=365*3)
|
|
|
|
+
|
|
|
|
+class ServiceTests(TestCase):
|
|
|
|
+ def setUp(self):
|
|
|
|
+ self.doc = Document.objects.create(name='budget')
|
|
|
|
+ self.electricity_cost = Cost.objects.create(
|
|
|
|
+ name='electricity',
|
|
|
|
+ price=10,
|
|
|
|
+ document=self.doc,
|
|
|
|
+ )
|
|
|
|
+ self.server = Good.objects.create(
|
|
|
|
+ name="Computer",
|
|
|
|
+ price=10,
|
|
|
|
+ document=self.doc,
|
|
|
|
+ provisioning_duration=THREE_YEARS,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ def test_get_prices_zero(self):
|
|
|
|
+ s = Service.objects.create(name='Foo', document=self.doc)
|
|
|
|
+ self.assertEqual(s.get_prices(), {
|
|
|
|
+ 'total_recurring_price': 0,
|
|
|
|
+ 'unit_recurring_price': 0,
|
|
|
|
+ 'unit_goods_value_share': 0,
|
|
|
|
+ 'total_goods_value_share': 0,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ def test_get_prices_w_costs(self):
|
|
|
|
+ s = Service.objects.create(name='Foo', document=self.doc)
|
|
|
|
+
|
|
|
|
+ CostUse.objects.create(
|
|
|
|
+ service=s, resource=self.electricity_cost, share=0.4)
|
|
|
|
+
|
|
|
|
+ self.assertEqual(s.get_prices(), {
|
|
|
|
+ 'total_recurring_price': 10,
|
|
|
|
+ 'unit_recurring_price': 0,
|
|
|
|
+ 'unit_goods_value_share': 0,
|
|
|
|
+ 'total_goods_value_share': 0,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ s.subscriptions_count = 2
|
|
|
|
+ s.save()
|
|
|
|
+
|
|
|
|
+ self.assertEqual(s.get_prices(), {
|
|
|
|
+ 'total_recurring_price': 10,
|
|
|
|
+ 'unit_recurring_price': 5,
|
|
|
|
+ 'unit_goods_value_share': 0,
|
|
|
|
+ 'total_goods_value_share': 0,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ def test_get_prices_w_goods(self):
|
|
|
|
+ s = Service.objects.create(
|
|
|
|
+ name='Foo', document=self.doc, subscriptions_count=0)
|
|
|
|
+
|
|
|
|
+ GoodUse.objects.create(
|
|
|
|
+ service=s, resource=self.server, share=0.4)
|
|
|
|
+
|
|
|
|
+ self.assertEqual(s.get_prices(), {
|
|
|
|
+ 'total_recurring_price': 10/(365*3)*365.25/12,
|
|
|
|
+ 'unit_recurring_price': 0,
|
|
|
|
+ 'unit_goods_value_share': 0,
|
|
|
|
+ 'total_goods_value_share': 10.0,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ s.subscriptions_count = 2
|
|
|
|
+ s.save()
|
|
|
|
+
|
|
|
|
+ self.assertEqual(s.get_prices(), {
|
|
|
|
+ 'total_recurring_price': 10/(365*3)*365.25/12,
|
|
|
|
+ 'unit_recurring_price': 10/(365*3)*365.25/12/2,
|
|
|
|
+ 'unit_goods_value_share': 5,
|
|
|
|
+ 'total_goods_value_share': 10,
|
|
|
|
+ })
|
|
|
|
|
|
|
|
|
|
class AbstractUseTests(TestCase):
|
|
class AbstractUseTests(TestCase):
|
|
@@ -22,6 +98,12 @@ class AbstractUseTests(TestCase):
|
|
total_capacity=4,
|
|
total_capacity=4,
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+ self.carrier_connection = Cost.objects.create(
|
|
|
|
+ name='carrier connection',
|
|
|
|
+ price=100,
|
|
|
|
+ document=self.doc,
|
|
|
|
+ )
|
|
|
|
+
|
|
def test_can_add_service_share(self):
|
|
def test_can_add_service_share(self):
|
|
use = CostUse(
|
|
use = CostUse(
|
|
service=self.hosting_service,
|
|
service=self.hosting_service,
|
|
@@ -152,3 +234,112 @@ class AbstractUseTests(TestCase):
|
|
|
|
|
|
self.assertEqual(self.electricity_cost.used(), 0.5)
|
|
self.assertEqual(self.electricity_cost.used(), 0.5)
|
|
self.assertEqual(self.electricity_cost.unused(), 3.5)
|
|
self.assertEqual(self.electricity_cost.unused(), 3.5)
|
|
|
|
+
|
|
|
|
+ def test_service_using_service(self):
|
|
|
|
+ """
|
|
|
|
+ Wifi+VPN is a service, but using VPN access
|
|
|
|
+ So there is a service using another service
|
|
|
|
+ """
|
|
|
|
+
|
|
|
|
+ vpn_service = Service.objects.create(
|
|
|
|
+ name="VPN",
|
|
|
|
+ document=self.doc,
|
|
|
|
+ subscriptions_count=20, # includes wifi+vpn subscribers
|
|
|
|
+ reusable=True,
|
|
|
|
+ )
|
|
|
|
+ # both should be auto-set
|
|
|
|
+ self.assertEqual(vpn_service.capacity_unit, 'services')
|
|
|
|
+ self.assertEqual(vpn_service.total_capacity, 20)
|
|
|
|
+
|
|
|
|
+ wifi_service = Service.objects.create(
|
|
|
|
+ name="Wifi, via VPN",
|
|
|
|
+ document=self.doc,
|
|
|
|
+ subscriptions_count=2,
|
|
|
|
+ reusable=True,
|
|
|
|
+ )
|
|
|
|
+ self.assertEqual(vpn_service.capacity_unit, 'services')
|
|
|
|
+
|
|
|
|
+ # To simplify, VPN is only using electricity
|
|
|
|
+ CostUse.objects.create(
|
|
|
|
+ service=vpn_service,
|
|
|
|
+ resource=self.electricity_cost,
|
|
|
|
+ share=0.5, # Amp
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # Wifi is using VPN + a carrier connection
|
|
|
|
+ wifi_vpn_use = ServiceUse.objects.create(
|
|
|
|
+ service=wifi_service,
|
|
|
|
+ resource=vpn_service,
|
|
|
|
+ share=2,
|
|
|
|
+ )
|
|
|
|
+ CostUse.objects.create(
|
|
|
|
+ service=wifi_service,
|
|
|
|
+ resource=self.carrier_connection,
|
|
|
|
+ share=1, # 100%
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ self.assertEqual(wifi_vpn_use.share, 0.5*4*10/20*2)
|
|
|
|
+ self.assertEqual(wifi_vpn_use.unit_share(), 0.5*4*10/20)
|
|
|
|
+
|
|
|
|
+ # VPN this is the only service using electricity
|
|
|
|
+ self.assertEqual(wifi_vpn_use.unit_real_share(), 10)
|
|
|
|
+
|
|
|
|
+ # VPN is now using some gear, with deprecation provisioning
|
|
|
|
+ hosting_access_fee = Good.objects.create(
|
|
|
|
+ name='hosting access fee', price=360,
|
|
|
|
+ provisioning_duration=THREE_YEARS, document=self.doc)
|
|
|
|
+ GoodUse.objects.create(
|
|
|
|
+ service=vpn_service, resource=hosting_access_fee, share=2)
|
|
|
|
+ self.assertEqual(
|
|
|
|
+ wifi_service.get_prices()['total_goods_value_share'], 36)
|
|
|
|
+ self.assertEqual(
|
|
|
|
+ wifi_service.get_prices()['unit_goods_value_share'], 18)
|
|
|
|
+
|
|
|
|
+ def test_service_using_non_usable_service(self):
|
|
|
|
+ serva = Service.objects.create(
|
|
|
|
+ name='A', document=self.doc,
|
|
|
|
+ subscriptions_count=4,
|
|
|
|
+ reusable=False,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ with self.assertRaises(ValidationError):
|
|
|
|
+ su = ServiceUse(
|
|
|
|
+ service=self.mailbox_service,
|
|
|
|
+ resource=serva,
|
|
|
|
+ share=1,
|
|
|
|
+ )
|
|
|
|
+ su.full_clean()
|
|
|
|
+ su.save()
|
|
|
|
+
|
|
|
|
+ def test_service_using_cyclic_service(self):
|
|
|
|
+ """ We should not save any service dependency building a cycle
|
|
|
|
+ """
|
|
|
|
+ a = Service.objects.create(
|
|
|
|
+ name='a', document=self.doc,
|
|
|
|
+ reusable=True,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ b = Service.objects.create(
|
|
|
|
+ name='b', document=self.doc,
|
|
|
|
+ reusable=True,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ c = Service.objects.create(
|
|
|
|
+ name='c', document=self.doc,
|
|
|
|
+ reusable=True,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ def create_clean(user, used):
|
|
|
|
+ new_use = ServiceUse(service=user, resource=used, share=1)
|
|
|
|
+ new_use.full_clean()
|
|
|
|
+ new_use.save()
|
|
|
|
+
|
|
|
|
+ create_clean(a, b)
|
|
|
|
+
|
|
|
|
+ with self.assertRaises(ValidationError):
|
|
|
|
+ create_clean(b, a)
|
|
|
|
+
|
|
|
|
+ create_clean(b, c)
|
|
|
|
+
|
|
|
|
+ with self.assertRaises(ValidationError):
|
|
|
|
+ create_clean(c, a)
|