diff --git a/orchestra/apps/services/handlers.py b/orchestra/apps/services/handlers.py index 00c15df9..37197f91 100644 --- a/orchestra/apps/services/handlers.py +++ b/orchestra/apps/services/handlers.py @@ -409,10 +409,30 @@ class ServiceHandler(plugins.Plugin): lines = [] bp = None for order in orders: + bp = self.get_billing_point(order, bp=bp, **options) + if (self.billing_period != self.NEVER and + self.get_pricing_period() == self.NEVER and + self.payment_style == self.PREPAY and order.billed_on): + # Recharge + if self.payment_style == self.PREPAY and order.billed_on: + rini = order.billed_on + charged = None + new_metric, new_price = 0, 0 + for cini, cend, metric in order.get_metric(rini, bp, changes=True): + if charged is None: + charged = metric + size = self.get_price_size(cini, cend) + new_price += self.get_price(order, metric) * size + new_metric += metric + size = self.get_price_size(rini, bp) + old_price = self.get_price(order, charged) * size + if new_price > old_price: + metric = new_metric - charged + price = new_price - old_price + lines.append(self.generate_line(order, price, rini, bp, metric=metric, computed=True)) if order.billed_until and order.cancelled_on and order.cancelled_on >= order.billed_until: continue if self.billing_period != self.NEVER: - bp = self.get_billing_point(order, bp=bp, **options) ini = order.billed_until or order.registered_on # Periodic billing if bp <= ini: @@ -425,6 +445,8 @@ class ServiceHandler(plugins.Plugin): lines.append(self.generate_line(order, price, cini, cend, metric=metric)) elif self.get_pricing_period() == self.billing_period: # pricing_slots (Traffic-like) + if self.payment_style == self.PREPAY: + raise NotImplementedError for cini, cend in self.get_pricing_slots(ini, bp): metric = order.get_metric(cini, cend) price = self.get_price(order, metric) @@ -456,7 +478,8 @@ class ServiceHandler(plugins.Plugin): if options.get('commit', True): now = timezone.now().date() for line in lines: - line.order.billed_on = now - line.order.billed_until = line.order.new_billed_until - line.order.save() + order = line.order + order.billed_on = now + order.billed_until = getattr(order, 'new_billed_until', order.billed_until) + order.save() return lines diff --git a/orchestra/apps/services/tests/functional_tests/test_mailbox.py b/orchestra/apps/services/tests/functional_tests/test_mailbox.py index 3060952d..db5ee338 100644 --- a/orchestra/apps/services/tests/functional_tests/test_mailbox.py +++ b/orchestra/apps/services/tests/functional_tests/test_mailbox.py @@ -129,5 +129,31 @@ class MailboxBillingTest(BaseBillingTest): bill = service.orders.bill(**options).pop() total = 9*10*0.5 + 19*10*0.25 + 29*10*0.25 self.assertEqual(total, bill.get_total()) + + def test_mailbox_with_recharge(self): + service = self.create_mailbox_disk_service() + self.create_disk_resource() + account = self.create_account() + mailbox = self.create_mailbox(account=account) + now = timezone.now() + bp = now.date() + relativedelta(years=1) + options = dict(billing_point=bp, fixed_point=True) + + self.allocate_disk(mailbox, 100) + bill = service.orders.bill(**options).pop() + self.assertEqual(99*10, bill.get_total()) + + with freeze_time(now+relativedelta(months=6)): + self.allocate_disk(mailbox, 50) + bills = service.orders.bill(**options) + self.assertEqual([], bills) + + with freeze_time(now+relativedelta(months=6)): + self.allocate_disk(mailbox, 200) + bill = service.orders.bill(new_open=True, **options).pop() + self.assertEqual((199-99)*10*0.5, bill.get_total()) + + with freeze_time(now+relativedelta(months=6)): + bills = service.orders.bill(new_open=True, **options) + self.assertEqual([], bills) - # TODO recharge missing stuff