示例#1
0
    def get_factor(self, current=False):
        month_days = monthrange(self.start.year, self.start.month)[1]

        if self.unit == self.Units.QUANTITY:
            return self.quantity
        elif self.unit == self.Units.PER_HOUR:
            if current:
                return utils.get_full_hours(self.start, min(self.end, timezone.now()))
            else:
                return utils.get_full_hours(self.start, self.end)
        elif self.unit == self.Units.PER_DAY:
            if current:
                return utils.get_full_days(self.start, min(self.end, timezone.now()))
            else:
                return self.usage_days
        elif self.unit == self.Units.PER_HALF_MONTH:
            if (self.start.day == 1 and self.end.day == 15) or (self.start.day == 16 and self.end.day == month_days):
                return 1
            elif (self.start.day == 1 and self.end.day == month_days):
                return 2
            elif (self.start.day == 1 and self.end.day > 15):
                return quantize_price(1 + (self.end.day - 15) / decimal.Decimal(month_days / 2))
            elif (self.start.day < 16 and self.end.day == month_days):
                return quantize_price(1 + (16 - self.start.day) / decimal.Decimal(month_days / 2))
            else:
                return quantize_price((self.end.day - self.start.day + 1) / decimal.Decimal(month_days / 2.0))
        # By default PER_MONTH
        else:
            if self.start.day == 1 and self.end.day == month_days:
                return 1

            use_days = (self.end - self.start).days + 1
            return quantize_price(decimal.Decimal(use_days) / month_days)
示例#2
0
    def get_factor(item):
        month_days = monthrange(item.start.year, item.start.month)[1]

        if item.unit == Units.QUANTITY:
            return item.quantity
        elif item.unit == Units.PER_HOUR:
            return utils.get_full_hours(item.start, item.end)
        elif item.unit == Units.PER_DAY:
            return usage_days(item)
        elif item.unit == Units.PER_HALF_MONTH:
            if (item.start.day == 1 and item.end.day == 15) or (
                    item.start.day == 16 and item.end.day == month_days):
                return 1
            elif item.start.day == 1 and item.end.day == month_days:
                return 2
            elif item.start.day == 1 and item.end.day > 15:
                return quantize_price(1 + (item.end.day - 15) /
                                      decimal.Decimal(month_days / 2))
            elif item.start.day < 16 and item.end.day == month_days:
                return quantize_price(1 + (16 - item.start.day) /
                                      decimal.Decimal(month_days / 2))
            else:
                return quantize_price((item.end.day - item.start.day + 1) /
                                      decimal.Decimal(month_days / 2.0))
        # By default PER_MONTH
        else:
            if item.start.day == 1 and item.end.day == month_days:
                return 1

            use_days = (item.end - item.start).days + 1
            return quantize_price(decimal.Decimal(use_days) / month_days)
示例#3
0
def get_quantity(unit, start, end):
    """
    For fixed components this method computes number of billing periods resource
    was used from the time it was purchased or from the start of current month
    till the time it was terminated or billing plan has been switched or end of current month.
    """
    month_days = monthrange(start.year, start.month)[1]

    if unit == Units.PER_HOUR:
        return utils.get_full_hours(start, end)
    elif unit == Units.PER_DAY:
        return utils.get_full_days(start, end)
    elif unit == Units.PER_HALF_MONTH:
        if (start.day == 1 and end.day == 15) or (start.day == 16
                                                  and end.day == month_days):
            return 1
        elif start.day == 1 and end.day == month_days:
            return 2
        elif start.day == 1 and end.day > 15:
            return quantize_price(1 + (end.day - 15) /
                                  decimal.Decimal(month_days / 2))
        elif start.day < 16 and end.day == month_days:
            return quantize_price(1 + (16 - start.day) /
                                  decimal.Decimal(month_days / 2))
        else:
            return quantize_price(
                (end.day - start.day + 1) / decimal.Decimal(month_days / 2.0))
    # By default PER_MONTH
    else:
        if start.day == 1 and end.day == month_days:
            return 1

        use_days = (end - start).days + 1
        return quantize_price(decimal.Decimal(use_days) / month_days)
示例#4
0
    def test_case_when_usage_is_reported_for_switched_plan(self):
        self.assertEqual(self.invoice.price, self.fixture.plan.unit_price)
        self._switch_plan()
        fixed_price = (Decimal(self.fixture.plan.unit_price) * quantize_price(Decimal(15 / 31.0))) + \
                      (Decimal(self.fixture.new_plan.unit_price) * quantize_price(Decimal(17 / 31.0)))
        self.assertEqual(self.invoice.price, fixed_price)
        self._create_usage(datetime.date(2018, 1, 10), usage=10)

        self.invoice.refresh_from_db()
        self.assertEqual(
            self.invoice.price,
            fixed_price + self.fixture.plan_component_cpu.price * 10)
示例#5
0
    def test_case_when_usage_is_reported_for_new_plan(self):
        self.assertEqual(self.invoice.items.count(), 1)
        self.assertEqual(self.invoice.price, self.fixture.plan.unit_price)
        self._switch_plan()
        self.assertEqual(self.invoice.items.count(), 2)
        fixed_price = (Decimal(self.fixture.plan.unit_price) * quantize_price(
            Decimal(15 / 31.0))) + (Decimal(self.fixture.new_plan.unit_price) *
                                    quantize_price(Decimal(17 / 31.0)))
        self.assertEqual(self.invoice.price, fixed_price)
        self._create_usage(usage=10)

        self.invoice.refresh_from_db()
        self.assertEqual(
            self.invoice.price,
            fixed_price + self.fixture.new_plan_component_cpu.price * 10,
        )
示例#6
0
 def test_factor_for_month_is_equal_to_fraction_of_days(self):
     item = factories.InvoiceItemFactory(
         start=parse_datetime('2016-11-1 14:00:00'),
         end=parse_datetime('2016-11-8 14:00:00'),
         unit=models.InvoiceItem.Units.PER_MONTH,
     )
     self.assertEqual(item.get_factor(),
                      quantize_price(decimal.Decimal(8.0 / 30)))
 def price(self):
     """
     Price for whole template for one day.
     :rtype: Decimal
     """
     price = self.components.aggregate(total=models.Sum(
         models.F('price') * models.F('amount'),
         output_field=models.DecimalField(
             max_digits=22, decimal_places=10)))['total'] or Decimal('0')
     return quantize_price(price)
示例#8
0
 def test_invoice_item_with_start_in_first_day_and_end_in_second_half(self):
     start_date = timezone.datetime(2017, 7, 1)
     month_days = monthrange(2017, 7)[1]
     end_date = timezone.datetime(2017, 7, 20)
     usage_days = 5
     offering, offering_item = self._start_end_offering(
         start_date, end_date)
     expected_price = offering.unit_price * quantize_price(
         1 + (usage_days / decimal.Decimal(month_days / 2)))
     self.assertEqual(offering_item.price, expected_price)
示例#9
0
 def monthly_price(self):
     """
     Return price for one month in case of monthly billing plan or price for 30 days otherwise.
     :rtype: Decimal
     """
     if self.unit == common_mixins.UnitPriceMixin.Units.PER_MONTH:
         price = self.components.aggregate(
             total=models.Sum(models.F('price') * models.F('amount'),
                              output_field=models.DecimalField(
                                  max_digits=22, decimal_places=10)
                              ))['total'] or Decimal('0')
         return quantize_price(price)
     elif self.unit == common_mixins.UnitPriceMixin.Units.PER_DAY:
         return self.price * 30
示例#10
0
    def test_invoice_item_with_monthly_price(self):
        start_date = timezone.datetime(2017, 7, 20)
        month_days = monthrange(2017, 7)[1]
        usage_days = month_days - start_date.day + 1
        offering = support_factories.OfferingFactory(
            unit=common_mixins.UnitPriceMixin.Units.PER_MONTH)
        with freeze_time(start_date):
            offering.state = support_models.Offering.States.OK
            offering.save(update_fields=['state'])

        expected_price = offering.unit_price * quantize_price(
            decimal.Decimal((usage_days / month_days)))
        offering_item = models.InvoiceItem.objects.get(scope=offering)
        self.assertEqual(offering_item.price, expected_price)
示例#11
0
    def _price(self, current=False):
        """
        For components billed daily and hourly this method returns estimated price if `current` is True.
        Otherwise, it returns total price calculated using `quantity` field.
        It is assumed that value of `quantity` field is updated automatically when invoice item is terminated.
        """
        quantity = self.quantity
        if current:
            if self.unit == self.Units.PER_HOUR:
                quantity = utils.get_full_hours(self.start,
                                                min(self.end, timezone.now()))
            if self.unit == self.Units.PER_DAY:
                quantity = utils.get_full_days(self.start,
                                               min(self.end, timezone.now()))

        return quantize_price(self.unit_price * decimal.Decimal(quantity))
    def test_invoice_item_with_monthly_price(self):
        start_date = timezone.datetime(2017, 7, 20)
        end_date = timezone.datetime(2017, 7, 31)
        resource = self.fixture.resource

        with freeze_time(start_date):
            resource.set_state_ok()
            resource.save()

        use_days = (end_date - start_date).days + 1
        month_days = monthrange(start_date.year, start_date.month)[1]
        factor = quantize_price(decimal.Decimal(use_days) / month_days)
        expected_price = self.fixture.plan_component.price * factor

        invoice_item = models.InvoiceItem.objects.get(resource=resource)
        self.assertEqual(invoice_item.price, expected_price)
示例#13
0
    def test_existing_invoice_is_updated_on_resource_creation(self):
        start_date = timezone.datetime(2014, 2, 27, tzinfo=pytz.UTC)
        end_date = core_utils.month_end(start_date)
        usage_days = utils.get_full_days(start_date, end_date)
        month_days = monthrange(start_date.year, start_date.month)[1]
        factor = quantize_price(decimal.Decimal(usage_days) / month_days)

        with freeze_time(start_date):
            invoice = factories.InvoiceFactory(customer=self.fixture.customer)
            self.resource.set_state_ok()
            self.resource.save()

        self.assertEqual(models.Invoice.objects.count(), 1)
        self.assertTrue(invoice.items.filter(resource=self.resource).exists())
        expected_price = self.plan_component.price * factor
        self.assertEqual(invoice.price, Decimal(expected_price))
    def test_invoice_item_with_half_monthly_price_with_start_in_first_half(
            self):
        start_date = timezone.datetime(2017, 7, 14)
        resource = self.fixture.resource
        self.fixture.plan.unit = common_mixins.UnitPriceMixin.Units.PER_HALF_MONTH
        self.fixture.plan.save()

        with freeze_time(start_date):
            resource.set_state_ok()
            resource.save()

        month_days = monthrange(2017, 7)[1]
        factor = quantize_price(1 + (16 - start_date.day) /
                                decimal.Decimal(month_days / 2))
        expected_price = self.fixture.plan_component.price * factor
        invoice_item = models.InvoiceItem.objects.get(resource=resource)
        self.assertEqual(invoice_item.price, expected_price)
示例#15
0
    def stats(self, request, uuid=None):
        invoice = self.get_object()
        offerings = {}

        for item in invoice.items.all():
            if not item.scope:
                continue

            if isinstance(item.scope, marketplace_models.Resource):
                resource = item.scope
                offering = resource.offering
                customer = offering.customer
                service_category_title = offering.category.title
                service_provider_name = customer.name
                service_provider_uuid = customer.serviceprovider.uuid.hex
            elif isinstance(item.scope, support_models.Offering):
                offering = item.scope.template
                service_category_title = 'Request'
                service_provider_name = ''
                service_provider_uuid = ''
            else:
                continue

            if offering.uuid.hex not in offerings.keys():
                offerings[offering.uuid.hex] = {
                    'offering_name': offering.name,
                    'aggregated_cost': item.total,
                    'service_category_title': service_category_title,
                    'service_provider_name': service_provider_name,
                    'service_provider_uuid': service_provider_uuid,
                }
            else:
                offerings[offering.uuid.hex]['aggregated_cost'] += item.total

        queryset = [dict(uuid=key, **details) for (key, details) in offerings.items()]

        for item in queryset:
            item['aggregated_cost'] = quantize_price(
                decimal.Decimal(item['aggregated_cost'])
            )

        page = self.paginate_queryset(queryset)
        return self.get_paginated_response(page)
    def _start_end_offering(self, start_date, end_date):
        resource = self.fixture.resource

        use_days = (end_date - start_date).days + 1
        month_days = monthrange(start_date.year, start_date.month)[1]
        factor = quantize_price(decimal.Decimal(use_days) / month_days)
        expected_price = self.fixture.plan_component.price * factor

        with freeze_time(start_date):
            resource.set_state_ok()
            resource.save()
            invoice_item = models.InvoiceItem.objects.get(resource=resource)

        with freeze_time(end_date):
            resource.set_state_terminating()
            resource.save()
            resource.set_state_terminated()
            resource.save()
            invoice_item.refresh_from_db()

        return resource, invoice_item, expected_price
示例#17
0
    def test_invoice_price_is_not_changed_after_a_while_if_resource_is_deleted(
            self):
        start_date = timezone.datetime(2014, 2, 27, tzinfo=pytz.UTC)
        end_date = core_utils.month_end(start_date)
        usage_days = utils.get_full_days(start_date, end_date)
        month_days = monthrange(start_date.year, start_date.month)[1]
        factor = quantize_price(decimal.Decimal(usage_days) / month_days)

        with freeze_time(start_date):
            self.resource.set_state_ok()
            self.resource.save()
            self.assertEqual(models.Invoice.objects.count(), 1)
            invoice = models.Invoice.objects.first()

        with freeze_time(end_date):
            self.resource.set_state_terminating()
            self.resource.save()
            self.resource.set_state_terminated()
            self.resource.save()

        expected_price = self.plan_component.price * factor
        self.assertEqual(invoice.price, Decimal(expected_price))
示例#18
0
 def create_file(self):
     parser = HTMLParser()
     context = {
         'contract': self,
         'client': {
             'name': self.team.customer.name,
             'laws': self.team.customer.country,
             'number': self.team.customer.registration_code,
             'representative': self.team.customer.get_owners()[0].full_name
         },
         'expert': {
             'name':
             self.request.project.customer.name,
             'laws':
             self.request.project.customer.country,
             'number':
             self.request.project.customer.registration_code,
             'representative':
             self.request.project.customer.get_owners()[0].full_name
         },
         'service': {
             'description': parser.unescape(self.request.description),
             'date_end': ''
         },
         'status': ExpertRequest.States.COMPLETED,
         'remuneration': {
             'type': 'regular payment'
             if self.request.recurring_billing else 'one-time payment',
             'value': common_utils.quantize_price(self.price),
             'currency': settings.WALDUR_EXPERTS['CURRENCY_NAME']
         },
         'period': ''
     }
     contract_text = render_to_string('experts/contract_template.html',
                                      context)
     pdf = pdfkit.from_string(contract_text, False)
     self._file = base64.b64encode(pdf)
     self.save()
示例#19
0
 def get_factor(self, start_date, usage_days):
     month_days = monthrange(start_date.year, start_date.month)[1]
     return quantize_price(decimal.Decimal(usage_days) / month_days)
示例#20
0
 def get_tax(self, invoice_item):
     return quantize_price(invoice_item.tax)
示例#21
0
 def get_total(self, invoice_item):
     return quantize_price(invoice_item.price)
示例#22
0
 def price(self):
     return quantize_price(
         decimal.Decimal(sum((item.price for item in self.items))))
示例#23
0
 def _price(self, current=False):
     return quantize_price(self.unit_price *
                           decimal.Decimal(self.get_factor(current)))
示例#24
0
 def quantize_prices(apps, schema_editor):
     OpenStackItem = apps.get_model('invoices', 'OpenStackItem')
     for item in OpenStackItem.objects.iterator():
         item.daily_price = quantize_price(item.daily_price)
         item.save(update_fields=['daily_price'])
示例#25
0
 def price(item):
     return quantize_price(item.unit_price *
                           decimal.Decimal(get_factor(item)))