Skip to content

Commit 0eca5db

Browse files
committed
Fix force_generate param and handle subs canceled before start_date
1 parent 0f260f2 commit 0eca5db

3 files changed

Lines changed: 90 additions & 9 deletions

File tree

silver/documents_generator.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def generate(self, subscription=None, billing_date=None, customers=None,
5656
:param customers: the customers for which one wants to generate the
5757
proformas/invoices.
5858
:param force_generate: if True, invoices are generated at the date
59-
indicated by `billing_date` instead of the normal end of billing
59+
indicated by `billing_date` instead of after the normal end of billing
6060
cycle.
6161
6262
:note
@@ -114,7 +114,16 @@ def get_subscriptions_prepared_for_billing(self, customer, billing_date, force_g
114114
criteria = {'state__in': [Subscription.STATES.ACTIVE,
115115
Subscription.STATES.CANCELED]}
116116
for subscription in customer.subscriptions.filter(**criteria):
117-
if subscription.should_be_billed(billing_date) or force_generate:
117+
to_bill = subscription.should_be_billed(billing_date) or force_generate
118+
119+
if not to_bill and subscription.cancel_date:
120+
billing_up_to_dates = subscription.billed_up_to_dates
121+
to_bill = (
122+
subscription.cancel_date < billing_up_to_dates["metered_features_billed_up_to"] and
123+
subscription.cancel_date < billing_up_to_dates["plan_billed_up_to"]
124+
)
125+
126+
if to_bill:
118127
subs_to_bill.append(subscription)
119128

120129
return subs_to_bill
@@ -135,7 +144,6 @@ def _bill_subscription_into_document(self, subscription, billing_date, document=
135144
})
136145

137146
billing_log, entries_info = self.add_subscription_cycles_to_document(**kwargs)
138-
139147
if subscription.state == Subscription.STATES.CANCELED:
140148
subscription.end()
141149
subscription.save()
@@ -382,6 +390,12 @@ def _generate_for_user_with_consolidated_billing(self, customer, billing_date, f
382390

383391
self._create_discount_entries(**kwargs)
384392

393+
# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
394+
# should be refactored.
395+
if not document.entries.exists():
396+
document.delete()
397+
continue
398+
385399
if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:
386400
document.issue()
387401

@@ -405,6 +419,12 @@ def _generate_for_user_without_consolidated_billing(self, customer, billing_date
405419

406420
self._create_discount_entries(**kwargs)
407421

422+
# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
423+
# should be refactored.
424+
if not document.entries.exists():
425+
document.delete()
426+
continue
427+
408428
if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:
409429
document.issue()
410430

@@ -419,14 +439,29 @@ def _generate_for_single_subscription(self, subscription=None, billing_date=None
419439

420440
provider = subscription.provider
421441

422-
if not subscription.should_be_billed(billing_date) or force_generate:
442+
to_bill = subscription.should_be_billed(billing_date) or force_generate
443+
444+
if not to_bill and subscription.cancel_date:
445+
billing_up_to_dates = subscription.billed_up_to_dates
446+
to_bill = (
447+
subscription.cancel_date < billing_up_to_dates["metered_features_billed_up_to"] and
448+
subscription.cancel_date < billing_up_to_dates["plan_billed_up_to"]
449+
)
450+
451+
if not to_bill:
423452
return
424453

425454
document, discount_amounts = self._bill_subscription_into_document(subscription, billing_date)
426455

427456
kwargs = {'entries_info': discount_amounts,
428457
provider.flow: document}
429458

459+
# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
460+
# should be refactored.
461+
if not document.entries.exists():
462+
document.delete()
463+
return
464+
430465
self._create_discount_entries(**kwargs)
431466

432467
if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:

silver/management/commands/generate_docs.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,35 @@ def add_arguments(self, parser):
4848
parser.add_argument('--date',
4949
action='store', dest='billing_date', type=date,
5050
help='The billing date (format YYYY-MM-DD).')
51+
parser.add_argument('--force',
52+
action='store', dest='force_generate', type=bool,
53+
help='Bill subscriptions even in situations when they would be skipped.')
5154

5255
def handle(self, *args, **options):
5356
translation.activate('en-us')
5457

5558
billing_date = options['billing_date']
59+
force_generate = options.get('force_generate', False)
5660

5761
docs_generator = DocumentsGenerator()
5862
if options['subscription_id']:
5963
try:
6064
subscription_id = options['subscription_id']
6165
logger.info('Generating for subscription with id=%s; '
62-
'billing_date=%s.', subscription_id,
63-
billing_date)
66+
'billing_date=%s; force_generate=%s.', subscription_id,
67+
billing_date, force_generate)
6468

6569
subscription = Subscription.objects.get(id=subscription_id)
6670
docs_generator.generate(subscription=subscription,
67-
billing_date=billing_date)
71+
billing_date=billing_date,
72+
force_generate=force_generate)
6873
self.stdout.write('Done. You can have a Club-Mate now. :)')
6974
except Subscription.DoesNotExist:
7075
msg = 'The subscription with the provided id does not exist.'
7176
self.stdout.write(msg)
7277
else:
7378
logger.info('Generating for all the available subscriptions; '
74-
'billing_date=%s.', billing_date)
79+
'billing_date=%s; force_generate=%s.', billing_date, force_generate)
7580

76-
docs_generator.generate(billing_date=billing_date)
81+
docs_generator.generate(billing_date=billing_date, force_generate=force_generate)
7782
self.stdout.write('Done. You can have a Club-Mate now. :)')

silver/tests/commands/test_generate_docs.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,47 @@ def test_gen_active_and_canceled_selection(self):
17261726

17271727
assert Subscription.objects.filter(state='ended').count() == 3
17281728

1729+
def test_subscription_with_cancel_date_before_start_date(self):
1730+
"""
1731+
Should not produce anything, just end the subscription.
1732+
"""
1733+
1734+
subscription = SubscriptionFactory.create()
1735+
subscription.activate()
1736+
subscription.cancel(when=subscription.start_date - dt.timedelta(days=2))
1737+
subscription.save()
1738+
1739+
assert subscription.state == "canceled"
1740+
1741+
call_command('generate_docs',
1742+
billing_date=subscription.start_date + dt.timedelta(days=9999),
1743+
stdout=self.output)
1744+
assert Invoice.objects.all().count() == Proforma.objects.all().count() == 0
1745+
1746+
subscription.refresh_from_db()
1747+
assert subscription.state == "ended"
1748+
1749+
def test_subscription_with_cancel_date_before_start_date_and_with_specified_subscription_id(self):
1750+
"""
1751+
Should not produce anything, just end the subscription.
1752+
"""
1753+
1754+
subscription = SubscriptionFactory.create()
1755+
subscription.activate()
1756+
subscription.cancel(when=subscription.start_date - dt.timedelta(days=2))
1757+
subscription.save()
1758+
1759+
assert subscription.state == "canceled"
1760+
1761+
call_command('generate_docs',
1762+
billing_date=subscription.start_date + dt.timedelta(days=9999),
1763+
subscription=str(subscription.id),
1764+
stdout=self.output)
1765+
assert Invoice.objects.all().count() == Proforma.objects.all().count() == 0
1766+
1767+
subscription.refresh_from_db()
1768+
assert subscription.state == "ended"
1769+
17291770
def test_subscription_with_separate_cycles_during_trial(self):
17301771
separate_cycles_during_trial = True
17311772
prebill_plan = False

0 commit comments

Comments
 (0)