From 8343ed6cebb93eaeb5831e695ae8a24da8034776 Mon Sep 17 00:00:00 2001 From: Vishnu Ks Date: Sun, 25 Nov 2018 18:54:54 +0000 Subject: [PATCH] billing: Use mock_stripe in test_downgrade_with_money_owed. --- ...ade_with_money_owed:Customer.create.1.json | Bin 0 -> 1581 bytes ...e_with_money_owed:Customer.retrieve.1.json | Bin 0 -> 4880 bytes ...e_with_money_owed:Customer.retrieve.2.json | Bin 0 -> 4880 bytes ...e_with_money_owed:Customer.retrieve.3.json | Bin 0 -> 2217 bytes ...grade_with_money_owed:Customer.save.1.json | Bin 0 -> 4894 bytes ...de_with_money_owed:Invoice.upcoming.1.json | Bin 0 -> 4201 bytes ..._with_money_owed:InvoiceItem.create.1.json | Bin 0 -> 459 bytes ...with_money_owed:Subscription.create.1.json | Bin 0 -> 2160 bytes ...with_money_owed:Subscription.delete.1.json | Bin 0 -> 2174 bytes ...th_money_owed:Subscription.retrieve.1.json | Bin 0 -> 2174 bytes ...ngrade_with_money_owed:Token.create.1.json | Bin 0 -> 826 bytes corporate/tests/test_stripe.py | 63 ++++++++---------- stubs/stripe/__init__.pyi | 5 ++ 13 files changed, 33 insertions(+), 35 deletions(-) create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.create.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.retrieve.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.retrieve.2.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.retrieve.3.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.save.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Invoice.upcoming.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:InvoiceItem.create.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Subscription.create.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Subscription.delete.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Subscription.retrieve.1.json create mode 100644 corporate/tests/stripe_fixtures/downgrade_with_money_owed:Token.create.1.json diff --git a/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.create.1.json b/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..5cbf2dc4562e886a04828d90fd2f974f24e82712 GIT binary patch literal 1581 zcmb_cOOMkq5WerPhmD@bZG?# za!E3eZ@zgxUKE7@rEF`0T!03nP`oL|mn>HfAz&H*Coku->FZaM*|bx%&Y@A8s4=b9 zNmgP7tq#)L)+G#~z?JgT=dT~HKD@tscRe0H6Oo-XnO`lM5TPp29<$ghM@=AWqFiiS zO-=FaF1@aC^*lS1PrQdLum;lXLvU~3CdU`b)|~@!DnhmXm{sONW@SmCY#dg!X3NBV zoYk6ESlg1Tb0At{fD!^k;bW{=tXV9Xu4Nag^V|!4aEzKriD_T8VdjqSn-$%KX(zoex}Y4Ai8g1|Q~sCWq@r*4Bh& zRLyuuGA7G62s}m8@ocE6;-H{w9Hm9-2KTUZ{Twoks9IBYW5xSjQW)l!H{`F2n+f&& z#e6!S4snKik;Xhb#I(7Y;;IB5GS|&|Rt`2H5*We-`+$bFzz0D_?4{+l@x~3~IAZ literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.retrieve.1.json b/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Customer.retrieve.1.json new file mode 100644 index 0000000000000000000000000000000000000000..e06cb1905339171d87ae7835b65f44f187ec5220 GIT binary patch literal 4880 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 literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Invoice.upcoming.1.json b/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Invoice.upcoming.1.json new file mode 100644 index 0000000000000000000000000000000000000000..ae36a17cf77e7c8008d1c0d4b91e25b0bcdc86b3 GIT binary patch literal 4201 zcmeHKS&!Q`5PsiZAqYj$0!=Jg^05ViqS!6k0%^8LTA)o^5VS2YwH}%@wDlz)kxRS)~UD2v?s^emd#fBiP6|X^Wfvf5e z4>ut}u;dKR$GRzaZO&P_J2`wpp@krN>(}MMN~6M=$s;nkMPe zx}nwUoq<=C@mv>rFSdA#DMjfmR(${cHo2*Pdt0;nDb40T$luve7iBw63xX&B40JvA zSVecF=H=M+HBs0*^5MOSwSN|0{Y?tv{n&WjT{sXoL{M&!>|)^$K|En8#7?JCDlCk` zbe3n+#XQYs-EG5*8^FS`UR)@!09KXIHf=hkc(V~?1DHix;>{45{T7?>aCjL&0l?sM z56NOnYI8OQvyf&~4Sa4u19_)x-lntcdYPryi?sK}MO1;%1=yH{Zh5x9*{$B)EwAt7 z%kUD)07E-mnP(gb7UR;cri2eTA7FUEnGl17(c%rm&UDO}hT8+XdJx#C1hPi(Qagm0 zzt*<=I)6pfFSpG;)T1a7CUM(L?qXvF$V2l~Dln64F6#5aRf6IQIW$6fIgH+7p@Gz) zu`!0KO&FwhJPtp>g)Qpv+z@T?TaB5b%GA_l?}}LJRZs%qd#tiLn}gk58cTZNMEh=^ z`!@Cc)4ROsv(Wc9cw-81cg@XT{pi{k1|lxQ0(Rt;uzub5^(&vRU+wDcY5;}!T>bi& zW9Q+04%~4M-TzU)e1XdQC_}QG)USLTK(2lr`4Cd1gVk{d7~pD<)d5lCXuOUUk-8b7)Z(LQdWFqNX(OYp5-$)4t3?LheSIq zU4lfPq=2SREv;>MpIVw_4IQXHXiK|Ldxn+ZWA(J)p0=sk-@jb#jkj3Bd>~Bc9=ts$ z@3I}&V#O6q11z*Y;r; zluxJZ)BY4QvRA0VhnfHl#f}u3c5NBgY~dLf)Ahb<4t&jE{VD>+cM3bYqXm!L_lHB{1x8Aw_~30-wcy5AX?u3 b)UO&?1!wNbYRmZ>2^N{Ciy>9LdVlo~lU-)L literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/downgrade_with_money_owed:InvoiceItem.create.1.json b/corporate/tests/stripe_fixtures/downgrade_with_money_owed:InvoiceItem.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..ba27537f616660221e31ce7ca893985b214a332b GIT binary patch literal 459 zcmZvZOHacv5QOjf6_L*z8XAhk4N-)Uct~(TT%wKRs*C(c?R6>?^}pkdqe4-0^JnkO z&SWggQh;&MlDH|W1%DUJWb|HH`JJeUp%XI<)Z3~)8ps;I*nENO$Ve{ z>Z)E|UazWUJxz8hNRK_Cv+2@Ctuw|T*&ABTL*%2HICgA-*i>sEw}03!?##!|*nPd) zybosEW-qjZL&=jzMU8_pu4A?V9kQHJ1Zgiwa6C)~uKiMyBa2xBNtrC#E02!-$J9e= zLRmhX=1DjZ_^GpF(DXcu_Zm)8_TG7zqyH|oi(m~K3z>F45~^i0bZ4cZ=~dvv_cxsUQbNW`UQoomDb8^(Zs|K>{fCJzAW&J z0Id%!4dUV;GzJ*4D=nVLZWi;|?W=4)i%|j{QgiThk1BI6O^#6;&`u@+GRKg#1Ysq3 zNuj3+gSA+0KV5cnyI5wk?$UmY^I$3YAd|zUBo)m>aQw^t!{>LOK7RjjH=Rziy2%_4 zjtAqF=6R55fw|m3(4M<8;QV?Xq-X|nZ)HMgj-OPY{EdT8=LJts%Y^)D%?4Jy(JtExyEsw_^YIbLZnU7?K) zgjai-ink%+T-%9$+pU#b#FhsK+jMZpkfIsi5`j3@b0j8rVkZka%aB!wkMc=D7?;ju zzFN++)os>GBqBq^fl>sQ_fOX&qqg{6Ie&b=U;n*duI}B#Ntp4{?m<(Ig9JP7kQRdV`r-g0+X8^&*j1s>M)UAUt0dMd1b%ZRU((_fe%tMVQ{fxaWR*SFFf4i$5 z`+2;Qme|*>gs!yc;7#R2uLa{ar7g~b>#YLas+Z(7c1xrN_lGKCjO$7ohs&U2b;{B| z0Z^Zwpj;mN?NJt8V>)ZnJ;(2#^;xz9hwa%DVAyf6TDg{O%$FXUIYF2O8#!^k&#ni; zac@)8n-TS6HL*Q5MiDlkMp9XtIl{?$(qto|yeLNoLm{^BhVv4|zWWWb=)5Es++DasM}<;z=u{l+ o%)1cHK9Ce!l8_phhsWga!SrQZ#!X4}d%WEMjj_#6=Bwwce>ePDYXATM literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Subscription.delete.1.json b/corporate/tests/stripe_fixtures/downgrade_with_money_owed:Subscription.delete.1.json new file mode 100644 index 0000000000000000000000000000000000000000..7580eee9c3214c116c19af5202d4d8a8eb4b9541 GIT binary patch literal 2174 zcma)8OOMkq5We?UR6ZlN>4R;N5JHp#60p+3352Yv$YKJ1i_Mms1g0p3TJ`AKh zlGKQ@Ba>*L*uK>0kuB!4>HVv0HVsw`6$nv z)F~?@%^gR}c2YUtf|Hh-(%}?48ev$8KB)|QztX7iJrd(KgZYK!g+YU71P9^C!2&-0 z2v6fE4I0*;*US&H{*ahO3?+#s1-B66Kc5oUa`THb-;6KPFfFREK)$jtqv&2qP;H@6 z2F!|spN-WnU|!4pD(-fg?+{_?4D8bJolS~3#3jOUuIId@)UZ7-yf48GLzIL~3PQVd zCbQLYmaXoyP9PTcgdKedXY#IhJu=@GU6-?`_lM2jhvn+QJYJY7%k=@Ik8$LnhqbiX zh;9KA$5WKK@1f;IJAf;IU}H+K-wNv1K`DpXJAIuY3#fE-l`eBv)=`~KsFrqBpb>SR)gAO6)?ur#g)O6&~A0Q zrGFeCORa};dG5EfvZxy3Sqygy-#=?#vIm3h=?h@Ud9YHLX4{A@EjDw3FmXEU#N8pg z>k-GiO+{}8*pJnO_Q=qRkltz}m8FpboTNidGC<0kbR^IxV)LH3PQe@G!(;1D_$BS) zjk-=aB8I8f%6kwD%?|0)o8B!-C6i6aME;9Lq)(t))Ta)yH%NoZTXezOg*SANDD@6q ul7n1%Bcj+kPeoF{ype3455&S#@@HZ4GMwXBRQ*4R;N5JHp#60p+3352Yv$YKJ1i_Mms1g0p3TJ`AKh zlGKQ@Ba>*L*uK>0kuB!4>HVv0HVsw`6$nv z)F~?@%^gR}c2YUtf|Hh-(%}?48ev$8KB)|QztX7iJrd(KgZYK!g+YU71P9^C!2&-0 z2v6fE4I0*;*US&H{*ahO3?+#s1-B66Kc5oUa`THb-;6KPFfFREK)$jtqv&2qP;H@6 z2F!|spN-WnU|!4pD(-fg?+{_?4D8bJolS~3#3jOUuIId@)UZ7-yf48GLzIL~3PQVd zCbQLYmaXoyP9PTcgdKedXY#IhJu=@GU6-?`_lM2jhvn+QJYJY7%k=@Ik8$LnhqbiX zh;9KA$5WKK@1f;IJAf;IU}H+K-wNv1K`DpXJAIuY3#fE-l`eBv)=`~KsFrqBpb>SR)gAO6)?ur#g)O6&~A0Q zrGFeCORa};dG5EfvZxy3Sqygy-#=?#vIm3h=?h@Ud9YHLX4{A@EjDw3FmXEU#N8pg z>k-GiO+{}8*pJnO_Q=qRkltz}m8FpboTNidGC<0kbR^IxV)LH3PQe@G!(;1D_$BS) zjk-=aB8I8f%6kwD%?|0)o8B!-C6i6aME;9Lq)(t))Ta)yH%NoZTXezOg*SANDD@6q ul7n1%Bcj+kPeoF{ype3455&S#@@HZ4GMwXBRQ*e?5488L!s+`e8KekD`A#I0A`_d3Q>{6M;T|L^gN>VgH{P)FyGFBndOKLwq zzZZKuiXtJwC~+5U{oVh8QUZ z7Wz_o;(c}uuH*$CwboFR%qy@i`!5oI+PrSGD}6XUc;eU^!T3-zN&9F)`U_2KNIRDF z^7{TfeR}+SxS#NednHAul}9o}8dT)^1O+EN?tD-i2u?YAogz!Jq_3~hfdU7fdAmC( z^|tuY#Z&=rfH6I|S$v}mI>UY);I3JsrVTi1bnf}ehBfgt{dxsXAuB@d^8LsrSK$k! z?8c9n3*zf6O>S@EG-h70H|Du7`w|tcux=C!E}*g)ivNTLar;(o-3D7n?V_`xbEq5b FM!#n%<$nMG literal 0 HcmV?d00001 diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index 78c8c7ed1d..86a54ef0d4 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -63,22 +63,6 @@ def mock_customer_with_cancel_at_period_end_subscription(*args: Any, **kwargs: A customer.subscriptions.data[0].cancel_at_period_end = True return customer -def mock_customer_with_account_balance(account_balance: int) -> Callable[[str, List[str]], stripe.Customer]: - def customer_with_account_balance(stripe_customer_id: str, expand: List[str]) -> stripe.Customer: - stripe_customer = mock_customer_with_subscription() - stripe_customer.account_balance = account_balance - return stripe_customer - return customer_with_account_balance - -def mock_invoice_preview_for_downgrade(total: int=-1000) -> Callable[[str, str, Dict[str, Any]], stripe.Invoice]: - def invoice_preview(customer: str, subscription: str, - subscription_items: Dict[str, Any]) -> stripe.Invoice: - # TODO: Get a better fixture; this is not at all what these look like - stripe_invoice = stripe.util.convert_to_stripe_object(fixture_data["upcoming_invoice"]) - stripe_invoice.total = total - return stripe_invoice - return invoice_preview - # TODO: check that this creates a token similar to what is created by our # actual Stripe Checkout flows def stripe_create_token(card_number: str="4242424242424242") -> stripe.Token: @@ -834,28 +818,37 @@ class StripeTest(ZulipTestCase): self.assert_json_error_contains(response, 'Please reload') self.assertEqual(ujson.loads(response.content)['error_description'], 'downgrade without subscription') - @patch("stripe.Subscription.delete") - @patch("stripe.Customer.retrieve", side_effect=mock_customer_with_account_balance(1234)) - def test_downgrade_credits(self, mock_retrieve_customer: Mock, - mock_delete_subscription: Mock) -> None: + @mock_stripe("Customer.create", "Customer.retrieve", "Customer.save", "Invoice.upcoming", + "Subscription.create", "Subscription.retrieve", "Subscription.save", + "Subscription.delete", "Token.create", "InvoiceItem.create") + def test_downgrade_with_money_owed(self, mock10: Mock, mock9: Mock, mock8: Mock, mock7: Mock, + mock6: Mock, mock5: Mock, mock4: Mock, mock3: Mock, + mock2: Mock, mock1: Mock) -> None: user = self.example_user('iago') self.login(user.email) - Customer.objects.create( - realm=user.realm, stripe_customer_id=self.stripe_customer_id, has_billing_relationship=True) - # Check that positive balance is forgiven - with patch("stripe.Invoice.upcoming", side_effect=mock_invoice_preview_for_downgrade(1000)): - with patch.object( - stripe.Customer, 'save', autospec=True, - side_effect=lambda customer: self.assertEqual(customer.account_balance, 1234)): - response = self.client_post("/json/billing/downgrade", {}) - self.assert_json_success(response) - # Check that negative balance is credited - with patch("stripe.Invoice.upcoming", side_effect=mock_invoice_preview_for_downgrade(-1000)): - with patch.object( - stripe.Customer, 'save', autospec=True, - side_effect=lambda customer: self.assertEqual(customer.account_balance, 234)): - response = self.client_post("/json/billing/downgrade", {}) + self.client_post("/upgrade/", {'stripeToken': stripe_create_token().id, + 'signed_seat_count': self.signed_seat_count, + 'salt': self.salt, + 'plan': Plan.CLOUD_ANNUAL, + 'billing_modality': 'charge_automatically'}) + stripe_customer = stripe_get_customer(Customer.objects.get(realm=user.realm).stripe_customer_id) + self.assertEqual(stripe_customer.account_balance, 0) + stripe_subscription = extract_current_subscription(stripe_customer) + # Create a situation where customer net owes us money + stripe.InvoiceItem.create( + amount=100000, + currency='usd', + customer=stripe_customer, + subscription=stripe_subscription) + + response = self.client_post("/json/billing/downgrade", {}) self.assert_json_success(response) + stripe_customer = stripe_get_customer(stripe_customer.id) + # Check that positive balance was forgiven + self.assertEqual(stripe_customer.account_balance, 0) + self.assertIsNone(extract_current_subscription(stripe_customer)) + stripe_subscription = stripe.Subscription.retrieve(stripe_subscription.id) + self.assertEqual(stripe_subscription.status, "canceled") @patch("stripe.Customer.retrieve", side_effect=mock_customer_with_subscription) def test_replace_payment_source(self, mock_retrieve_customer: Mock) -> None: diff --git a/stubs/stripe/__init__.pyi b/stubs/stripe/__init__.pyi index ec40febacd..77753ee45f 100644 --- a/stubs/stripe/__init__.pyi +++ b/stubs/stripe/__init__.pyi @@ -135,3 +135,8 @@ class Charge: @staticmethod def list(customer: Optional[str]) -> List[Charge]: ... + +class InvoiceItem: + @staticmethod + def create(amount: int, currency: str, customer: Customer, subscription: Subscription) -> Subscription: + ...