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,142 @@ 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 .
email = "[email protected] " 198+ self .owner .save ()
199+
200+ response = self ._send_event (
201+ payload = {
202+ "type" : "invoice.payment_failed" ,
203+ "data" : {
204+ "object" : {
205+ "customer" : self .owner .stripe_customer_id ,
206+ "subscription" : self .owner .stripe_subscription_id ,
207+ "default_payment_method" : {
208+ "card" : {"brand" : "visa" , "last4" : 1234 }
209+ },
210+ "total" : 24000 ,
211+ "hosted_invoice_url" : "https://stripe.com" ,
212+ }
213+ },
214+ }
215+ )
216+
217+ self .owner .refresh_from_db ()
218+ assert response .status_code == status .HTTP_204_NO_CONTENT
219+ assert self .owner .delinquent is True
220+
221+ expected_calls = [
222+ call (
223+ to_addr = self .owner .email ,
224+ subject = "Your Codecov payment failed" ,
225+ template_name = "failed-payment" ,
226+ name = self .owner .username ,
227+ amount = 240 ,
228+ card_type = "visa" ,
229+ last_four = 1234 ,
230+ cta_link = "https://stripe.com" ,
231+ date = datetime .now ().strftime ("%B %-d, %Y" ),
232+ ),
233+ call (
234+ to_addr = admin_1 .email ,
235+ subject = "Your Codecov payment failed" ,
236+ template_name = "failed-payment" ,
237+ name = admin_1 .username ,
238+ amount = 240 ,
239+ card_type = "visa" ,
240+ last_four = 1234 ,
241+ cta_link = "https://stripe.com" ,
242+ date = datetime .now ().strftime ("%B %-d, %Y" ),
243+ ),
244+ call (
245+ to_addr = admin_2 .email ,
246+ subject = "Your Codecov payment failed" ,
247+ template_name = "failed-payment" ,
248+ name = admin_2 .username ,
249+ amount = 240 ,
250+ card_type = "visa" ,
251+ last_four = 1234 ,
252+ cta_link = "https://stripe.com" ,
253+ date = datetime .now ().strftime ("%B %-d, %Y" ),
254+ ),
255+ ]
256+ mocked_send_email .assert_has_calls (expected_calls )
257+
258+ @patch ("services.task.TaskService.send_email" )
259+ def test_invoice_payment_failed_sends_email_to_admins_no_card (
260+ self , mocked_send_email
261+ ):
262+ non_admin = OwnerFactory (
email = "[email protected] " )
263+ admin_1 = OwnerFactory (
email = "[email protected] " )
264+ admin_2 = OwnerFactory (
email = "[email protected] " )
265+ self .owner .admins = [admin_1 .ownerid , admin_2 .ownerid ]
266+ self .owner .plan_activated_users = [non_admin .ownerid ]
267+ self .
owner .
email = "[email protected] " 268+ self .owner .save ()
269+
270+ response = self ._send_event (
271+ payload = {
272+ "type" : "invoice.payment_failed" ,
273+ "data" : {
274+ "object" : {
275+ "customer" : self .owner .stripe_customer_id ,
276+ "subscription" : self .owner .stripe_subscription_id ,
277+ "default_payment_method" : None ,
278+ "total" : 24000 ,
279+ "hosted_invoice_url" : "https://stripe.com" ,
280+ }
281+ },
282+ }
283+ )
284+
285+ self .owner .refresh_from_db ()
286+ assert response .status_code == status .HTTP_204_NO_CONTENT
287+ assert self .owner .delinquent is True
288+
289+ expected_calls = [
290+ call (
291+ to_addr = self .owner .email ,
292+ subject = "Your Codecov payment failed" ,
293+ template_name = "failed-payment" ,
294+ name = self .owner .username ,
295+ amount = 240 ,
296+ card_type = None ,
297+ last_four = None ,
298+ cta_link = "https://stripe.com" ,
299+ date = datetime .now ().strftime ("%B %-d, %Y" ),
300+ ),
301+ call (
302+ to_addr = admin_1 .email ,
303+ subject = "Your Codecov payment failed" ,
304+ template_name = "failed-payment" ,
305+ name = admin_1 .username ,
306+ amount = 240 ,
307+ card_type = None ,
308+ last_four = None ,
309+ cta_link = "https://stripe.com" ,
310+ date = datetime .now ().strftime ("%B %-d, %Y" ),
311+ ),
312+ call (
313+ to_addr = admin_2 .email ,
314+ subject = "Your Codecov payment failed" ,
315+ template_name = "failed-payment" ,
316+ name = admin_2 .username ,
317+ amount = 240 ,
318+ card_type = None ,
319+ last_four = None ,
320+ cta_link = "https://stripe.com" ,
321+ date = datetime .now ().strftime ("%B %-d, %Y" ),
322+ ),
323+ ]
324+ mocked_send_email .assert_has_calls (expected_calls )
325+
179326 def test_customer_subscription_deleted_sets_plan_to_free (self ):
180327 self .owner .plan = "users-inappy"
181328 self .owner .plan_user_count = 20
0 commit comments