def _init_one(self):
        """
        Creates pricing service with 2 service usages.
        Pricing service has se4 in excluded services, its usage type has se3 in
        excluded services.

        There are 3 daily pricing objects - one of them belongs to se1 (and
        should not be considered to calculate usages).
        """
        self.ps1 = PricingServiceFactory()
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(2)

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.service_usage_types[0].excluded_services.add(self.se3.service)
        self.service_usage_types[0].save()

        self.ps1.excluded_services.add(self.se4.service)
        self.ps1.save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=30,
        )

        self.dpo1 = DailyPricingObjectFactory()
        self.dpo2 = DailyPricingObjectFactory()
        self.dpo3 = DailyPricingObjectFactory(service_environment=self.se1)

        for dpo in models.DailyPricingObject.objects.all():
            for su, value in zip(self.service_usage_types, [10, 20]):
                models.DailyUsage.objects.create(
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    date=self.today,
                    value=value,
                    type=su,
                )
示例#2
0
    def setUp(self):
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(2)
        self.po1 = PricingObjectFactory(service_environment=self.se1)
        self.po2 = PricingObjectFactory(service_environment=self.se2)

        self.bu1 = ExtraCostTypeFactory()
        self.bu2 = UsageTypeFactory()
        self.bu3 = PricingServiceFactory()
        self.bu4 = PricingServiceFactory()

        self.wh1 = WarehouseFactory()
        self.wh2 = WarehouseFactory()
    def setUp(self):
        self.today = date(2014, 11, 10)

        self.service_environments = ServiceEnvironmentFactory.create_batch(5)
        self.pricing_service1 = PricingServiceFactory()

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin)
        self.pricing_service2 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service2.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service2.save()

        self.pricing_service3 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service3.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service3.save()
    def setUp(self):
        self.today = date(2014, 11, 10)

        self.service_environments = ServiceEnvironmentFactory.create_batch(5)
        self.pricing_service1 = PricingServiceFactory()

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin
        )
        self.pricing_service2 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service2.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service2.save()

        self.pricing_service3 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service3.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service3.save()
    def test_get_pricing_service_real_costs_diff(
        self,
        pricing_service_costs_mock,
    ):
        ps2 = PricingServiceFactory()
        self.pricing_service1.charge_diff_to_real_costs = ps2
        self.pricing_service1.save()

        pricing_service_costs_mock.return_value = {
            self.pricing_service1.id: (D(100), {
                self.service_usage_types[0].id: (D(50), {}),
                self.service_usage_types[1].id: (D(50), {}),
            })
        }

        result = PricingServicePlugin._get_service_charging_by_diffs(
            ps2,
            date=self.today,
            forecast=False,
        )
        self.assertEqual(
            result,
            {
                self.pricing_service1.id: (D(-1100), {})  # 100 - 1200
            })
    def _init(self):
        self.ps1, self.ps2, self.ps3 = PricingServiceFactory.create_batch(3)
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps2,
        )
        self.se5 = ServiceEnvironmentFactory(service__pricing_service=self.ps3)
        self.other_se = ServiceEnvironmentFactory.create_batch(5)

        self.service_usage_types = UsageTypeFactory.create_batch(
            4,
            usage_type='SU',
        )

        self.ps1.excluded_services.add(self.other_se[0].service)
        self.ps1.save()

        self.ps2.excluded_services.add(self.other_se[1].service)
        self.ps2.save()

        self.service_usage_types[0].excluded_services.add(
            self.other_se[2].service)
        self.service_usage_types[0].save()

        self.service_usage_types[3].excluded_services.add(
            self.other_se[4].service)
        self.service_usage_types[3].save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[3],
            pricing_service=self.ps3,
            start=self.start,
            end=self.end,
            percent=100,
        )
    def setUp(self):
        self.components = ComponentsContent()
        self.se1 = ServiceEnvironmentFactory()
        self.se2 = ServiceEnvironmentFactory(service=self.se1.service, )
        self.se3 = ServiceEnvironmentFactory()
        self.today = datetime.date(2014, 10, 11)
        self.tomorrow = datetime.date(2014, 10, 12)
        self.today_accepted = CostDateStatusFactory(date=self.today,
                                                    accepted=True)

        self.ut1 = UsageTypeFactory()
        self.ut2 = PricingServiceFactory()

        self.dpo1, self.dpo2 = DailyAssetInfoFactory.create_batch(
            2,
            service_environment=self.se1,
            pricing_object__service_environment=self.se1,
            date=self.today,
        )
        self.dpo3 = DailyAssetInfoFactory(
            service_environment=self.se2,
            pricing_object__service_environment=self.se2,
            date=self.today,
        )
        self.dpo3 = DailyAssetInfoFactory(
            service_environment=self.se3,
            pricing_object__service_environment=self.se3,
            date=self.today,
        )
        self.dpo4 = DailyAssetInfoFactory(
            service_environment=self.se1,
            pricing_object__service_environment=self.se1,
            date=self.tomorrow,
        )
        self.dc1 = DailyCostFactory(
            type=self.ut1,
            pricing_object=self.dpo1.pricing_object,
            service_environment=self.se1,
            date=self.today,
            value=10,
            cost=20,
        )
        self.dc2 = DailyCostFactory(
            type=self.ut1,
            pricing_object=self.dpo1.pricing_object,
            service_environment=self.se1,
            date=self.today,
            value=20,
            cost=30,
        )
        self.dc3 = DailyCostFactory(
            type=self.ut2,
            pricing_object=self.dpo1.pricing_object,
            service_environment=self.se1,
            date=self.today,
            value=25,
            cost=35,
        )
        self.maxDiff = None
    def _init_one(self):
        """
        Creates pricing service with 2 service usages.
        Pricing service has se4 in excluded services, its usage type has se3 in
        excluded services.

        There are 3 daily pricing objects - one of them belongs to se1 (and
        should not be considered to calculate usages).
        """
        self.ps1 = PricingServiceFactory()
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(2)

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.service_usage_types[0].excluded_services.add(self.se3.service)
        self.service_usage_types[0].save()

        self.ps1.excluded_services.add(self.se4.service)
        self.ps1.save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=30,
        )

        self.dpo1 = DailyPricingObjectFactory()
        self.dpo2 = DailyPricingObjectFactory()
        self.dpo3 = DailyPricingObjectFactory(
            service_environment=self.se1
        )

        for dpo in models.DailyPricingObject.objects.all():
            for su, value in zip(self.service_usage_types, [10, 20]):
                models.DailyUsage.objects.create(
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    date=self.today,
                    value=value,
                    type=su,
                )
示例#9
0
 def generate_data(self, data):
     service = Service.objects.get(name='Load balancing')
     pricing_service = PricingServiceFactory(name='Load balancing')
     for usage_type in data['scrooge_usage_type'].itervalues():
         ServiceUsageTypes.objects.create(
             usage_type=usage_type,
             pricing_service=pricing_service,
             percent=50,
         )
     service.pricing_service = pricing_service
     service.save()
     return {
         'load_balancing': pricing_service,
     }
示例#10
0
    def setUp(self):
        super(TestPricingServiceUsagesApi, self).setUp()
        self.maxDiff = None
        self.resource = 'pricingserviceusages'
        self.user = User.objects.create_user('ralph', '*****@*****.**',
                                             'ralph')
        self.date = datetime.date(2013, 10, 10)

        self.today = datetime.date.today()

        self.pricing_service = PricingServiceFactory()

        self.service_environment1 = ServiceEnvironmentFactory()
        self.service_environment2 = ServiceEnvironmentFactory()
        self.service_environment3 = ServiceEnvironmentFactory()
        self.pricing_object1 = PricingObjectFactory()
        self.pricing_object2 = PricingObjectFactory()

        self.usage_type1 = UsageTypeFactory()
        self.usage_type2 = UsageTypeFactory()

        ServiceUsageTypes.objects.create(
            usage_type=self.usage_type1,
            pricing_service=self.pricing_service,
            start=datetime.date.min,
            end=datetime.date.max,
            percent=50,
        )
        ServiceUsageTypes.objects.create(
            usage_type=self.usage_type2,
            pricing_service=self.pricing_service,
            start=datetime.date.min,
            end=datetime.date.max,
            percent=50,
        )

        self.api_key = self.create_apikey(
            self.user.username,
            self.user.api_key.key,
        )
示例#11
0
 def setUp(self):
     self.today = date(2013, 10, 10)
     self.start = date(2013, 10, 1)
     self.end = date(2013, 10, 30)
     self.pricing_service = PricingServiceFactory()
     self.service_usage_types = UsageTypeFactory.create_batch(
         2,
         usage_type='SU',
     )
     models.ServiceUsageTypes.objects.create(
         usage_type=self.service_usage_types[0],
         pricing_service=self.pricing_service,
         start=self.start,
         end=self.end,
     )
     models.ServiceUsageTypes.objects.create(
         usage_type=self.service_usage_types[1],
         pricing_service=self.pricing_service,
         start=self.start,
         end=self.end,
     )
     self.service_environments = ServiceEnvironmentFactory.create_batch(2)
     self.maxDiff = None
class TestPricingServiceFixedPricePlugin(ScroogeTestCase):
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin
        )
        self.pricing_service1 = PricingServiceFactory(plugin_type=fixed_price)

        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory())

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.sut1 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        self.sut2 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )

        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[0]
        )
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[1]
        )
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[2]
        )

        models.UsagePrice(
            type=self.service_usage_types[0],
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        models.UsagePrice(
            type=self.service_usage_types[1],
            price=20,
            forecast_price=40,
            start=self.start,
            end=self.end,
        ).save()

        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.service_usage_types[0],
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.service_usage_types[1],
                )

    def test_get_fixed_prices_costs(self):
        result = PricingServiceFixedPricePlugin.costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            service_environments=self.service_environments[:2],
        )

        def _get_single(dpo):
            return {
                'cost': D('200'),
                'pricing_object_id': dpo.pricing_object.id,
                'type_id': self.pricing_service1.id,
                '_children': [
                    {
                        'cost': D('100'),
                        'pricing_object_id': dpo.pricing_object.id,
                        'type_id': self.service_usage_types[0].id,
                        'value': 10.0
                    },
                    {
                        'cost': D('100'),
                        'pricing_object_id': dpo.pricing_object.id,
                        'type_id': self.service_usage_types[1].id,
                        'value': 5.0
                    }
                ],
            }
        self.assertNestedDictsEqual(result, {
            self.service_environments[0].id: [
                _get_single(self.se1_dpo[0]),
                _get_single(self.se1_dpo[1]),
            ],
            self.service_environments[1].id: [
                _get_single(self.se2_dpo[0]),
                _get_single(self.se2_dpo[1]),
            ]
        })

    def test_get_total_cost(self):
        result = PricingServiceFixedPricePlugin.total_cost(
            pricing_service=self.pricing_service1,
            date=self.today,
            service_environments=self.service_environments[:2]
        )
        self.assertEqual(result, {
            self.pricing_service1.id: [D('800'), {
                self.service_usage_types[0].id: [D('400'), {}],
                self.service_usage_types[1].id: [D('400'), {}],
            }]
        })

    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_pricing_service_costs')  # noqa
    def test_get_pricing_service_real_costs_diff(
        self,
        pricing_service_costs_mock,
    ):
        ps2 = PricingServiceFactory()
        self.pricing_service1.charge_diff_to_real_costs = ps2
        self.pricing_service1.save()

        pricing_service_costs_mock.return_value = {
            self.pricing_service1.id: (D(100), {
                self.service_usage_types[0].id: (D(50), {}),
                self.service_usage_types[1].id: (D(50), {}),
            })
        }

        result = PricingServicePlugin._get_service_charging_by_diffs(
            ps2,
            date=self.today,
            forecast=False,
        )
        self.assertEqual(result, {
            self.pricing_service1.id: (D(-1100), {})  # 100 - 1200
        })
class TestPricingServiceDiffCharging(TestCase):
    def setUp(self):
        self.today = date(2014, 11, 10)

        self.service_environments = ServiceEnvironmentFactory.create_batch(5)
        self.pricing_service1 = PricingServiceFactory()

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin)
        self.pricing_service2 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service2.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service2.save()

        self.pricing_service3 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service3.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service3.save()

    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost'
    )  # noqa
    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost'
    )  # noqa
    def test_get_service_charging_by_diffs(self, fixed_total_mock, total_mock):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(100)
            else:
                val = D(1000)
            return {pricing_service.id: (val, {})}

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(1000)
            else:
                val = D(100)
            return {pricing_service.id: (val, {})}

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_service_charging_by_diffs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(
            result, {
                self.pricing_service2.id: (-900, {}),
                self.pricing_service3.id: (900, {}),
            })
        calls = [
            mock.call(
                date=self.today,
                pricing_service=x,
                for_all_service_environments=True,
                forecast=False,
            ) for x in (self.pricing_service2, self.pricing_service3)
        ]
        total_mock.assert_has_calls(calls, any_order=True)
        fixed_total_mock.assert_has_calls(calls, any_order=True)

    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost'
    )  # noqa
    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost'
    )  # noqa
    def test_get_service_charging_by_diffs_error(self, fixed_total_mock,
                                                 total_mock):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                return {pricing_service.id: (100, {})}
            raise KeyError()

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                return {pricing_service.id: (100, {})}
            raise AttributeError()

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_service_charging_by_diffs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(result, {
            self.pricing_service2.id: (0, {}),
        })

    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost'
    )  # noqa
    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost'
    )  # noqa
    def test_get_pricing_service_costs(self, fixed_total_mock, total_mock):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(100)
            else:
                val = D(1000)
            return {pricing_service.id: (val, {})}

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(1000)
            else:
                val = D(100)
            return {pricing_service.id: (val, {})}

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_pricing_service_costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(
            result, {
                self.pricing_service1.id: (0, {
                    self.pricing_service2.id: (-900, {}),
                    self.pricing_service3.id: (900, {}),
                })
            })

    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_service_charging_by_diffs'
    )  # noqa
    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_dependent_services_cost'
    )  # noqa
    def test_get_pricing_service_costs_when_diff_key_exist(
            self, dependent_costs_mock, diff_costs_mock):
        self.usage_type1 = UsageTypeFactory()

        def dependent_costs(*args, **kwargs):
            return {
                self.pricing_service2.id: (100, {
                    self.usage_type1.id: (100, {}),
                }),
                self.pricing_service3.id: (300, {
                    self.usage_type1.id: (100, {}),
                }),
            }

        def diff_costs(pricing_service, *args, **kwargs):
            return {
                self.pricing_service2.id: (200, {}),
            }

        dependent_costs_mock.side_effect = dependent_costs
        diff_costs_mock.side_effect = diff_costs
        result = PricingServicePlugin._get_pricing_service_costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(
            result, {
                self.pricing_service1.id: (600, {
                    self.pricing_service2.id: (300, {}),
                    self.pricing_service3.id: (300, {
                        self.usage_type1.id: (100, {}),
                    }),
                })
            })
class TestPricingServicePlugin(TestCase):
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        # TODO: unify with usages generator

        # base usages
        self.base_usage_type = UsageTypeFactory(
            usage_type='BU',
            by_cost=True,
        )

        # regular usage
        self.regular_usage_type = UsageTypeFactory(
            usage_type='RU',
            by_cost=False,
        )

        # team
        self.team = TeamFactory()

        # extra cost
        self.extra_cost_type = ExtraCostTypeFactory()

        # pricing services
        self.pricing_service1 = PricingServiceFactory()
        self.pricing_service1.regular_usage_types.add(self.regular_usage_type)
        self.pricing_service1.save()

        # NOTICE THAT PRICING SERVICE 2 IS NOT CHARGED FOR REGULAR USAGE
        self.pricing_service2 = PricingServiceFactory()

        # services
        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory.create(
            service__pricing_service=self.pricing_service2,
        ))
        self.service_environments.extend(
            ServiceEnvironmentFactory.create_batch(3)
        )

        # pricing service usages
        self.service_usage_types = UsageTypeFactory.create_batch(
            3,
            usage_type='SU',
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.pricing_service2,
            start=self.start,
            end=self.end,
            percent=100,
        )

        # daily pricing objects
        # in pricing service 1 (& use pricing service 2)
        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[0]
        )
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[1]
        )
        # in pricing service 2
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[2]
        )
        # use pricing service 1
        self.se4_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[3]
        )
        self.se5_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[4]
        )
        # use pricing service 2 (besides se1_dpo and se2_dpo)
        self.se6_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[5]
        )
        # other
        self.se7_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[5]
        )

        # SO FAR SUMMARY:
        # there are 2 pricing services:
        # pricing service 1: collect costs from 2 services (4 pricing objects:
        # se1_dpo and se2_dpo); is distributed according to usages of 2 service
        # usage types: sut[0] (30%) and sut[1] (70%)
        # pricing service 2: collect costs from 1 service (2 pricing objects:
        # se3_dpo); is distributed according to usages of 1 service usage type
        # (sut[2] -  100%)
        # there are also another 2 service environments (each has 2 pricing
        # objects)
        # TOTAL DAILY PRICING OBJECTS: 14

        # USAGES
        # base usage type
        models.UsagePrice(
            type=self.base_usage_type,
            # cost per unit: 1, daily cost (usages are the same for each date):
            # 140, cost per daily pricing object: 10
            cost=4200,
            forecast_cost=8400,  # cost per unit: 2
            start=self.start,
            end=self.end,
        ).save()
        # regular usage type
        models.UsagePrice(
            type=self.regular_usage_type,
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            # TODO: fix assigning DPO with wrong date to DailyUsage
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.base_usage_type,
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.regular_usage_type,
                )

        # team
        team_cost = models.TeamCost(
            team=self.team,
            cost=300,  # daily cost: 10
            forecast_cost=600,  # daily cost: 20
            start=self.start,
            end=self.end,
        )
        team_cost.save()
        for se in self.service_environments[:5]:
            models.TeamServiceEnvironmentPercent(
                team_cost=team_cost,
                service_environment=se,
                percent=20,  # 2 per day per se
            ).save()

        # extra cost
        for se in self.service_environments[:5]:
            models.ExtraCost(
                extra_cost_type=self.extra_cost_type,
                start=self.start,
                end=self.end,
                service_environment=se,
                cost=3000,  # daily cost: 100
                forecast_cost=6000,  # daily cost: 200
            ).save()

        # pricing service 1 service usage types usages
        for dpo, multiplier in zip(self.se4_dpo + self.se5_dpo, [1, 1, 3, 3]):
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[0],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10 * multiplier,
                    date=day,
                )
                DailyUsageFactory(
                    type=self.service_usage_types[1],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=50 * multiplier,
                    date=day,
                )

        # pricing service 2 service usage types usages
        for dpo in self.se1_dpo + self.se6_dpo:
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[2],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=100,
                    date=day,
                )

    def test_get_service_base_usage_types_cost(self):
        result = PricingServicePlugin._get_service_base_usage_types_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.base_usage_type.id: (D('40'), {})})

    def test_get_service_regular_usage_types_cost(self):
        result = PricingServicePlugin._get_service_regular_usage_types_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.regular_usage_type.id: (D('200'), {})})

    def test_get_service_teams_cost(self):
        result = PricingServicePlugin._get_service_teams_cost(
            self.today,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.team.id: (D('4'), {})})

    def test_get_service_extra_cost(self):
        result = PricingServicePlugin._get_service_extra_cost(
            self.today,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.extra_cost_type.id: (D('200'), {})})

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=False)
    def test_get_dependent_services_cost(self):
        result = PricingServicePlugin._get_dependent_services_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        # daily pricing objects which are under pricing service 1 (practically
        # under se1) are using extacly half of pricing service resources, so
        # they will be charged with half of total amount
        self.assertEquals(result, {
            self.pricing_service2.id: [
                D('61'),
                {
                    self.base_usage_type.id: [D('10'), {}],
                    self.team.id: [D('1'), {}],
                    self.extra_cost_type.id: [D('50'), {}]
                }
            ]
        })

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=True)
    def test_get_dependent_services_cost_only_first_depth(self):
        result = PricingServicePlugin._get_dependent_services_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {
            self.pricing_service2.id: [D('61'), {}]
        })

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=False)
    def test_get_pricing_service_costs(self):
        costs = PricingServicePlugin._get_pricing_service_costs(
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
        )
        self.assertEquals(costs, {
            self.pricing_service1.id: (
                D('505'),
                {
                    self.base_usage_type.id: (D('40'), {}),
                    self.regular_usage_type.id: (D('200'), {}),
                    self.team.id: (D('4'), {}),
                    self.extra_cost_type.id: (D('200'), {}),
                    self.pricing_service2.id: [
                        D('61'),
                        {
                            self.base_usage_type.id: [D('10'), {}],
                            self.team.id: [D('1'), {}],
                            self.extra_cost_type.id: [D('50'), {}]
                        }
                    ]
                }
            )
        })

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=True)
    def test_get_pricing_service_costs_only_first_depth(self):
        costs = PricingServicePlugin._get_pricing_service_costs(
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
        )
        self.assertEquals(costs, {
            self.pricing_service1.id: (
                D('505'),
                {
                    self.base_usage_type.id: (D('40'), {}),
                    self.regular_usage_type.id: (D('200'), {}),
                    self.team.id: (D('4'), {}),
                    self.extra_cost_type.id: (D('200'), {}),
                    self.pricing_service2.id: [D('61'), {}]
                }
            )
        })

    def test_get_pricing_service_costs2(self):
        # there are 4 daily pricing objects that are using pricing service 2:
        # 2 are in se1, 2 are in se6
        # total cost of pricing service 1 (which has 2 daily pricing objects)
        # for one day (today) is 122:
        #   base usage: 2 (dpo) * 10 (usage value) * 1 (cost per unit) = 20
        #   team: 10 (daily cost) * 0.2 (percent) = 2
        #   extra cost: 100 (daily cost)
        costs = PricingServicePlugin._get_pricing_service_costs(
            self.today,
            self.pricing_service2,
            forecast=False,
        )
        self.assertEquals(costs, {
            self.pricing_service2.id: (D('122'), {
                self.base_usage_type.id: (D('20'), {}),
                self.team.id: (D('2'), {}),
                self.extra_cost_type.id: (D('100'), {}),
            }),
        })

    def test_get_total_costs_from_costs(self):
        result = PricingServicePlugin._get_total_costs_from_costs(
            PRICING_SERVICE_COSTS
        )
        self.assertEquals(result, {
            1: [
                D(5100),
                {
                    2: [D(1800), {}],
                    3: [D(1600), {}],
                    4: [D(900), {}],
                    5: [D(800), {}],
                }
            ],
            6: [
                D(300),
                {
                    2: [D(100), {}],
                    3: [D(200), {}],
                }
            ]
        })

    # TODO: add tests for _distribute_costs

    def test_costs(self):
        costs = PricingServicePlugin(
            type='costs',
            date=self.today,
            pricing_service=self.pricing_service1,
            service_environments=self.service_environments,
            forecast=True,
        )
        po1 = self.se4_dpo[0].pricing_object.id
        po2 = self.se4_dpo[1].pricing_object.id
        po3 = self.se5_dpo[0].pricing_object.id
        po4 = self.se5_dpo[1].pricing_object.id
        result = {
            self.service_environments[3].id: [
                {
                    'cost': D('126.25'),
                    'pricing_object_id': po2,
                    'type_id': self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('10'),
                            'pricing_object_id': po2,
                            'type_id': self.base_usage_type.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po2,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('1'),
                            'pricing_object_id': po2,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po2,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost': D('15.25'),
                            'pricing_object_id': po2,
                            'type_id': self.pricing_service2.id,
                            '_children': [
                                {
                                    'cost': D('2.5'),
                                    'pricing_object_id': po2,
                                    'type_id': self.base_usage_type.id,
                                },
                                {
                                    'cost': D('0.25'),
                                    'pricing_object_id': po2,
                                    'type_id': self.team.id,
                                },
                                {
                                    'cost': D('12.5'),
                                    'pricing_object_id': po2,
                                    'type_id': self.extra_cost_type.id,
                                }
                            ],
                        },
                    ],
                },
                {
                    'cost': D('126.25'),
                    'pricing_object_id': po1,
                    'type_id': self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('10'),
                            'pricing_object_id': po1,
                            'type_id': self.base_usage_type.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po1,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('1'),
                            'pricing_object_id': po1,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po1,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost': D('15.25'),
                            'pricing_object_id': po1,
                            'type_id': self.pricing_service2.id,
                            '_children': [
                                {
                                    'cost': D('2.5'),
                                    'pricing_object_id': po1,
                                    'type_id': self.base_usage_type.id,
                                },
                                {
                                    'cost': D('0.25'),
                                    'pricing_object_id': po1,
                                    'type_id': self.team.id,
                                },
                                {
                                    'cost': D('12.5'),
                                    'pricing_object_id': po1,
                                    'type_id': self.extra_cost_type.id,
                                }
                            ],
                        },
                    ],
                },
            ],
            self.service_environments[4].id: [
                {
                    'cost': D('378.75'),
                    'pricing_object_id': po4,
                    'type_id': self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('30'),
                            'pricing_object_id': po4,
                            'type_id': self.base_usage_type.id
                        },
                        {
                            'cost': D('150'),
                            'pricing_object_id': po4,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('3'),
                            'pricing_object_id': po4,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('150'),
                            'pricing_object_id': po4,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost': D('45.75'),
                            'pricing_object_id': po4,
                            'type_id': self.pricing_service2.id,
                            '_children': [
                                {
                                    'cost': D('7.5'),
                                    'pricing_object_id': po4,
                                    'type_id': self.base_usage_type.id,
                                },
                                {
                                    'cost': D('0.75'),
                                    'pricing_object_id': po4,
                                    'type_id': self.team.id,
                                },
                                {
                                    'cost': D('37.5'),
                                    'pricing_object_id': po4,
                                    'type_id': self.extra_cost_type.id,
                                }
                            ],
                        }
                    ]
                },
                {
                    'cost': D('378.75'),
                    'pricing_object_id': po3,
                    'type_id': self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('30'),
                            'pricing_object_id': po3,
                            'type_id': self.base_usage_type.id
                        },
                        {
                            'cost': D('150'),
                            'pricing_object_id': po3,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('3'),
                            'pricing_object_id': po3,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('150'),
                            'pricing_object_id': po3,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost': D('45.75'),
                            'pricing_object_id': po3,
                            'type_id': self.pricing_service2.id,
                            '_children': [
                                {
                                    'cost': D('7.5'),
                                    'pricing_object_id': po3,
                                    'type_id': self.base_usage_type.id,
                                },
                                {
                                    'cost': D('0.75'),
                                    'pricing_object_id': po3,
                                    'type_id': self.team.id,
                                },
                                {
                                    'cost': D('37.5'),
                                    'pricing_object_id': po3,
                                    'type_id': self.extra_cost_type.id,
                                }
                            ],
                        }
                    ]
                },
            ]
        }

        self.assertItemsEqual(costs, result)

    def test_total_costs(self):
        costs = PricingServicePlugin(
            type='total_cost',
            date=self.today,
            pricing_service=self.pricing_service1,
            service_environments=self.service_environments,
            forecast=True,
        )
        self.assertItemsEqual(
            costs,
            {self.pricing_service1.id: (D('1010'), {})}
        )

    def test_total_costs_for_all_service_environments(self):
        costs = PricingServicePlugin(
            type='total_cost',
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=True,
            for_all_service_environments=True,
        )
        self.assertItemsEqual(costs, {
            self.pricing_service1.id: [
                D('1010'), {
                    self.pricing_service2.id: [
                        D('122'),
                        {
                            self.base_usage_type.id: [D('20'), {}],
                            self.team.id: [D('2'), {}],
                            self.extra_cost_type.id: [D('100'), {}]
                        }
                    ],
                    self.base_usage_type.id: [D('80'), {}],
                    self.regular_usage_type.id: [D('400'), {}],
                    self.team.id: [D('8'), {}],
                    self.extra_cost_type.id: [D('400'), {}]
                }
            ]
        })
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        # TODO: unify with usages generator

        # base usages
        self.base_usage_type = UsageTypeFactory(
            usage_type='BU',
            by_cost=True,
        )

        # regular usage
        self.regular_usage_type = UsageTypeFactory(
            usage_type='RU',
            by_cost=False,
        )

        # team
        self.team = TeamFactory()

        # extra cost
        self.extra_cost_type = ExtraCostTypeFactory()

        # pricing services
        self.pricing_service1 = PricingServiceFactory()
        self.pricing_service1.regular_usage_types.add(self.regular_usage_type)
        self.pricing_service1.save()

        # NOTICE THAT PRICING SERVICE 2 IS NOT CHARGED FOR REGULAR USAGE
        self.pricing_service2 = PricingServiceFactory()

        # services
        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory.create(
            service__pricing_service=self.pricing_service2,
        ))
        self.service_environments.extend(
            ServiceEnvironmentFactory.create_batch(3)
        )

        # pricing service usages
        self.service_usage_types = UsageTypeFactory.create_batch(
            3,
            usage_type='SU',
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.pricing_service2,
            start=self.start,
            end=self.end,
            percent=100,
        )

        # daily pricing objects
        # in pricing service 1 (& use pricing service 2)
        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[0]
        )
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[1]
        )
        # in pricing service 2
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[2]
        )
        # use pricing service 1
        self.se4_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[3]
        )
        self.se5_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[4]
        )
        # use pricing service 2 (besides se1_dpo and se2_dpo)
        self.se6_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[5]
        )
        # other
        self.se7_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[5]
        )

        # SO FAR SUMMARY:
        # there are 2 pricing services:
        # pricing service 1: collect costs from 2 services (4 pricing objects:
        # se1_dpo and se2_dpo); is distributed according to usages of 2 service
        # usage types: sut[0] (30%) and sut[1] (70%)
        # pricing service 2: collect costs from 1 service (2 pricing objects:
        # se3_dpo); is distributed according to usages of 1 service usage type
        # (sut[2] -  100%)
        # there are also another 2 service environments (each has 2 pricing
        # objects)
        # TOTAL DAILY PRICING OBJECTS: 14

        # USAGES
        # base usage type
        models.UsagePrice(
            type=self.base_usage_type,
            # cost per unit: 1, daily cost (usages are the same for each date):
            # 140, cost per daily pricing object: 10
            cost=4200,
            forecast_cost=8400,  # cost per unit: 2
            start=self.start,
            end=self.end,
        ).save()
        # regular usage type
        models.UsagePrice(
            type=self.regular_usage_type,
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            # TODO: fix assigning DPO with wrong date to DailyUsage
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.base_usage_type,
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.regular_usage_type,
                )

        # team
        team_cost = models.TeamCost(
            team=self.team,
            cost=300,  # daily cost: 10
            forecast_cost=600,  # daily cost: 20
            start=self.start,
            end=self.end,
        )
        team_cost.save()
        for se in self.service_environments[:5]:
            models.TeamServiceEnvironmentPercent(
                team_cost=team_cost,
                service_environment=se,
                percent=20,  # 2 per day per se
            ).save()

        # extra cost
        for se in self.service_environments[:5]:
            models.ExtraCost(
                extra_cost_type=self.extra_cost_type,
                start=self.start,
                end=self.end,
                service_environment=se,
                cost=3000,  # daily cost: 100
                forecast_cost=6000,  # daily cost: 200
            ).save()

        # pricing service 1 service usage types usages
        for dpo, multiplier in zip(self.se4_dpo + self.se5_dpo, [1, 1, 3, 3]):
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[0],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10 * multiplier,
                    date=day,
                )
                DailyUsageFactory(
                    type=self.service_usage_types[1],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=50 * multiplier,
                    date=day,
                )

        # pricing service 2 service usage types usages
        for dpo in self.se1_dpo + self.se6_dpo:
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[2],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=100,
                    date=day,
                )
class TestPricingServiceDependency(TestCase):
    """
    Specific test cases to test pricing services dependency
    """
    def setUp(self):
        self.start = date(2014, 10, 1)
        self.end = date(2014, 10, 31)
        self.today = date(2014, 10, 12)

    def _init(self):
        self.ps1, self.ps2, self.ps3 = PricingServiceFactory.create_batch(3)
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps2,
        )
        self.se5 = ServiceEnvironmentFactory(service__pricing_service=self.ps3)
        self.other_se = ServiceEnvironmentFactory.create_batch(5)

        self.service_usage_types = UsageTypeFactory.create_batch(
            4,
            usage_type='SU',
        )

        self.ps1.excluded_services.add(self.other_se[0].service)
        self.ps1.save()

        self.ps2.excluded_services.add(self.other_se[1].service)
        self.ps2.save()

        self.service_usage_types[0].excluded_services.add(
            self.other_se[2].service)
        self.service_usage_types[0].save()

        self.service_usage_types[3].excluded_services.add(
            self.other_se[4].service)
        self.service_usage_types[3].save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[3],
            pricing_service=self.ps3,
            start=self.start,
            end=self.end,
            percent=100,
        )

    def _init_one(self):
        """
        Creates pricing service with 2 service usages.
        Pricing service has se4 in excluded services, its usage type has se3 in
        excluded services.

        There are 3 daily pricing objects - one of them belongs to se1 (and
        should not be considered to calculate usages).
        """
        self.ps1 = PricingServiceFactory()
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(2)

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.service_usage_types[0].excluded_services.add(self.se3.service)
        self.service_usage_types[0].save()

        self.ps1.excluded_services.add(self.se4.service)
        self.ps1.save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=30,
        )

        self.dpo1 = DailyPricingObjectFactory()
        self.dpo2 = DailyPricingObjectFactory()
        self.dpo3 = DailyPricingObjectFactory(service_environment=self.se1)

        for dpo in models.DailyPricingObject.objects.all():
            for su, value in zip(self.service_usage_types, [10, 20]):
                models.DailyUsage.objects.create(
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    date=self.today,
                    value=value,
                    type=su,
                )

    def test_distribute_costs_with_excluded_services(self):
        self._init_one()
        usage_orig = PricingServicePlugin._get_usages_per_pricing_object
        total_orig = PricingServicePlugin._get_total_usage
        with mock.patch(
                'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_usages_per_pricing_object'
        ) as usage_mock:  # noqa
            with mock.patch(
                    'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_total_usage'
            ) as total_mock:  # noqa
                usage_mock.side_effect = usage_orig
                total_mock.side_effect = total_orig
                PricingServicePlugin._distribute_costs(
                    self.today,
                    pricing_service=self.ps1,
                    costs_hierarchy={},
                    service_usage_types=self.ps1.serviceusagetypes_set.all(),
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ]))

                total_mock.assert_any_call(
                    usage_type=self.service_usage_types[0],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                        self.se3.service,
                    ]))
                total_mock.assert_any_call(
                    usage_type=self.service_usage_types[1],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ]))
                usage_mock.assert_any_call(
                    usage_type=self.service_usage_types[0],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                        self.se3.service,
                    ]),
                )
                usage_mock.assert_any_call(
                    usage_type=self.service_usage_types[1],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ]),
                )

    def test_pricing_dependent_services(self):
        """
        Call costs for PS1, which dependent on PS2, which dependent of PS3.
        Check if all dependencies (and )
        """
        self._init()

        def dependent_services(self1, date, exclude=None):
            if self1 == self.ps1:
                return [self.ps2]
            elif self1 == self.ps2:
                return [self.ps3]
            return []

        # get_dependent_services_mock.side_effect = dependent_services
        with mock.patch.object(models.service.PricingService,
                               'get_dependent_services',
                               dependent_services):  # noqa
            distribute_costs_orig = PricingServicePlugin._distribute_costs
            with mock.patch(
                    'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._distribute_costs'
            ) as distribute_costs_mock:  # noqa
                distribute_costs_mock.side_effect = distribute_costs_orig
                PricingServicePlugin.costs(
                    pricing_service=self.ps1,
                    date=self.today,
                    service_environments=models.ServiceEnvironment.objects.all(
                    ),  # noqa
                    forecast=False,
                    pricing_services_calculated=None,
                )
                calls = [
                    mock.call(
                        self.today,  # date
                        self.ps3,  # pricing service
                        {self.ps3.id: (0, {})},  # costs - not important here
                        self.ps3.serviceusagetypes_set.all(),  # percentage
                        excluded_services=set([
                            # from ps3
                            self.se5.service,
                        ])),
                    mock.call(
                        self.today,
                        self.ps2,
                        {self.ps2.id: (0, {})},
                        self.ps2.serviceusagetypes_set.all(),
                        excluded_services=set([
                            # from ps2
                            self.other_se[1].service,
                            self.se3.service,
                            self.se4.service,
                        ])),
                    mock.call(
                        self.today,
                        self.ps1,
                        {self.ps1.id: (0, {})},
                        self.ps1.serviceusagetypes_set.all(),
                        excluded_services=set([
                            # from ps1
                            self.other_se[0].service,
                            self.se1.service,
                            self.se2.service,
                        ])),
                ]

                self.assertEquals(len(calls),
                                  len(distribute_costs_mock.call_args_list))
                # comparing strings, because of django query sets in params
                for expected_call, actual_call in zip(
                        calls, distribute_costs_mock.call_args_list):
                    self.assertEquals(str(expected_call), str(actual_call))
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        # TODO: unify with usages generator

        # base usages
        self.base_usage_type = UsageTypeFactory(
            usage_type='BU',
            by_cost=True,
        )

        # regular usage
        self.regular_usage_type = UsageTypeFactory(
            usage_type='RU',
            by_cost=False,
        )

        # team
        self.team = TeamFactory()

        # extra cost
        self.extra_cost_type = ExtraCostTypeFactory()

        # pricing services
        self.pricing_service1 = PricingServiceFactory()
        self.pricing_service1.regular_usage_types.add(self.regular_usage_type)
        self.pricing_service1.save()

        # NOTICE THAT PRICING SERVICE 2 IS NOT CHARGED FOR REGULAR USAGE
        self.pricing_service2 = PricingServiceFactory()

        # services
        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(
            ServiceEnvironmentFactory.create(
                service__pricing_service=self.pricing_service2, ))
        self.service_environments.extend(
            ServiceEnvironmentFactory.create_batch(3))

        # pricing service usages
        self.service_usage_types = UsageTypeFactory.create_batch(
            3,
            usage_type='SU',
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.pricing_service2,
            start=self.start,
            end=self.end,
            percent=100,
        )

        # daily pricing objects
        # in pricing service 1 (& use pricing service 2)
        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[0])
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[1])
        # in pricing service 2
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[2])
        # use pricing service 1
        self.se4_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[3])
        self.se5_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[4])
        # use pricing service 2 (besides se1_dpo and se2_dpo)
        self.se6_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[5])
        # other
        self.se7_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[5])

        # SO FAR SUMMARY:
        # there are 2 pricing services:
        # pricing service 1: collect costs from 2 services (4 pricing objects:
        # se1_dpo and se2_dpo); is distributed according to usages of 2 service
        # usage types: sut[0] (30%) and sut[1] (70%)
        # pricing service 2: collect costs from 1 service (2 pricing objects:
        # se3_dpo); is distributed according to usages of 1 service usage type
        # (sut[2] -  100%)
        # there are also another 2 service environments (each has 2 pricing
        # objects)
        # TOTAL DAILY PRICING OBJECTS: 14

        # USAGES
        # base usage type
        models.UsagePrice(
            type=self.base_usage_type,
            # cost per unit: 1, daily cost (usages are the same for each date):
            # 140, cost per daily pricing object: 10
            cost=4200,
            forecast_cost=8400,  # cost per unit: 2
            start=self.start,
            end=self.end,
        ).save()
        # regular usage type
        models.UsagePrice(
            type=self.regular_usage_type,
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            # TODO: fix assigning DPO with wrong date to DailyUsage
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.base_usage_type,
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.regular_usage_type,
                )

        # team
        team_cost = models.TeamCost(
            team=self.team,
            cost=300,  # daily cost: 10
            forecast_cost=600,  # daily cost: 20
            start=self.start,
            end=self.end,
        )
        team_cost.save()
        for se in self.service_environments[:5]:
            models.TeamServiceEnvironmentPercent(
                team_cost=team_cost,
                service_environment=se,
                percent=20,  # 2 per day per se
            ).save()

        # extra cost
        for se in self.service_environments[:5]:
            models.ExtraCost(
                extra_cost_type=self.extra_cost_type,
                start=self.start,
                end=self.end,
                service_environment=se,
                cost=3000,  # daily cost: 100
                forecast_cost=6000,  # daily cost: 200
            ).save()

        # pricing service 1 service usage types usages
        for dpo, multiplier in zip(self.se4_dpo + self.se5_dpo, [1, 1, 3, 3]):
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[0],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10 * multiplier,
                    date=day,
                )
                DailyUsageFactory(
                    type=self.service_usage_types[1],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=50 * multiplier,
                    date=day,
                )

        # pricing service 2 service usage types usages
        for dpo in self.se1_dpo + self.se6_dpo:
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[2],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=100,
                    date=day,
                )
class TestPricingServicePlugin(TestCase):
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        # TODO: unify with usages generator

        # base usages
        self.base_usage_type = UsageTypeFactory(
            usage_type='BU',
            by_cost=True,
        )

        # regular usage
        self.regular_usage_type = UsageTypeFactory(
            usage_type='RU',
            by_cost=False,
        )

        # team
        self.team = TeamFactory()

        # extra cost
        self.extra_cost_type = ExtraCostTypeFactory()

        # pricing services
        self.pricing_service1 = PricingServiceFactory()
        self.pricing_service1.regular_usage_types.add(self.regular_usage_type)
        self.pricing_service1.save()

        # NOTICE THAT PRICING SERVICE 2 IS NOT CHARGED FOR REGULAR USAGE
        self.pricing_service2 = PricingServiceFactory()

        # services
        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(
            ServiceEnvironmentFactory.create(
                service__pricing_service=self.pricing_service2, ))
        self.service_environments.extend(
            ServiceEnvironmentFactory.create_batch(3))

        # pricing service usages
        self.service_usage_types = UsageTypeFactory.create_batch(
            3,
            usage_type='SU',
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.pricing_service2,
            start=self.start,
            end=self.end,
            percent=100,
        )

        # daily pricing objects
        # in pricing service 1 (& use pricing service 2)
        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[0])
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[1])
        # in pricing service 2
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[2])
        # use pricing service 1
        self.se4_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[3])
        self.se5_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[4])
        # use pricing service 2 (besides se1_dpo and se2_dpo)
        self.se6_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[5])
        # other
        self.se7_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[5])

        # SO FAR SUMMARY:
        # there are 2 pricing services:
        # pricing service 1: collect costs from 2 services (4 pricing objects:
        # se1_dpo and se2_dpo); is distributed according to usages of 2 service
        # usage types: sut[0] (30%) and sut[1] (70%)
        # pricing service 2: collect costs from 1 service (2 pricing objects:
        # se3_dpo); is distributed according to usages of 1 service usage type
        # (sut[2] -  100%)
        # there are also another 2 service environments (each has 2 pricing
        # objects)
        # TOTAL DAILY PRICING OBJECTS: 14

        # USAGES
        # base usage type
        models.UsagePrice(
            type=self.base_usage_type,
            # cost per unit: 1, daily cost (usages are the same for each date):
            # 140, cost per daily pricing object: 10
            cost=4200,
            forecast_cost=8400,  # cost per unit: 2
            start=self.start,
            end=self.end,
        ).save()
        # regular usage type
        models.UsagePrice(
            type=self.regular_usage_type,
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            # TODO: fix assigning DPO with wrong date to DailyUsage
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.base_usage_type,
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.regular_usage_type,
                )

        # team
        team_cost = models.TeamCost(
            team=self.team,
            cost=300,  # daily cost: 10
            forecast_cost=600,  # daily cost: 20
            start=self.start,
            end=self.end,
        )
        team_cost.save()
        for se in self.service_environments[:5]:
            models.TeamServiceEnvironmentPercent(
                team_cost=team_cost,
                service_environment=se,
                percent=20,  # 2 per day per se
            ).save()

        # extra cost
        for se in self.service_environments[:5]:
            models.ExtraCost(
                extra_cost_type=self.extra_cost_type,
                start=self.start,
                end=self.end,
                service_environment=se,
                cost=3000,  # daily cost: 100
                forecast_cost=6000,  # daily cost: 200
            ).save()

        # pricing service 1 service usage types usages
        for dpo, multiplier in zip(self.se4_dpo + self.se5_dpo, [1, 1, 3, 3]):
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[0],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10 * multiplier,
                    date=day,
                )
                DailyUsageFactory(
                    type=self.service_usage_types[1],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=50 * multiplier,
                    date=day,
                )

        # pricing service 2 service usage types usages
        for dpo in self.se1_dpo + self.se6_dpo:
            days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
            for day in days:
                DailyUsageFactory(
                    type=self.service_usage_types[2],
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=100,
                    date=day,
                )

    def test_get_service_base_usage_types_cost(self):
        result = PricingServicePlugin._get_service_base_usage_types_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.base_usage_type.id: (D('40'), {})})

    def test_get_service_regular_usage_types_cost(self):
        result = PricingServicePlugin._get_service_regular_usage_types_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.regular_usage_type.id: (D('200'), {})})

    def test_get_service_teams_cost(self):
        result = PricingServicePlugin._get_service_teams_cost(
            self.today,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.team.id: (D('4'), {})})

    def test_get_service_extra_cost(self):
        result = PricingServicePlugin._get_service_extra_cost(
            self.today,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.extra_cost_type.id: (D('200'), {})})

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=False)
    def test_get_dependent_services_cost(self):
        result = PricingServicePlugin._get_dependent_services_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        # daily pricing objects which are under pricing service 1 (practically
        # under se1) are using extacly half of pricing service resources, so
        # they will be charged with half of total amount
        self.assertEquals(
            result, {
                self.pricing_service2.id: [
                    D('61'), {
                        self.base_usage_type.id: [D('10'), {}],
                        self.team.id: [D('1'), {}],
                        self.extra_cost_type.id: [D('50'), {}]
                    }
                ]
            })

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=True)
    def test_get_dependent_services_cost_only_first_depth(self):
        result = PricingServicePlugin._get_dependent_services_cost(
            self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
            service_environments=self.pricing_service1.service_environments,
        )
        self.assertEquals(result, {self.pricing_service2.id: [D('61'), {}]})

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=False)
    def test_get_pricing_service_costs(self):
        costs = PricingServicePlugin._get_pricing_service_costs(
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
        )
        self.assertEquals(
            costs, {
                self.pricing_service1.id: (D('505'), {
                    self.base_usage_type.id: (D('40'), {}),
                    self.regular_usage_type.id: (D('200'), {}),
                    self.team.id: (D('4'), {}),
                    self.extra_cost_type.id: (D('200'), {}),
                    self.pricing_service2.id: [
                        D('61'), {
                            self.base_usage_type.id: [D('10'), {}],
                            self.team.id: [D('1'), {}],
                            self.extra_cost_type.id: [D('50'), {}]
                        }
                    ]
                })
            })

    @override_settings(SAVE_ONLY_FIRST_DEPTH_COSTS=True)
    def test_get_pricing_service_costs_only_first_depth(self):
        costs = PricingServicePlugin._get_pricing_service_costs(
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=False,
        )
        self.assertEquals(
            costs, {
                self.pricing_service1.id: (D('505'), {
                    self.base_usage_type.id: (D('40'), {}),
                    self.regular_usage_type.id: (D('200'), {}),
                    self.team.id: (D('4'), {}),
                    self.extra_cost_type.id: (D('200'), {}),
                    self.pricing_service2.id: [D('61'), {}]
                })
            })

    def test_get_pricing_service_costs2(self):
        # there are 4 daily pricing objects that are using pricing service 2:
        # 2 are in se1, 2 are in se6
        # total cost of pricing service 1 (which has 2 daily pricing objects)
        # for one day (today) is 122:
        #   base usage: 2 (dpo) * 10 (usage value) * 1 (cost per unit) = 20
        #   team: 10 (daily cost) * 0.2 (percent) = 2
        #   extra cost: 100 (daily cost)
        costs = PricingServicePlugin._get_pricing_service_costs(
            self.today,
            self.pricing_service2,
            forecast=False,
        )
        self.assertEquals(
            costs, {
                self.pricing_service2.id: (D('122'), {
                    self.base_usage_type.id: (D('20'), {}),
                    self.team.id: (D('2'), {}),
                    self.extra_cost_type.id: (D('100'), {}),
                }),
            })

    def test_get_total_costs_from_costs(self):
        result = PricingServicePlugin._get_total_costs_from_costs(
            PRICING_SERVICE_COSTS)
        self.assertEquals(
            result, {
                1: [
                    D(5100), {
                        2: [D(1800), {}],
                        3: [D(1600), {}],
                        4: [D(900), {}],
                        5: [D(800), {}],
                    }
                ],
                6: [D(300), {
                    2: [D(100), {}],
                    3: [D(200), {}],
                }]
            })

    # TODO: add tests for _distribute_costs

    def test_costs(self):
        costs = PricingServicePlugin(
            type='costs',
            date=self.today,
            pricing_service=self.pricing_service1,
            service_environments=self.service_environments,
            forecast=True,
        )
        po1 = self.se4_dpo[0].pricing_object.id
        po2 = self.se4_dpo[1].pricing_object.id
        po3 = self.se5_dpo[0].pricing_object.id
        po4 = self.se5_dpo[1].pricing_object.id
        result = {
            self.service_environments[3].id: [
                {
                    'cost':
                    D('126.25'),
                    'pricing_object_id':
                    po2,
                    'type_id':
                    self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('10'),
                            'pricing_object_id': po2,
                            'type_id': self.base_usage_type.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po2,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('1'),
                            'pricing_object_id': po2,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po2,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost':
                            D('15.25'),
                            'pricing_object_id':
                            po2,
                            'type_id':
                            self.pricing_service2.id,
                            '_children': [{
                                'cost': D('2.5'),
                                'pricing_object_id': po2,
                                'type_id': self.base_usage_type.id,
                            }, {
                                'cost': D('0.25'),
                                'pricing_object_id': po2,
                                'type_id': self.team.id,
                            }, {
                                'cost': D('12.5'),
                                'pricing_object_id': po2,
                                'type_id': self.extra_cost_type.id,
                            }],
                        },
                    ],
                },
                {
                    'cost':
                    D('126.25'),
                    'pricing_object_id':
                    po1,
                    'type_id':
                    self.pricing_service1.id,
                    '_children': [
                        {
                            'cost': D('10'),
                            'pricing_object_id': po1,
                            'type_id': self.base_usage_type.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po1,
                            'type_id': self.regular_usage_type.id,
                        },
                        {
                            'cost': D('1'),
                            'pricing_object_id': po1,
                            'type_id': self.team.id,
                        },
                        {
                            'cost': D('50'),
                            'pricing_object_id': po1,
                            'type_id': self.extra_cost_type.id,
                        },
                        {
                            'cost':
                            D('15.25'),
                            'pricing_object_id':
                            po1,
                            'type_id':
                            self.pricing_service2.id,
                            '_children': [{
                                'cost': D('2.5'),
                                'pricing_object_id': po1,
                                'type_id': self.base_usage_type.id,
                            }, {
                                'cost': D('0.25'),
                                'pricing_object_id': po1,
                                'type_id': self.team.id,
                            }, {
                                'cost': D('12.5'),
                                'pricing_object_id': po1,
                                'type_id': self.extra_cost_type.id,
                            }],
                        },
                    ],
                },
            ],
            self.service_environments[4].id: [
                {
                    'cost':
                    D('378.75'),
                    'pricing_object_id':
                    po4,
                    'type_id':
                    self.pricing_service1.id,
                    '_children': [{
                        'cost': D('30'),
                        'pricing_object_id': po4,
                        'type_id': self.base_usage_type.id
                    }, {
                        'cost': D('150'),
                        'pricing_object_id': po4,
                        'type_id': self.regular_usage_type.id,
                    }, {
                        'cost': D('3'),
                        'pricing_object_id': po4,
                        'type_id': self.team.id,
                    }, {
                        'cost': D('150'),
                        'pricing_object_id': po4,
                        'type_id': self.extra_cost_type.id,
                    }, {
                        'cost':
                        D('45.75'),
                        'pricing_object_id':
                        po4,
                        'type_id':
                        self.pricing_service2.id,
                        '_children': [{
                            'cost': D('7.5'),
                            'pricing_object_id': po4,
                            'type_id': self.base_usage_type.id,
                        }, {
                            'cost': D('0.75'),
                            'pricing_object_id': po4,
                            'type_id': self.team.id,
                        }, {
                            'cost': D('37.5'),
                            'pricing_object_id': po4,
                            'type_id': self.extra_cost_type.id,
                        }],
                    }]
                },
                {
                    'cost':
                    D('378.75'),
                    'pricing_object_id':
                    po3,
                    'type_id':
                    self.pricing_service1.id,
                    '_children': [{
                        'cost': D('30'),
                        'pricing_object_id': po3,
                        'type_id': self.base_usage_type.id
                    }, {
                        'cost': D('150'),
                        'pricing_object_id': po3,
                        'type_id': self.regular_usage_type.id,
                    }, {
                        'cost': D('3'),
                        'pricing_object_id': po3,
                        'type_id': self.team.id,
                    }, {
                        'cost': D('150'),
                        'pricing_object_id': po3,
                        'type_id': self.extra_cost_type.id,
                    }, {
                        'cost':
                        D('45.75'),
                        'pricing_object_id':
                        po3,
                        'type_id':
                        self.pricing_service2.id,
                        '_children': [{
                            'cost': D('7.5'),
                            'pricing_object_id': po3,
                            'type_id': self.base_usage_type.id,
                        }, {
                            'cost': D('0.75'),
                            'pricing_object_id': po3,
                            'type_id': self.team.id,
                        }, {
                            'cost': D('37.5'),
                            'pricing_object_id': po3,
                            'type_id': self.extra_cost_type.id,
                        }],
                    }]
                },
            ]
        }

        self.assertItemsEqual(costs, result)

    def test_total_costs(self):
        costs = PricingServicePlugin(
            type='total_cost',
            date=self.today,
            pricing_service=self.pricing_service1,
            service_environments=self.service_environments,
            forecast=True,
        )
        self.assertItemsEqual(costs,
                              {self.pricing_service1.id: (D('1010'), {})})

    def test_total_costs_for_all_service_environments(self):
        costs = PricingServicePlugin(
            type='total_cost',
            date=self.today,
            pricing_service=self.pricing_service1,
            forecast=True,
            for_all_service_environments=True,
        )
        self.assertItemsEqual(
            costs, {
                self.pricing_service1.id: [
                    D('1010'), {
                        self.pricing_service2.id: [
                            D('122'), {
                                self.base_usage_type.id: [D('20'), {}],
                                self.team.id: [D('2'), {}],
                                self.extra_cost_type.id: [D('100'), {}]
                            }
                        ],
                        self.base_usage_type.id: [D('80'), {}],
                        self.regular_usage_type.id: [D('400'), {}],
                        self.team.id: [D('8'), {}],
                        self.extra_cost_type.id: [D('400'), {}]
                    }
                ]
            })
class TestPricingServiceDependency(TestCase):
    """
    Specific test cases to test pricing services dependency
    """
    def setUp(self):
        self.start = date(2014, 10, 1)
        self.end = date(2014, 10, 31)
        self.today = date(2014, 10, 12)

    def _init(self):
        self.ps1, self.ps2, self.ps3 = PricingServiceFactory.create_batch(3)
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps2,
        )
        self.se5 = ServiceEnvironmentFactory(
            service__pricing_service=self.ps3
        )
        self.other_se = ServiceEnvironmentFactory.create_batch(5)

        self.service_usage_types = UsageTypeFactory.create_batch(
            4,
            usage_type='SU',
        )

        self.ps1.excluded_services.add(self.other_se[0].service)
        self.ps1.save()

        self.ps2.excluded_services.add(self.other_se[1].service)
        self.ps2.save()

        self.service_usage_types[0].excluded_services.add(
            self.other_se[2].service
        )
        self.service_usage_types[0].save()

        self.service_usage_types[3].excluded_services.add(
            self.other_se[4].service
        )
        self.service_usage_types[3].save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[3],
            pricing_service=self.ps3,
            start=self.start,
            end=self.end,
            percent=100,
        )

    def _init_one(self):
        """
        Creates pricing service with 2 service usages.
        Pricing service has se4 in excluded services, its usage type has se3 in
        excluded services.

        There are 3 daily pricing objects - one of them belongs to se1 (and
        should not be considered to calculate usages).
        """
        self.ps1 = PricingServiceFactory()
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(2)

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.service_usage_types[0].excluded_services.add(self.se3.service)
        self.service_usage_types[0].save()

        self.ps1.excluded_services.add(self.se4.service)
        self.ps1.save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=30,
        )

        self.dpo1 = DailyPricingObjectFactory()
        self.dpo2 = DailyPricingObjectFactory()
        self.dpo3 = DailyPricingObjectFactory(
            service_environment=self.se1
        )

        for dpo in models.DailyPricingObject.objects.all():
            for su, value in zip(self.service_usage_types, [10, 20]):
                models.DailyUsage.objects.create(
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    date=self.today,
                    value=value,
                    type=su,
                )

    def test_distribute_costs_with_excluded_services(self):
        self._init_one()
        usage_orig = PricingServicePlugin._get_usages_per_pricing_object
        total_orig = PricingServicePlugin._get_total_usage
        with mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_usages_per_pricing_object') as usage_mock:  # noqa
            with mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_total_usage') as total_mock:  # noqa
                usage_mock.side_effect = usage_orig
                total_mock.side_effect = total_orig
                PricingServicePlugin._distribute_costs(
                    self.today,
                    pricing_service=self.ps1,
                    costs_hierarchy={},
                    service_usage_types=self.ps1.serviceusagetypes_set.all(),
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ])
                )

                total_mock.assert_any_call(
                    usage_type=self.service_usage_types[0],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                        self.se3.service,
                    ])
                )
                total_mock.assert_any_call(
                    usage_type=self.service_usage_types[1],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ])
                )
                usage_mock.assert_any_call(
                    usage_type=self.service_usage_types[0],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                        self.se3.service,
                    ]),
                )
                usage_mock.assert_any_call(
                    usage_type=self.service_usage_types[1],
                    date=self.today,
                    excluded_services=set([
                        self.se4.service,
                        self.se1.service,
                        self.se2.service,
                    ]),
                )

    def test_pricing_dependent_services(self):
        """
        Call costs for PS1, which dependent on PS2, which dependent of PS3.
        Check if all dependencies (and )
        """
        self._init()

        def dependent_services(self1, date, exclude=None):
            if self1 == self.ps1:
                return [self.ps2]
            elif self1 == self.ps2:
                return [self.ps3]
            return []

        # get_dependent_services_mock.side_effect = dependent_services
        with mock.patch.object(models.service.PricingService, 'get_dependent_services', dependent_services):  # noqa
            distribute_costs_orig = PricingServicePlugin._distribute_costs
            with mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._distribute_costs') as distribute_costs_mock:  # noqa
                distribute_costs_mock.side_effect = distribute_costs_orig
                PricingServicePlugin.costs(
                    pricing_service=self.ps1,
                    date=self.today,
                    service_environments=models.ServiceEnvironment.objects.all(),  # noqa
                    forecast=False,
                    pricing_services_calculated=None,
                )
                calls = [
                    mock.call(
                        self.today,  # date
                        self.ps3,  # pricing service
                        {self.ps3.id: (0, {})},  # costs - not important here
                        self.ps3.serviceusagetypes_set.all(),  # percentage
                        excluded_services=set([
                            # from ps3
                            self.se5.service,
                        ])
                    ),
                    mock.call(
                        self.today,
                        self.ps2,
                        {self.ps2.id: (0, {})},
                        self.ps2.serviceusagetypes_set.all(),
                        excluded_services=set([
                            # from ps2
                            self.other_se[1].service,
                            self.se3.service,
                            self.se4.service,
                        ])
                    ),
                    mock.call(
                        self.today,
                        self.ps1,
                        {self.ps1.id: (0, {})},
                        self.ps1.serviceusagetypes_set.all(),
                        excluded_services=set([
                            # from ps1
                            self.other_se[0].service,
                            self.se1.service,
                            self.se2.service,
                        ])
                    ),
                ]

                self.assertEquals(
                    len(calls),
                    len(distribute_costs_mock.call_args_list)
                )
                # comparing strings, because of django query sets in params
                for expected_call, actual_call in zip(
                    calls,
                    distribute_costs_mock.call_args_list
                ):
                    self.assertEquals(str(expected_call), str(actual_call))
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin)
        self.pricing_service1 = PricingServiceFactory(plugin_type=fixed_price)

        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory())

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.sut1 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        self.sut2 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )

        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[0])
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[1])
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[2])

        models.UsagePrice(
            type=self.service_usage_types[0],
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        models.UsagePrice(
            type=self.service_usage_types[1],
            price=20,
            forecast_price=40,
            start=self.start,
            end=self.end,
        ).save()

        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.service_usage_types[0],
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.service_usage_types[1],
                )
class TestPricingServiceFixedPricePlugin(ScroogeTestCase):
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin)
        self.pricing_service1 = PricingServiceFactory(plugin_type=fixed_price)

        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory())

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.sut1 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        self.sut2 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )

        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[0])
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[1])
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2, service_environment=self.service_environments[2])

        models.UsagePrice(
            type=self.service_usage_types[0],
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        models.UsagePrice(
            type=self.service_usage_types[1],
            price=20,
            forecast_price=40,
            start=self.start,
            end=self.end,
        ).save()

        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.service_usage_types[0],
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.service_usage_types[1],
                )

    def test_get_fixed_prices_costs(self):
        result = PricingServiceFixedPricePlugin.costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            service_environments=self.service_environments[:2],
        )

        def _get_single(dpo):
            return {
                'cost':
                D('200'),
                'pricing_object_id':
                dpo.pricing_object.id,
                'type_id':
                self.pricing_service1.id,
                '_children': [{
                    'cost': D('100'),
                    'pricing_object_id': dpo.pricing_object.id,
                    'type_id': self.service_usage_types[0].id,
                    'value': 10.0
                }, {
                    'cost': D('100'),
                    'pricing_object_id': dpo.pricing_object.id,
                    'type_id': self.service_usage_types[1].id,
                    'value': 5.0
                }],
            }

        self.assertNestedDictsEqual(
            result, {
                self.service_environments[0].id: [
                    _get_single(self.se1_dpo[0]),
                    _get_single(self.se1_dpo[1]),
                ],
                self.service_environments[1].id: [
                    _get_single(self.se2_dpo[0]),
                    _get_single(self.se2_dpo[1]),
                ]
            })

    def test_get_total_cost(self):
        result = PricingServiceFixedPricePlugin.total_cost(
            pricing_service=self.pricing_service1,
            date=self.today,
            service_environments=self.service_environments[:2])
        self.assertEqual(
            result, {
                self.pricing_service1.id: [
                    D('800'), {
                        self.service_usage_types[0].id: [D('400'), {}],
                        self.service_usage_types[1].id: [D('400'), {}],
                    }
                ]
            })

    @mock.patch(
        'ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_pricing_service_costs'
    )  # noqa
    def test_get_pricing_service_real_costs_diff(
        self,
        pricing_service_costs_mock,
    ):
        ps2 = PricingServiceFactory()
        self.pricing_service1.charge_diff_to_real_costs = ps2
        self.pricing_service1.save()

        pricing_service_costs_mock.return_value = {
            self.pricing_service1.id: (D(100), {
                self.service_usage_types[0].id: (D(50), {}),
                self.service_usage_types[1].id: (D(50), {}),
            })
        }

        result = PricingServicePlugin._get_service_charging_by_diffs(
            ps2,
            date=self.today,
            forecast=False,
        )
        self.assertEqual(
            result,
            {
                self.pricing_service1.id: (D(-1100), {})  # 100 - 1200
            })
    def _init(self):
        self.ps1, self.ps2, self.ps3 = PricingServiceFactory.create_batch(3)
        self.se1, self.se2 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps1,
        )
        self.se3, self.se4 = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.ps2,
        )
        self.se5 = ServiceEnvironmentFactory(
            service__pricing_service=self.ps3
        )
        self.other_se = ServiceEnvironmentFactory.create_batch(5)

        self.service_usage_types = UsageTypeFactory.create_batch(
            4,
            usage_type='SU',
        )

        self.ps1.excluded_services.add(self.other_se[0].service)
        self.ps1.save()

        self.ps2.excluded_services.add(self.other_se[1].service)
        self.ps2.save()

        self.service_usage_types[0].excluded_services.add(
            self.other_se[2].service
        )
        self.service_usage_types[0].save()

        self.service_usage_types[3].excluded_services.add(
            self.other_se[4].service
        )
        self.service_usage_types[3].save()

        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.ps1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=70,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[2],
            pricing_service=self.ps2,
            start=self.start,
            end=self.end,
            percent=30,
        )
        models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[3],
            pricing_service=self.ps3,
            start=self.start,
            end=self.end,
            percent=100,
        )
    def setUp(self):
        self.maxDiff = None
        self.today = date(2013, 10, 10)
        self.start = date(2013, 10, 1)
        self.end = date(2013, 10, 30)

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin
        )
        self.pricing_service1 = PricingServiceFactory(plugin_type=fixed_price)

        self.service_environments = ServiceEnvironmentFactory.create_batch(
            2,
            service__pricing_service=self.pricing_service1,
        )
        self.service_environments.append(ServiceEnvironmentFactory())

        self.service_usage_types = UsageTypeFactory.create_batch(
            2,
            usage_type='SU',
        )
        self.sut1 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[0],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )
        self.sut2 = models.ServiceUsageTypes.objects.create(
            usage_type=self.service_usage_types[1],
            pricing_service=self.pricing_service1,
            start=self.start,
            end=self.end,
            percent=100,
        )

        self.se1_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[0]
        )
        self.se2_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[1]
        )
        self.se3_dpo = DailyPricingObjectFactory.create_batch(
            2,
            service_environment=self.service_environments[2]
        )

        models.UsagePrice(
            type=self.service_usage_types[0],
            price=10,
            forecast_price=20,
            start=self.start,
            end=self.end,
        ).save()
        models.UsagePrice(
            type=self.service_usage_types[1],
            price=20,
            forecast_price=40,
            start=self.start,
            end=self.end,
        ).save()

        days = rrule.rrule(rrule.DAILY, dtstart=self.start, until=self.end)
        for day in days:
            for dpo in models.DailyPricingObject.objects.all():
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=10,
                    type=self.service_usage_types[0],
                )
                DailyUsageFactory(
                    date=day,
                    daily_pricing_object=dpo,
                    service_environment=dpo.service_environment,
                    value=5,
                    type=self.service_usage_types[1],
                )
class TestPricingServiceDiffCharging(TestCase):
    def setUp(self):
        self.today = date(2014, 11, 10)

        self.service_environments = ServiceEnvironmentFactory.create_batch(5)
        self.pricing_service1 = PricingServiceFactory()

        fixed_price = (
            models.PricingServicePlugin.pricing_service_fixed_price_plugin
        )
        self.pricing_service2 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service2.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service2.save()

        self.pricing_service3 = PricingServiceFactory(plugin_type=fixed_price)
        self.pricing_service3.charge_diff_to_real_costs = self.pricing_service1
        self.pricing_service3.save()

    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost')  # noqa
    @mock.patch('ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost')  # noqa
    def test_get_service_charging_by_diffs(self, fixed_total_mock, total_mock):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(100)
            else:
                val = D(1000)
            return {pricing_service.id: (val, {})}

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(1000)
            else:
                val = D(100)
            return {pricing_service.id: (val, {})}

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_service_charging_by_diffs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(result, {
            self.pricing_service2.id: (-900, {}),
            self.pricing_service3.id: (900, {}),
        })
        calls = [
            mock.call(
                date=self.today,
                pricing_service=x,
                for_all_service_environments=True,
                forecast=False,
            ) for x in (self.pricing_service2, self.pricing_service3)
        ]
        total_mock.assert_has_calls(calls, any_order=True)
        fixed_total_mock.assert_has_calls(calls, any_order=True)

    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost')  # noqa
    @mock.patch('ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost')  # noqa
    def test_get_service_charging_by_diffs_error(
        self,
        fixed_total_mock,
        total_mock
    ):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                return {pricing_service.id: (100, {})}
            raise KeyError()

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                return {pricing_service.id: (100, {})}
            raise AttributeError()

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_service_charging_by_diffs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(result, {
            self.pricing_service2.id: (0, {}),
        })

    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin.total_cost')  # noqa
    @mock.patch('ralph_scrooge.plugins.cost.pricing_service_fixed_price.PricingServiceFixedPricePlugin.total_cost')  # noqa
    def test_get_pricing_service_costs(self, fixed_total_mock, total_mock):
        def total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(100)
            else:
                val = D(1000)
            return {pricing_service.id: (val, {})}

        def fixed_total_cost(pricing_service, *args, **kwargs):
            if pricing_service == self.pricing_service2:
                val = D(1000)
            else:
                val = D(100)
            return {pricing_service.id: (val, {})}

        total_mock.side_effect = total_cost
        fixed_total_mock.side_effect = fixed_total_cost
        result = PricingServicePlugin._get_pricing_service_costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(result, {
            self.pricing_service1.id: (0, {
                self.pricing_service2.id: (-900, {}),
                self.pricing_service3.id: (900, {}),
            })
        })

    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_service_charging_by_diffs')  # noqa
    @mock.patch('ralph_scrooge.plugins.cost.pricing_service.PricingServiceBasePlugin._get_dependent_services_cost')  # noqa
    def test_get_pricing_service_costs_when_diff_key_exist(
        self,
        dependent_costs_mock,
        diff_costs_mock
    ):
        self.usage_type1 = UsageTypeFactory()

        def dependent_costs(*args, **kwargs):
            return {
                self.pricing_service2.id: (100, {
                    self.usage_type1.id: (100, {}),
                }),
                self.pricing_service3.id: (300, {
                    self.usage_type1.id: (100, {}),
                }),
            }

        def diff_costs(pricing_service, *args, **kwargs):
            return {
                self.pricing_service2.id: (200, {}),
            }

        dependent_costs_mock.side_effect = dependent_costs
        diff_costs_mock.side_effect = diff_costs
        result = PricingServicePlugin._get_pricing_service_costs(
            pricing_service=self.pricing_service1,
            date=self.today,
            forecast=False,
        )
        self.assertEquals(result, {
            self.pricing_service1.id: (600, {
                self.pricing_service2.id: (300, {}),
                self.pricing_service3.id: (300, {
                    self.usage_type1.id: (100, {}),
                }),
            })
        })
示例#25
0
    def _set_sample_usages(self):
        # 3 Pricing Services (1 tested and dependent from others)
        # usage types:
        self.ps1, self.ps2, self.ps3 = PricingServiceFactory.create_batch(3)
        se1 = ServiceEnvironmentFactory(service__pricing_service=self.ps1)
        se2 = ServiceEnvironmentFactory(service__pricing_service=self.ps1)

        ut1, ut2, ut3 = UsageTypeFactory.create_batch(3, usage_type='SU')

        models.ServiceUsageTypes(
            usage_type=ut1,
            pricing_service=self.ps2,
            start=datetime.date(2013, 10, 1),
            end=datetime.date(2013, 10, 30),
            percent=50,
        ).save()
        models.ServiceUsageTypes(
            usage_type=ut2,
            pricing_service=self.ps2,
            start=datetime.date(2013, 10, 1),
            end=datetime.date(2013, 10, 30),
            percent=50,
        ).save()
        models.ServiceUsageTypes(
            usage_type=ut3,
            pricing_service=self.ps3,
            start=datetime.date(2013, 10, 1),
            end=datetime.date(2013, 10, 30),
            percent=100,
        ).save()

        # sample usages
        models.DailyUsage(
            daily_pricing_object=DailyPricingObjectFactory(),
            type=ut1,
            date=datetime.date(2013, 10, 3),
            service_environment=se1,
            value=100,
        ).save()
        models.DailyUsage(
            daily_pricing_object=DailyPricingObjectFactory(),
            type=ut2,
            date=datetime.date(2013, 10, 20),
            service_environment=se1,
            value=100,
        ).save()
        models.DailyUsage(
            daily_pricing_object=DailyPricingObjectFactory(),
            type=ut1,
            date=datetime.date(2013, 10, 28),
            service_environment=se2,
            value=100,
            warehouse=WarehouseFactory(),
        ).save()
        models.DailyUsage(
            daily_pricing_object=DailyPricingObjectFactory(),
            type=ut3,
            date=datetime.date(2013, 10, 3),
            service_environment=se2,
            value=100,
        ).save()