11import time
2- from unittest .mock import patch
2+ from datetime import datetime
3+ from unittest .mock import call , patch
34
45import stripe
56from django .conf import settings
@@ -142,6 +143,11 @@ def test_invoice_payment_failed_sets_owner_delinquent_true(self):
142143 "object" : {
143144 "customer" : self .owner .stripe_customer_id ,
144145 "subscription" : self .owner .stripe_subscription_id ,
146+ "default_payment_method" : {
147+ "card" : {"brand" : "visa" , "last4" : 1234 }
148+ },
149+ "total" : 24000 ,
150+ "hosted_invoice_url" : "https://stripe.com" ,
145151 }
146152 },
147153 }
@@ -165,6 +171,11 @@ def test_invoice_payment_failed_sets_multiple_owners_delinquent_true(self):
165171 "object" : {
166172 "customer" : self .owner .stripe_customer_id ,
167173 "subscription" : self .owner .stripe_subscription_id ,
174+ "default_payment_method" : {
175+ "card" : {"brand" : "visa" , "last4" : 1234 }
176+ },
177+ "total" : 24000 ,
178+ "hosted_invoice_url" : "https://stripe.com" ,
168179 }
169180 },
170181 }
@@ -176,6 +187,118 @@ def test_invoice_payment_failed_sets_multiple_owners_delinquent_true(self):
176187 assert self .owner .delinquent is True
177188 assert self .other_owner .delinquent is True
178189
190+ @patch ("services.task.TaskService.send_email" )
191+ def test_invoice_payment_failed_sends_email_to_admins (self , mocked_send_email ):
192+ non_admin = OwnerFactory (
email = "[email protected] " )
193+ admin_1 = OwnerFactory (
email = "[email protected] " )
194+ admin_2 = OwnerFactory (
email = "[email protected] " )
195+ self .owner .admins = [admin_1 .ownerid , admin_2 .ownerid ]
196+ self .owner .plan_activated_users = [non_admin .ownerid ]
197+ self .owner .save ()
198+
199+ response = self ._send_event (
200+ payload = {
201+ "type" : "invoice.payment_failed" ,
202+ "data" : {
203+ "object" : {
204+ "customer" : self .owner .stripe_customer_id ,
205+ "subscription" : self .owner .stripe_subscription_id ,
206+ "default_payment_method" : {
207+ "card" : {"brand" : "visa" , "last4" : 1234 }
208+ },
209+ "total" : 24000 ,
210+ "hosted_invoice_url" : "https://stripe.com" ,
211+ }
212+ },
213+ }
214+ )
215+
216+ self .owner .refresh_from_db ()
217+ assert response .status_code == status .HTTP_204_NO_CONTENT
218+ assert self .owner .delinquent is True
219+
220+ expected_calls = [
221+ call (
222+ to_addr = admin_1 .email ,
223+ subject = "Your Codecov payment failed" ,
224+ template_name = "failed-payment" ,
225+ name = admin_1 .username ,
226+ amount = 240 ,
227+ card_type = "visa" ,
228+ last_four = 1234 ,
229+ cta_link = "https://stripe.com" ,
230+ date = datetime .now ().strftime ("%B %-d, %Y" ),
231+ ),
232+ call (
233+ to_addr = admin_2 .email ,
234+ subject = "Your Codecov payment failed" ,
235+ template_name = "failed-payment" ,
236+ name = admin_2 .username ,
237+ amount = 240 ,
238+ card_type = "visa" ,
239+ last_four = 1234 ,
240+ cta_link = "https://stripe.com" ,
241+ date = datetime .now ().strftime ("%B %-d, %Y" ),
242+ ),
243+ ]
244+ mocked_send_email .assert_has_calls (expected_calls )
245+
246+ @patch ("services.task.TaskService.send_email" )
247+ def test_invoice_payment_failed_sends_email_to_admins_no_card (
248+ self , mocked_send_email
249+ ):
250+ non_admin = OwnerFactory (
email = "[email protected] " )
251+ admin_1 = OwnerFactory (
email = "[email protected] " )
252+ admin_2 = OwnerFactory (
email = "[email protected] " )
253+ self .owner .admins = [admin_1 .ownerid , admin_2 .ownerid ]
254+ self .owner .plan_activated_users = [non_admin .ownerid ]
255+ self .owner .save ()
256+
257+ response = self ._send_event (
258+ payload = {
259+ "type" : "invoice.payment_failed" ,
260+ "data" : {
261+ "object" : {
262+ "customer" : self .owner .stripe_customer_id ,
263+ "subscription" : self .owner .stripe_subscription_id ,
264+ "default_payment_method" : None ,
265+ "total" : 24000 ,
266+ "hosted_invoice_url" : "https://stripe.com" ,
267+ }
268+ },
269+ }
270+ )
271+
272+ self .owner .refresh_from_db ()
273+ assert response .status_code == status .HTTP_204_NO_CONTENT
274+ assert self .owner .delinquent is True
275+
276+ expected_calls = [
277+ call (
278+ to_addr = admin_1 .email ,
279+ subject = "Your Codecov payment failed" ,
280+ template_name = "failed-payment" ,
281+ name = admin_1 .username ,
282+ amount = 240 ,
283+ card_type = None ,
284+ last_four = None ,
285+ cta_link = "https://stripe.com" ,
286+ date = datetime .now ().strftime ("%B %-d, %Y" ),
287+ ),
288+ call (
289+ to_addr = admin_2 .email ,
290+ subject = "Your Codecov payment failed" ,
291+ template_name = "failed-payment" ,
292+ name = admin_2 .username ,
293+ amount = 240 ,
294+ card_type = None ,
295+ last_four = None ,
296+ cta_link = "https://stripe.com" ,
297+ date = datetime .now ().strftime ("%B %-d, %Y" ),
298+ ),
299+ ]
300+ mocked_send_email .assert_has_calls (expected_calls )
301+
179302 def test_customer_subscription_deleted_sets_plan_to_free (self ):
180303 self .owner .plan = "users-inappy"
181304 self .owner .plan_user_count = 20
0 commit comments