diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py index af87512ca0..09be7b36d6 100644 --- a/corporate/lib/stripe.py +++ b/corporate/lib/stripe.py @@ -4932,8 +4932,11 @@ def invoice_plans_as_needed(event_time: Optional[datetime] = None) -> None: plan.reminder_to_review_plan_email_sent = True plan.save(update_fields=["reminder_to_review_plan_email_sent"]) + free_plan_with_no_next_plan = not plan.is_paid() and plan.status == CustomerPlan.ACTIVE last_audit_log_update = remote_server.last_audit_log_update - if last_audit_log_update is None or plan.next_invoice_date > last_audit_log_update: + if not free_plan_with_no_next_plan and ( + last_audit_log_update is None or plan.next_invoice_date > last_audit_log_update + ): if ( last_audit_log_update is None or plan.next_invoice_date - last_audit_log_update >= timedelta(days=1) diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index 8f75f456e2..0bf9c42e43 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -9079,11 +9079,14 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase): self.remote_server.plan_type, RemoteZulipServer.PLAN_TYPE_SELF_MANAGED_LEGACY ) - with mock.patch("stripe.Invoice.create") as invoice_create, time_machine.travel( - plan_end_date, tick=False - ): - send_server_data_to_push_bouncer(consider_usage_statistics=False) + with mock.patch("stripe.Invoice.create") as invoice_create, mock.patch( + "corporate.lib.stripe.send_email" + ) as send_email, time_machine.travel(plan_end_date, tick=False): invoice_plans_as_needed() + # Verify that for legacy plan with no next plan scheduled, + # invoice overdue email is not sent even if the last audit log + # update was 3 months ago. + send_email.assert_not_called() # The legacy plan is downgraded, no invoice created. invoice_create.assert_not_called() @@ -9143,6 +9146,15 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase): ) licenses = max(min_licenses, server_user_count) + with mock.patch("stripe.Invoice.create") as invoice_create, mock.patch( + "corporate.lib.stripe.send_email" + ) as send_email, time_machine.travel(end_date, tick=False): + invoice_plans_as_needed() + # Verify that for legacy plan with next plan scheduled, invoice + # overdue email is sent if the last audit log is stale. + send_email.assert_called() + invoice_create.assert_not_called() + with time_machine.travel(end_date, tick=False): send_server_data_to_push_bouncer(consider_usage_statistics=False) invoice_plans_as_needed()