From f60b8ccedc0d3e370ecd4ceae8c81cc290b5dd5c Mon Sep 17 00:00:00 2001 From: Eeshan Garg Date: Sat, 30 Oct 2021 22:24:33 +0530 Subject: [PATCH] corporate: Improve testing for switching from Standard to Plus. This is a follow-up to #19752. The tests in that PR did not verify that the financial math involved worked properly. This commit improves the existing tests and adds new fixtures to make sure that the financial math works as expected. --- ...ndard_to_plus_plan--Customer.create.1.json | Bin 0 -> 635 bytes ...Customer.create_balance_transaction.1.json | Bin 411 -> 389 bytes ...-Customer.list_balance_transactions.1.json | Bin 0 -> 1010 bytes ...andard_to_plus_plan--Invoice.create.1.json | Bin 3785 -> 3415 bytes ...plus_plan--Invoice.finalize_invoice.1.json | Bin 4105 -> 3740 bytes ...standard_to_plus_plan--Invoice.list.1.json | Bin 0 -> 4346 bytes ...rd_to_plus_plan--InvoiceItem.create.1.json | Bin 1143 -> 1044 bytes corporate/tests/test_stripe.py | 53 ++++++++++++++++-- 8 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.create.1.json create mode 100644 corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.list_balance_transactions.1.json create mode 100644 corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Invoice.list.1.json diff --git a/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.create.1.json b/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..0eddc80a49da1bf675ee5649f9d3e096655bdef5 GIT binary patch literal 635 zcmZ9JO;5ux42JLf6;%%iBs6VTP9WfbG(h4ALXnraYam}F>C|c3f5%SSZO}ud*smYk zulKX6szIrUDb+WX>x{YP&>9Rli4=^GMVjOgU|I-O`CN!I~Cu7JO0%mVT zqtU2y&nPu59$;r_M`1Cyo~M}RB~9af#yG}^cqqFWy+!L48-B8d%0WSfQ*XM0v0_+k z*n@~eFlB}o@9HDgfo0^>zINDWp~uY=@+HcFmSqUP{zA!@8F!>HOFXpR{lTzjNOxDl gcnJpChL6vpO|1@r3_I_dp%>Vr4TbF(HapCI0Y9+3wEzGB literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.create_balance_transaction.1.json b/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.create_balance_transaction.1.json index 68a55480a80d3b25633456d51ab28b35f0ede9b1..cfd38627ace972b2a72f2dd94440d7d3f1f9908d 100644 GIT binary patch literal 389 zcmY+A!Ait15Qgu4ijcEH*Nfmy)Pt}p=*>%+CR53hOv+@kSeAWvlhm%5N!%Rgqx?L0j0a-_CYnoeUHO%Oz#+SDcxV%u<-n$?9L2BnIRPO-{q> z+xyG?{`vFiu~hEXjKyTw&Eg`}*aKs!R};se5ZEtDkb@(r0Tn0pAwU+`s@Vgr6-d_6 z*DyjMrcU*z;i`c)qkPl<-#4er9FC6BwbvIX?~WLvt&J1-gv}|SfCYg9Pv=JBctBIP fR~?)0Hp(Cjl)yB(mX&3$bsFrUWCND1cjxX0J^yq? delta 242 zcmZo=p3Q7f&7}YYN|`B2RtieVNhK9|@rGX6QC039!HMA!m1S-P-kye`<|)P56-qil zwUZqf^$dU-5_9uQ^Gbl4bj^(n3_vnK!Q`UU#FA8yQHEy5CPpTPhL&KdiF%SIAnDSg zqSUB4Y#~T_Mo0x(nC)T-6JSgi5RFj!kmYzOi3(B1PViZR||G{4x=OhH8eqt diff --git a/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.list_balance_transactions.1.json b/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Customer.list_balance_transactions.1.json new file mode 100644 index 0000000000000000000000000000000000000000..07d1d8cb4d689bf32ea5adbe4b16d92da323f918 GIT binary patch literal 1010 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 diff --git a/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Invoice.finalize_invoice.1.json b/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--Invoice.finalize_invoice.1.json index 8ca538120014d6dfe6e0f0dda4f9fb5168f9b349..dc4f1c7ec6c68905b70bed648d5aa8dadaa77098 100644 GIT binary patch literal 3740 zcmcgvOK%)E48G@AEOf5DUL#16oZ7;56To#_CvjQ_g`l0$dX&{jvK|{dhW~p>y=G<~ ztxxq~y$~siUc9^c`Rr&h z)$r_|iq?UW3R0%aeKgw!y!!p=$;tTCFww&C#obj3Mk(dy(K z?|E;s|AWnR%JG#Ila8m?gV&U`8>Slc%G)rU_wYzVArKHeLiCUtuGmseO~9%1%!d*x zC_Y8gOCcrrPAz9nE3iR&rUH{GPff?{Ek0S((`YGq6XWW+?=(6}99JzBYNG}C7tJ~*g0);V5wGCdtR0-!JzWVdr(iTuz%4!k-|2uP7|mD~9Y|1XxhoOo*U&Jx z6fu%$WevgpAUU(g+TM;|2c=vuL#+9AYC5f^Stt_M31brWyVtO~_&uVGFDtY$^=c@; z&wocr%U3K&PYrwMITUwIaW!5voDMb?!;S=vT1Y-7qMCJ$6$Vj*!{LT-v3vHNjc*4| zTQCS}TVMk0SUXE5b7iK+SZVDeX7!~`JE(?IA~e{DMd!V7Z|3t{Imga}ll-{R{annU zzx@<%Kzt5iO->ih+4Z}Rr{{ludMi(_)K3=|=dUlW*XHW-{QB<0`tqSs=F9b>eYiT6 zH-9a0pRVl_zy$yy1;r1+Moh+C_%nJO^Q`>{|ma{$Z?#GfON%rc)uPN@X8c=QskO2RhX{M;>a?E5oRN$5z$qk&W^tdJ7xtBqe z{|;)lQlJ&U&WNoL&$=eXhWEPN=NI%a%Xxi_oSR?L%P&Br_y&SN#oD27P-D4shcz5-8Mq9SmJ_oIle9fb;-TAW@=OZ%v2l|A1q3 za~i#|x(x|s{5p*xu}L*#Irh?Ym{cLM`jU5SBVq%Spq$~2fRUMI=%6ULbu`!FPKe$z zS%c9=aTCp&r>^kHATh zo`LbMR$a8)f3)&`Tr@Uc@fmTj9I4OBBB!773R2 zN^qj&im1>p(`J>os-t128luVhNCO3yS*$_1q8bNZHI>)m3LYu@i%=fc7*HkVKX|lW zaol_80YokjrD7~CLsZ8-2Ib{_KxIn@(JUG@Z;4UqJ_;pSw#%Rh88NWF)SV0nt%U|q zu;aL)4btXgEPs~XU4Yx82nh5(hXsvRP)cmLwp&cdXv;dPKTB|@2ljIsO zvv^$5IndJB>amL;TXpro4j*T4k3wv`_RvO=8*?8~kVKI%%kt1J&Xccv*}?p9kZT+= MPzKxCdGYk(A6^MKzyJUM literal 4105 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 KpvaSlC;tNcX^~g} literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--InvoiceItem.create.1.json b/corporate/tests/stripe_fixtures/switch_realm_from_standard_to_plus_plan--InvoiceItem.create.1.json index 1d6d11ea4cd70ac3fdfd3e7d9f7dd948688f00ad..f67f3a76987ae0f8f92116897d4278c1dbf51ece 100644 GIT binary patch literal 1044 zcmaJ=O>f&U488YP7&>==0~7_i+kovbplgR7I}Cy>Gc6Zc()5w72>RbgN{VBzL347R z$j8S=@^I00LQO8)BtCYVtE;}hWJu=_!0HzQMUJCrU`%d;z@W}i-rYZZ`*i#D@yqAF z?>9AOR0)`gkoqf`BSan0Cv=vRAG1NuEluUzrnB2IoFhNqJUQyuTwS>9h7ijiHG!9HKRh=FJ zI<9{px5zKB{Ab-Y!7-^&jGa|ccqR8nu@|!@AF9YksB|Kc6fj#rbORcL_DM$l3==;J z(jl|OR8&!f4nPAqtL5BCDWkers=sd}#h&wxVdr+)%N_8#92+A1jiZEF)H|z+_(kN& z>1qSpPr*L8G1m$3=UQJ~IEo6ut&uP5>Ph{T13arey0Wp^Mh_adNcJ@Tgb<=^o3N0R zg0gYz!X$rZWfP|V8cQ#}xbG~;gw#yq<4MTVHC@+ZB8iI!Ig*Hp_MN7;p$Ku>h~R>1 oCo)f6EEL?7t&DkC9@9~_;C?9|78kN8OXav)VOYR#)x2K(18(0Yx&QzG literal 1143 zcmZuwO;6k~5WVv&qMWHjmatNKt5mfJ4y;=BgGH6)II}RUV;g^L*&_aX$BDB^SaOJx zdE+ z`jJyuplKz6vvCo@`@<*TeN!W#^)?u`g}5-Iazc&_&$47WfeOV|@vg_&A!BtD`h|_3 z?0R+6-mHGEm$%P9u0D+_EW}nx>)WcHKeHMh_zrcqt3f#f0yjvK5B7Nk>sVTnS$%K0 zavN=1_7u4C=#OOiz3H6Q3YbSyaA1u-v++(Xhbu*LClG6>ot74#rc+Q(K3^fLEl>Al nGTVI8O_lc6g?f6sMj3hZfLP%8!c6+0`muZ>n*hfRzMlLCO&U0G diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index faf1253eea..4163a9d284 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -300,6 +300,7 @@ MOCKED_STRIPE_FUNCTION_NAMES = [ "Coupon.create", "Customer.create", "Customer.create_balance_transaction", + "Customer.list_balance_transactions", "Customer.retrieve", "Customer.save", "Invoice.create", @@ -2982,7 +2983,8 @@ class StripeTest(StripeTestCase): @mock_stripe() def test_switch_realm_from_standard_to_plus_plan(self, *mock: Mock) -> None: - realm = get_realm("zulip") + iago = self.example_user("iago") + realm = iago.realm # Test upgrading to Plus when realm has no Standard subscription with self.assertRaises(BillingError) as billing_context: @@ -3002,12 +3004,28 @@ class StripeTest(StripeTestCase): "Organization missing Stripe customer.", billing_context.exception.error_description ) - plan.customer.stripe_customer_id = "cus_12345" - plan.customer.save(update_fields=["stripe_customer_id"]) - plan.price_per_license = get_price_per_license(CustomerPlan.STANDARD, CustomerPlan.MONTHLY) - plan.automanage_licenses = True + king = self.lear_user("king") + realm = king.realm + customer = update_or_create_stripe_customer(king) + plan = CustomerPlan.objects.create( + customer=customer, + automanage_licenses=True, + billing_cycle_anchor=timezone_now(), + billing_schedule=CustomerPlan.MONTHLY, + tier=CustomerPlan.STANDARD, + ) + ledger = LicenseLedger.objects.create( + plan=plan, + is_renewal=True, + event_time=timezone_now(), + licenses=9, + licenses_at_next_renewal=9, + ) + realm.plan_type = Realm.PLAN_TYPE_STANDARD + realm.save(update_fields=["plan_type"]) plan.invoiced_through = ledger - plan.save(update_fields=["price_per_license", "automanage_licenses", "invoiced_through"]) + plan.price_per_license = get_price_per_license(CustomerPlan.STANDARD, CustomerPlan.MONTHLY) + plan.save(update_fields=["invoiced_through", "price_per_license"]) switch_realm_from_standard_to_plus_plan(realm) @@ -3018,6 +3036,29 @@ class StripeTest(StripeTestCase): self.assertEqual(plus_plan.tier, CustomerPlan.PLUS) self.assertEqual(LicenseLedger.objects.filter(plan=plus_plan).count(), 1) + # There are 9 licenses and the realm is on the Standard monthly plan. + # Therefore, the customer has already paid 800 * 9 = 7200 = $72 for + # the month. Once they upgrade to Plus, the new price for their 9 + # licenses will be 1600 * 9 = 14400 = $144. Since the customer has + # already paid $72 for a month, -7200 = -$72 will be credited to the + # customer's balance. + stripe_customer_id = customer.stripe_customer_id + assert stripe_customer_id is not None + _, cb_txn = stripe.Customer.list_balance_transactions( # type: ignore[attr-defined] # mypy seems to incorrectly think that this function doesn't exist + stripe_customer_id + ) + self.assertEqual(cb_txn.amount, -7200) + self.assertEqual( + cb_txn.description, + "Credit from early termination of Standard plan", + ) + self.assertEqual(cb_txn.type, "adjustment") + + # The customer now only pays the difference 14400 - 7200 = 7200 = $72, + # since the unused proration is for the whole month. + (invoice,) = stripe.Invoice.list(customer=stripe_customer_id) + self.assertEqual(invoice.amount_due, 7200) + def test_update_billing_method_of_current_plan(self) -> None: realm = get_realm("zulip") customer = Customer.objects.create(realm=realm, stripe_customer_id="cus_12345")