From 2e394f39138f400a0e0d63e5034c9dd1edd20b71 Mon Sep 17 00:00:00 2001 From: Lauryn Menard Date: Wed, 18 Sep 2024 17:54:06 +0200 Subject: [PATCH] billing: Check minimum for plan tier for stale license count check. --- corporate/lib/stripe.py | 4 +- ..._minimum_for_plan_tier--Charge.list.1.json | Bin 0 -> 3502 bytes ...imum_for_plan_tier--Customer.create.1.json | Bin 0 -> 795 bytes ...imum_for_plan_tier--Customer.modify.1.json | Bin 0 -> 806 bytes ...um_for_plan_tier--Customer.retrieve.1.json | Bin 0 -> 2153 bytes ...um_for_plan_tier--Customer.retrieve.2.json | Bin 0 -> 2153 bytes ...d_minimum_for_plan_tier--Event.list.1.json | Bin 0 -> 1805 bytes ...d_minimum_for_plan_tier--Event.list.2.json | Bin 0 -> 40639 bytes ...d_minimum_for_plan_tier--Event.list.3.json | Bin 0 -> 21085 bytes ...d_minimum_for_plan_tier--Event.list.4.json | Bin 0 -> 81 bytes ...nimum_for_plan_tier--Invoice.create.1.json | Bin 0 -> 4796 bytes ...plan_tier--Invoice.finalize_invoice.1.json | Bin 0 -> 4963 bytes ...minimum_for_plan_tier--Invoice.list.1.json | Bin 0 -> 83 bytes ...minimum_for_plan_tier--Invoice.list.2.json | Bin 0 -> 5760 bytes ..._minimum_for_plan_tier--Invoice.pay.1.json | Bin 0 -> 4978 bytes ...m_for_plan_tier--InvoiceItem.create.1.json | Bin 0 -> 1203 bytes ...for_plan_tier--PaymentMethod.create.1.json | Bin 0 -> 1098 bytes ...m_for_plan_tier--SetupIntent.create.1.json | Bin 0 -> 904 bytes ...mum_for_plan_tier--SetupIntent.list.1.json | Bin 0 -> 1117 bytes ...for_plan_tier--SetupIntent.retrieve.1.json | Bin 0 -> 904 bytes ..._plan_tier--checkout.Session.create.1.json | Bin 0 -> 2159 bytes ...or_plan_tier--checkout.Session.list.1.json | Bin 0 -> 2574 bytes corporate/tests/test_stripe.py | 51 ++++++++++++++++++ 23 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Charge.list.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.modify.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.retrieve.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.retrieve.2.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.2.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.3.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.4.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.finalize_invoice.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.2.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.pay.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--InvoiceItem.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--PaymentMethod.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.list.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.retrieve.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.create.1.json create mode 100644 corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.list.1.json diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py index 884e0579ee..78977ca0d7 100644 --- a/corporate/lib/stripe.py +++ b/corporate/lib/stripe.py @@ -1710,8 +1710,8 @@ class BillingSession(ABC): if request_seat_count == minimum_seat_count and current_seat_count < minimum_seat_count: # Continue to use the minimum licenses for the plan tier. return request_seat_count - # Otherwise, use a current count for billed licenses. - return current_seat_count + # Otherwise, we want to check the current count against the minimum. + return max(current_seat_count, minimum_seat_count) def ensure_current_plan_is_upgradable(self, customer: Customer, new_plan_tier: int) -> None: # Upgrade for customers with an existing plan is only supported for remote realm / server right now. diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Charge.list.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Charge.list.1.json new file mode 100644 index 0000000000000000000000000000000000000000..9359655d1b19da5bb747787cabd8d6f363b36aff GIT binary patch literal 3502 zcmcIn-EZ4A5P#2KA@I4iV=sMZfng1j4akswpjloz3LmP-SO^szdJvl6a^_+VB}r#C;Tpo=kyJytT9msI6pgu&#UP%<;;fYM0rf^ zL=|X)fyj|qTH029P;*TbNXg_733kwF3w3;t)h78 zUkibW2A(;yO*CuLwckyxi%TO$R*9{R?u*gc%oYh}ibn-bOPYK)LI+5u=T6#S9ESPz z_WJ5`adG|W_OiJ7EyV#*H>svz;u zEp!>66C1s1SLj7q1Hfc=eO+>9D#v0uM)OcAi7}CA?;I;3j3?+{SJDR=YHDHt0>BzV z(g9xpUdnVy8>wXz8w$Ch7W#??DctMV7d3NtVx^=HtIg`0hgQx3$S#H8N-npYl6%p# z5T0hJfgbF5=y?d+?7j((97K3>JGe5M?nKR0MNI|rNt%o+6AGq>F>pW!=#H9Pi|}CF zeS&YqUMI|2XZDZ{$WbTFPN9VWnE2wULp+!Mo+_~y*k42&*Dy7?hjL&FhXG_lgo|D% zB^(_pnlTB{S|x&5jqQXdixvorp*Bu_hbEb|rDdtwla8`2(5ch`@QxO&Tx^hD5$aK! z1RC4?fZ`Z+nR|dB9GVys4i9dbn~olEFkuqg_2SfhJ?V|>nY4C5z$wPP^lX$SaKmfC z?+@7<-M6$(6BE;U$ic?UCw;dH?wW-}3{7oQeq%V|d4Bgm|>HF*?)`*V}PO z1SL;`A;E1=w{H$)P*|9^Ik7!&jgt?Kk*Hgw16i@18UTcE&YhPMP{D8%&N=`M=4fGr zwrViwK@(MgxJ!93(WHh`WLcPAld{5vqrpYZ_Q07KU=Q$ld{W~`RA?J3J%fj0KAd4# zXWO&wq`IU5;Iz|ncB_dhz><>IoBteQPazP*9HTw^1amKtQx38beHwv@CyxRNxXK+3 zwqcKn!n>Yp^-@k3dTs)aAIg8Ioe&fU2Z!OdRDlO5k3jHXmh&4%C?h?gC93E&vK;7^ z3)m%Szqyc_HDK`l_o$>@0Ym1hW>p=V-JJbUwlW_Ii@@3+%I)-JwN=E)oOUqjErQ#|x}%G<;O)L|HVIA*g`kOb2%f$e5K z9wgn%*89!6ot1w5|BQRc5L8_ZsmgI#{=+ecPS38++f*j+ c$-+Blq8(%Y1#q1zzgY97YLj_2$;r#f-<-0>R{#J2 literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.create.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..ec5a4bf2ea9f749fff4e1b3c62b2d3eeac2197c8 GIT binary patch literal 795 zcmaJYxH487-9M0)~>M$MHIh;l$`LE>11EN8~sb(t^bBP3M)?|8i3G`X;s)p+dp z{N9_V)p|XkwV6s8-mgP*?p-hK&|xqnrE5K#Ojyavd3(Kl^F_;!|z6+3f73OkP=ubCUdGBgVcw=&2d`4x!2zf?cWY_7Z($oj-CL?BfCB` zp?6e2=;+2oKaX%%Gqm)O(Gu*AU@%+w!*zn#s_k;2h-y$^z+l01VBb89F+&oApfcsF zt52=e=qYbzmp0qYW07rjF%J94h9G4c`Oq1^e*1p+@%GF8=bOupLbY;u=rKG=1QLQ# zTo{?0Jx@oj7K;-ey*LJ*>J+=6MZNTlF;>c#HOb0S78;0Z=>jW+&$_SUJ^5&R@~;^P zI*K9qx|%!(=V7*Rt2%^mE|%Ik=b(lYZb08Lm-U7~hYE{1g?jG#9Jabe+&z-%@8HD) zk)ic8#c%=BZ6$eu7F;ywsO$OhQ+vzADT&f^)`|z91No%bp@V5}r6M^C#IKj`)${5f Dc=q|` literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.modify.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.modify.1.json new file mode 100644 index 0000000000000000000000000000000000000000..5b05485fb50c9dda9b5c57d8f3ebda9652cd17be GIT binary patch literal 806 zcmaJYxH487-9M0+X{jhZVb5aobGLE>11tjUbG>oQ-=ctS$e|BlDoO;ZldC0dXD zp5J?ZSgqHCajsyk!@G5C-oNdoo$)4Gl+u-c+k%GC$@lhZ`OOcl6pZ$GKJ0Kb%`@0n z-fC(^@lTWvJ;mP*BMa7Od_^U2SZ$%ql%mv!zs*x#U)<{7HSXUGa~D;cnvR|TF&OfF zW-`Gezt_=?O<^9Pu4ZWYt{8`~JAyUE!5`uYQe)TULKW4Zz+j?-K#@WVFs1@o3<4%B zmzN(~3_z9O=**zkd6E^Wn?q+fUaoJ1R0$yz4PMNCXms zRa_Vey*p1wo)(LK}}?{Gb2; literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.retrieve.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Customer.retrieve.1.json new file mode 100644 index 0000000000000000000000000000000000000000..2562e0b42201091c14d518df3b3c36079ad89403 GIT binary patch literal 2153 zcmcIlO>Yx15WV+TL_UE;t0uIEaspA1Kole@F0GK|*t1!;UfbB-G@i#IdhI`@i>mdYuw0gsOPzfPbE82mp!?!V5^rUYJZr@;m) z)w&|}GqxPs#QBGk2AuW3TJQyPRmx@H0tT{9HWnK^o{QhDvvKy~ihs^w{Ze#ZHtW!G z=#UT^WgW%Ts&P=>a_Er`O&4P6HlmHIqzuUAR%(@uytAd2p)H24D>L3&a$>2xk&X4X zX&YIEBqIVOi-mM}_`c00G?0!ul#b>{HyOL-#;jilt3k#DmEBOquiw63y!-O$>cjcI zM}|_YU(p!uaRfL7&3R>I!I|lF(9}a5)wV&zWCNuRbfGR3J(P3dP9`umW2-bD(fS-g zTg+#;G#6P~hq$k#fr4<2)!8^QqtDwlW(z00RDSj`AyEkZA!X-6(@5;~<8t4G3Ste~MtsB)5n*nvZC2Afx(0o_k1!3Y+dj## zNcN$-MTHwV_C0Z&fbg8VUh7BZ0feD@%*yP3Vo+j79Qn`dz$VHj_)=rLXJe;=&bOcv z9xsj;rxQzsM1vHQo%LAF_~ zsL)6jOqAOgL+Zq}q!xyX(<$BIIs*ygq|{(1oSsx?zDB1aK;!t|YRC2dgRUkh$-)|@ z%F4BzT|?7}!SG_R0rgO!gewAj#3?LqKog3%U3Yx15WV+TL_UE;t0uIEaspA1Kole@F0GK|*t1!;UfbB-G@i#IdhI`@i>mdYuw0gsOPzfPbE82mp!?!V5^rUYJZr@;m) z)w&|}GqxPs#QBGk2AuW3TJQyPRmx@H0tT{9HWnK^o{QhDvvKy~ihs^w{Ze#ZHtW!G z=#UT^WgW%Ts&P=>a_Er`O&4P6HlmHIqzuUAR%(@uytAd2p)H24D>L3&a$>2xk&X4X zX&YIEBqIVOi-mM}_`c00G?0!ul#b>{HyOL-#;jilt3k#DmEBOquiw63y!-O$>cjcI zM}|_YU(p!uaRfL7&3R>I!I|lF(9}a5)wV&zWCNuRbfGR3J(P3dP9`umW2-bD(fS-g zTg+#;G#6P~hq$k#fr4<2)!8^QqtDwlW(z00RDSj`AyEkZA!X-6(@5;~<8t4G3Ste~MtsB)5n*nvZC2Afx(0o_k1!3Y+dj## zNcN$-MTHwV_C0Z&fbg8VUh7BZ0feD@%*yP3Vo+j79Qn`dz$VHj_)=rLXJe;=&bOcv z9xsj;rxQzsM1vHQo%LAF_~ zsL)6jOqAOgL+Zq}q!xyX(<$BIIs*ygq|{(1oSsx?zDB1aK;!t|YRC2dgRUkh$-)|@ z%F4BzT|?7}!SG_R0rgO!gewAj#3?LqKog3%U31d!x^~5wE}UBtb7`b&kWACT{h#XAz^25Au2~;T zs&FBT$?!Km$(LB`AGD^>X!o~_BVsse2x~V@`*uL&DtnDhD z8eeLvgF|n%V>#Q|2B;C03lQ z@1*70`%e)LR~b4!60#(#VrPTy`_bFLO|T5?Vd>q`^vp2QFexy;kp>y3+aH72wA3LG zlE=Esas{|T8+c5F<06CDjEN*ksUJ4c{rh*&7t}jK$|MCzLxK>0x4I!;!ctBpqqWhm1^I`9+vvpIj1wO9>%d=PSq=dTDUObtos!3Xs h39OIon`5avc?ULzyP_satUL9*ot;-KlQ?@m`wd<#?(hHr literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.2.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.2.json new file mode 100644 index 0000000000000000000000000000000000000000..7a893d89bdd5fcdad0a1f3679d523e4054ff5442 GIT binary patch literal 40639 zcmeHQS&!Vt5q|ft81N|pqFwEJ1=|4v$B=BmiR}bY{9?l(xEzj_5r?FCtRx%$@A;~` ztJx<>ZN_88q8?;7JuW{tS!^~qU+11#>3?L z@%7_Jk3W8N{ZaBK2Fbf38;U(1Up?kO`k@+?$HR!t?SG1V0QB@5&2wzVntr{ZA^3G# zih7jhSv!nfc3TyI3PS9QAuFri85$!DWlKN)qE<|!{t}v^EApbe7h4G|qiw4)&jyK! zdaNpYi0N^9D2h~X$cG$<=7@3fw9Vcei+V_p#c5 zp%=##03+NLY9b7jWV{G{jsn;DUDmxQ0w}bogFxjU^9QsPhaX+lK6l!&vVH zq;>8LHDNx0A|Hs3XEk8_9M!6J#D)XpAfTRpmKe8{H*4Km z{xK!xgZ9(zM^Dvw7jlUgR~P>wHWb(c<3-(n6Lno8qt)Z-A zj8~y&U-s=NNXKP#>WHhHyuZk+BF8vZ14e1_UXl>x-%?I;aUur3v3r z?60kgp|}W-J-lgYR8lMMny&l_oNN^fZ8Jg35uV5TQCSb57#jZ+G{1`ccxtJd(bVm6 zL7>~On0MGi1u<%{TMQc_7(A8QV``u?pcyj_5WK>>R0L;v5xte%LQxP*Wam|CKmC8vfG=@~b3shxLSbXLt*Q;ML^n$go=J&Y+8bGb1+#6V0rTrAI+w|Df z!yR_=Nq7?p!MrIl5}~k&orh=IMC!QV#BK|wlmh*J*2C!-rnlS%9@nN zie@HC3^QP{l`89p8`{Xt_04sJ`jR8aUTT;#BOS*I)|oIjV?15VIGxsmx5vyM%bvT5 zEJ23mWkGg$6yswrbVwmF-wMx=M%{`nAG6m&1yuaWvdKM@nUKVP4AOouvWB}3hBc|B z&~oWyX3p>xh^AnZIe>}a4N6#y3Fhp*6?g{%8ZLu&NZAHS?y@5${_9U;Rkjz9ngL4G zFV*Amc22M0!N*Pr_q$Hg!zB zl4f^||7(BI4QXr{E>EE- zJoS`g;F{3ZuTyTi;=U|iMd>u@@5;87+&4_gN#BeejG`E&tLM`9aG0Z{sC`Ogx_eqR z;~qvnF-K@6{(*|yE7(8O8n$oKemoq?*E6fr(ySlzyePGBa=Xs{Pu zGm<}#;G8>ZdiZubhcXvva-JF;I=r&?k@yt&DXW80dHu^N2-4SFjs08PDaor6B9mBU zC)i+27l22oK9n#T$Z@s8KRDy-C00M{fA}pt59B=%{+N|Mhvam&wSQVB(IjUzsuR+V zw7?HP<&qggSkjz>7Nz}%NRs9-nDR#JeTbX2weG%=s z7tH^J-(6z{I>2z8;by%+$UOougYyHVH4}|-@Igu$VdHyiWQh&)MiKW>!yAy65J=#5 z$>H1x3tg?3tyAUz9+B_xqYPu49!3##86zIQIr$%#{6SGnSM|FkQ679VF2oIuJuJQx zEs-OFdjbfGY!=p9aGizsM%j%a|KUx80nN0Pw6NkqG3l$~_O5A!M?~wPAOdkEh@v&s zon<2+_i|qx+XhaC{7w3@5I%nnz&@gXIDhdo)?O#Xv)#itPwFfe)47YSDR|!JI~N-k zrmts(vM((bMI>kJTLgA-&@O8T;(Zb|*Ax_BtG>ZbI*}XD0xDXY@jad;7 z6i~59U}E_Ch*yPUfRaJcb2s{@DOK%@8MJ#6xDyMpzF3scngMd;e~;{85D|1IH>>O4 zUX14b|Lf87QM)7_uj5CAH_vsDaJVgekz9Jv;1Q3wem+G!{2^u|awlZ(%^<9bV6C? zO<`0l#k(xp5LawI#w8+G(dgDvTno=vN3;y{Ar{N>7r#D!m5?8HK5_-S_-$fV#)4-e z6#kmmSl{!pDK^d_@LcI5j&v~|_0XkH)_yqpq`7N6?v%_#oP1m@MVWw!w~jA8bn~7M zBZ&KW9Ld?8X5wz_$bx%&7lRBhMI%Lez*EMEFlanFq#g$RQ_2nS{SP)LJEh-U+ue#m z`hNE_Mth1xfY& zopAx>G7UAZ-6WX;VF$q95zXwf-B;Od|0krE=62?q1|PE5X&KJFS4j^0kwPI+zmihO zEzZQcDpF>UJ}uRh=m16-*cs%l98>X3^&}exI0{uNFZSY0BcD!*BTUdj`GC6Jq}l$S zlHBpCZ;=y#EN1{J0pV!#MJ@A~0%%hEt$dY%il?~(=+W}b;1f$>;X9+Z&K)x zS%nP5K2kEl{xod_lKM3|Nt2v0>T6_hmLao5gq@6Vsk|+e86|N+E71;Qsh6K1a*Dkb zRhU+PgQRX9&INgJje>iI6AZiT<`ZNlcy*2A1Dfgj7R53uQsZL9hoSplyr$~`+C}~> zN&v#6O^m`;a1dcWWXKrP(N%2>dy_I`G_6CAMUx?LDC1t1KIH_o{W+-oLng~apNVLi zGwO)Us&HmpQXCFM@b@TcA|&}$UV^|?kVHA=0B3WVLxVsCB}{s&I&{r3ot#_V^E=d! zAc;~zq>iGiel`=L%1g+C!N}IV6jANDtf&*Z@#6Z1Kof7H-BZ4K63OXOP)i%R#3+7> zS5o%rx&^tW}9?aMZ22-b%*bAm# zlqdzRJON6NH2^MgUX3D7C*@EKd_{$flQXiYPOF8$&mpxGsW|wz%z+cxutB*f_Qk_R z$2nK3idwd!Nut_cCz;9QyY`%E2?ge?6VD~3sI^5?Q`Gax6;5|RZXvM6w&=15r8DV4k(rEg z#Bj2W1|n65O0e!rSu#1+eOu%uRNYXvC{{sLhm>3_%1NVWk;y42hf04OvwDb`7;+if zc?b0mRgEB5|Ds}MBHoFbK1M#p5*X5D^O7pEz%&Wol)7?iOZKYO0M9aO46k_xmkYC4 zXe8=7NPz+mC0Rl!Tg4v?#0B_H(vP=hYGwE&5<1=mc^FrAozqbgNC*QT^XBn*+CUKd zoPi{#u@qvQ_IwJvkuDTSUSFRstoGEO#Bb^8o|jVnGLGA#w^=@9aTa3)pvL6w`%!dc zNUoea0~SoB$gqp3R9JG@Z(Q>VVl$RBjla?f=YeeA+&Rl#_*PnfJUd5du82M8*?K4l=G#OgGF5~lQa|Uxi>PfDKE>O z*Ptd=v#e2;0_VyJN2Czd)4(LQIXo~23;;}klJ@gqTyR5+^dm1p&KudtCI52!?W;Hqbbeo@#&4tP=-##MankHko?_E08`R} zivg*GgOIs>0LHP86Xb!_6GvqGQuT;fmAEU*LL20wTI@`@NM)F)j3kb;OH_4{2|I9r z`eW9;grYFk?BhfQYS@b^4i=mx*p&tk(ab>QQ&Qq58WR2ETB zhO_b912mN^He2*0kWv#O6Inb_HTlcnQ>tVO&Mc>8dq1i!DWzh?@lVHfJcz4y(=B{AH4B}%Gbz-`fcGmqdltj)d}L;!gsQJ3ePX9E2TPs;p71yw&+I*_|&0%Q;4V;)BZYv6?yCsVfR%%6{SHOUeI`4=gzooUGK5 zEAVvYlq|<0Hs^6DKBm zD>zqaxRY7vuVd@!5h&VGYgZQTeA((rD8=li}$zL z1~G80&#-2rLz`y_{YPt^wl*6(_Ss#$8-c8NhS!{Vt$pohO>&V9p2D4o-r843pNtco zcViuOHGp4?dzMS&_}VH>)@Ki z8mn5}&O&#JY62pk1(@$WHs85+-5xjnLw!MIuJO)XRwG!+uajX;Z2uk6LE>KmiG3J? zb*JcuC1#Zu{-nk#pt&CF@l&UtMIWB(w+Ry!N_LA!+sE%GJ;0TDj{1yMEbGI z#N!FeM3SNlzvXQ<s4ay%iV zv1jalO_7;#ojt{p$;W}2rc(dXQ=UbIiz;u%VHNkpVE90wo6DYC+-egz>% literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.3.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Event.list.3.json new file mode 100644 index 0000000000000000000000000000000000000000..92539b434584bc54102a25c04be52e2b3c62e139 GIT binary patch literal 21085 zcmeHPTW{pH6@JgJ80b0n*j^jE4NxROk^(`~6iCpQ1OdU3I3C5itw=iS1pD9n9bP0+ zq{b-<8wfx@jP2p!A$jf>QGa~0+Z7d8y!dSQGydM~{xF~TmJc<16r-&B4ui$b)y>t# z)w_$Ex5cL(q#OlTqQda?mH(Lr9afJI82iJoqEvvMzoT`^ve%tr=5u_awf^(tv<7Wy z0_k`wX#AhNt46;2jvwTwyKlSlG7YZy2Ub@SGdkTgeq$D6Yu2nZ;k%{1r-lb!)8RJ9 zN73@StGjyuB@xI|Jq*e5VQA`-D@)vXd-E_m3c=7WDL+^k0k>o0kLEoxFR}!XbkFTDn^@{AL^!7#L)HmFf0{U+Ox*V z6LIEav_-Q6-ZW3_Sa-ase;1N*lA<-%0_!y(HiJ}3E3_@|G;c!bC{KL6H)2$t*!Tbb z;a^{V_w7&Le7yqdn+CE9_OMo{Q%_=0*qMxjZque#)6OV_k-Jilqv%Q_bcRg3ZB;+sbZ!DUlRb$N67D_Mv@THJowP#sC&PVN{Gp5O?U9M2tO4=ky} zNU062SEf`w4aOo#(Hx6SYuIoQ%NarAI+z&8o~%K{x`sql!4f{!&Vk1ub!Vh_wUr-<$QJlH+vqS>VyR-qPh_fgUp2k1c0Vex9-z)ZD$ zb&jsE&)i3iK^)-LoZ?3W7oD(6FICuq4PvZ~!;WPZ%!4(=ey`u$y}kO|-Mibn7=evW zMq^Rm+}z#1eRF$zw@^yEOlpHAJp?|meFQ}$`&0H|LAZq7DWpCu z-CLRy1+mw<-c3KY9i*U$bXL`3J{3l zt}sswAODaa-q(YCdOo3h)z4)isoTqi!vsT#M13#VL5(JVUM9&8G{mAucU*C#Il z0-TA=V{>FZMfz(sD_qqls+Z9BlyhJjk|`5LM79KzZLV2&$`KxAw5^SLU@4S>QI9Q7 z;S*Evaw7=@!#x_C-?HAMpx!Voj~>I4nf8zii3~Yo11jbsCn}bipC#tP!Jw>T11Ap@ z=9&XC#wi`Qc9eBUKT*-~6|U8UQT$Kv?=`Tcm%se>{ZbV6R4y|8C>EZi_t}OcIAOW_Du&n zBN>G+$-u(G_9nDq0+_vHL_)*;bF~Jl`WcG^A8TEm4N;y=)D&~mi%LjQ><4R~n_f;M1OI%k zzU1plx#`una6;s&a?`6oUp_azUZI#@kXQeONGmlbc?YTZN5pOPyDW z5Irlrl;psr(Xdd*TnB*{&$=s~I6^vX@I-1IV~ji9iRn_lEX z%=41#R0(aG-1IVz#k8(+)5|&8sX|Zx2TiR+4iSv!rk81E<))X_s;vk9a?=YB(Ze?l`nUtik;JykW>)kA7_ax z=ef^iRPRL|)SVu7F@a|8a~U$^%Uzwym%FwvLE0e6$B((sH3f}S=g567FCMRCwLSGW zA8_;l^gH*t0*~iOllxpoIC7uM3xxlj`&{u00dk)!_qlSPEBColPc!8{7hUbkm%F_G z#P58$D^?VHH4A01`2NUW{c_jb`p08ac(G28JBPTZJk|$|`))Y$vIoBEGEBFtNPPU* z@+M78E_Vfby7In4v3RpvbQ8tBsVr5DbX|{lioHaMDMgRlVL>k8E?=I%U`dG6*Bqy( w@ACDy|MM+XFLymo4|KiUUy1|Aej#a3zOiA^V4dF6uzdf5xoU_vBz*kjzjz?nCQczGzNi0cJvQmhS)dBG`5{u(=^NUh}B58>^#i?My{G_bZ Xv?vE8pkHRFpIVlhS5mCRRm%kck@XgY literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.create.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..957b5e08a3e355488e93b1d1e7003b33854a6e48 GIT binary patch literal 4796 zcmcgwO>Z1G488YPEObunY+@s6Pc7OM2%4rqgI*F8f_6shRjkoW^s%uMwufuf1nKY}j9K*`uY%h(Xf&Z^HCeY+j3SP8Nn}yAQPg>IuH(@+4G`^=8e=K`5il&AAQkpr$Fw@}_ChsuNy~ zra5+A=6fl*h}UQ|yqCk2Up?O;txCGpUT7!NZG#`V=#Rp5^o&+8;P8&)>5zPZ)8J8Q z#7?(1u&R~VDXlztxcCRl&I=!k&#?b%Ju+GrTHo`%GD54*(sAJzyBX|hc!OIhTyy{% zgb6~YuyhAuZ|K71G}et;%Z{AI2k8$ZJ(DFhF7U{DVm1J~KE7j1k&9ovT^FpCri)k! zuFu-R!2<3ob&G*63Z#vP1;^j~@#pV9y?*uXBUEUza1eu* z{>RTjtLdT}hn0;C)%nT!a6TPI(>kL_7N9!aMwpg&1Qj~mkd5|YGw9#{9VNZoi=aK9 z#Qh+VSJl(ic+qfUun|!w5;AJxd-6p!>pH8ZHPU@g52MHO&mXE+= z1a`iU%&^G}5m};gQl&*&CPGe}DepQRVk8o|tkupXVYblAC05uw%9YK}dJO&Mt%o<^ z?dYeXp7D}ta)!-HPOOHvRQ_9uPxgK5Fz54U_Osg+YE5TZQ6sO0u|MZ8 z5Q50C_!8MZZy9$VkdI`QFqDoUG-vT7t%{7Dkd;@Ftk|)AcK!Ux_t!73uICM@wpcQ_ zefISF>iM&)tLtiRc`)S@v2en)%t&shsQh|W)hC$ZJ7A2Y)gLj?*lNvKBKzZRUNA@n?W+g z_%!jJ?AV6{A^P_`G;x5H{ z;IJfvDUV)**sOs*aN8s8QPhz8B&8>xJ!bLXMLseYc1v1rJr>=bnE!-FPrHGY_c8-U zQkp%4$kil457SnY#!Fx0Gh+LKxE=&W)vl$2gzON4Ctg_|k@}`Vgxc+mK}`doXWE<0MC` zEpEVcCQ^27pNo~OM!{s)Wf6_{-eMl{Rwby)6pf0AR5p38lWB;_M8dKR zBUmbvD=B)|+Qp~r=LQWhrm!+jrXh5)@;~W)4A{Ml5qMalrRS%y!g$rA-p468u~2CX zi44&611oJ+VX4;fMr+Dzr>!De=zq#1ss*e8a{i%2+BBSpj0 z0)J(!?%M$fei($k1=9ypCT4WLCrU9Nn$Zb6F$wk9S(mHp9$^2bDx8#_C3WR;ld>Py zBJ;w{buJ)NiH_G~KdYosqIy40F`XW}+hx2?Ehn>O);yULauxWOV`G&d=&nl~i;>xb b;&Mw|@AgUV4rrhpoI+g|s_(+9U%&eYH7%{J literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.finalize_invoice.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.finalize_invoice.1.json new file mode 100644 index 0000000000000000000000000000000000000000..b67cbf845eead46518b2afb495466ca02bf4a46a GIT binary patch literal 4963 zcmcgwU2hdP5Pj!YT=^Mt2_&LLs@kfh5-O!qQC~on<-6;fYvT1T{s;+(|K2nHTJPSQ zwl6dfh^+0gXXebAGx_{rvtgp^#$Y^;|JpnDe8c{H!ydLvMhud^|0+yx#padRxrdvV zraN11^Wv7P-eIQ+S|?g%3Pf~;0|h<(po+=O!vlw8DTEOvM=hbenKzaf2<^s2qkPNvreKXTFE2-A@p%Y^}#cO0%`0M{QLy+R{b3|GS=z=0oUAuy1F-9(ALo?0_!D2(1#6}0 zB36Ry^X}ka0dJLhiGeOINEkKcZL_44hDpWB1dBE-FwuEZkWL`JbjsL*8L zAOka*=^%LzgY7oC z-xC;aP#)ymD#z0F1g)LW8TP5*_T%VdD(h`~i>xbiGpeO8htUB%WrYWu(&zo;o^QAL zz?t)KN>U=XY6~jz4Lr68K>Pdm?mIE1@JHTYVY;%Smwb1}J7IhNQTYQOgC|dW?ttFJ zY8<@92e8Tz0MOC$2~KgZqCg3lTl} z3PeQUL+fIiFg~V~|ZKt>(Tj*sAS@xDncJq@SL%(_B zkrJdV2D@y}u+3~eqj$AV7u&V6mHn(-o+J~7$HZgrfk}nYLxdd z_NU?nUJ@A=pJUU>w#VIj&;nT{45cfmB=Yhkt%{8!AuE3cTj0d`)5~X%zrFnC;&MKa zTAYmx^YqE(#j~du7njvsdodLyj1+X2`)uNs#dRX`7B;UyfXhlxblpKF)q)rEV3cp- zf_>dR%`N+h4JVphvlyElnLQR4b=UucJUDZInrU$yufxQz%bUPdg2Ju&|gj~EHsxID+(RKU8!ccRE{NK&&R0AOC@IHt@aSVlpPf$sgv^D zI@5TSxrOC542P+6u2vzf>wJ+2fg9*@%!g&rO=^9z@;~kS5OBJUHmF%**x)sNH4hm4 zdPsmcpC@7}N|E>h;|SohY&0xs=)z)%-<9MJ<1FC|vmDJ6u^uucUL7)zujNQ$rBV?6KrP(uqq`kGfak&Qm@cCz(eK zvVw8gQ-@MC*EIkv6MuhdHbXE5VXx5xf+-_CH1YC}0}-eypD!-qBj&UoC+i;)YW(i$ z3yXen)RbCMqf1(Ak&_YYIx&!`MAYjxFmFjiMtLui4y1Q_?5^9S9a~Oj%P@R2LFE4M p57);2K?q(qKNj<|2l-{OT;KLl?hcSv4nZOPg}%H_)`Kq({swUL-QoZM literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.1.json new file mode 100644 index 0000000000000000000000000000000000000000..e39960ab7254f5b071e40ef45d6574c984929f3a GIT binary patch literal 83 zcmb>CQczGzNi0cJvQmhS)dBG`5{u(=^NUh}B58>^#i?My{G_bZ Zv?vE8pkHRFpP5&dpP8Imti)Bz1pvYK7f%2H literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.2.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--Invoice.list.2.json new file mode 100644 index 0000000000000000000000000000000000000000..774009d5cf6d60be43d9be6acc322737f772e3a8 GIT binary patch literal 5760 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 Gx%dafaBMgL literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--PaymentMethod.create.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--PaymentMethod.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..fcd9d75d70414c1cb4b366c0ed735dd7a080a2f7 GIT binary patch literal 1098 zcmaJ>!EO^V5WVLsRzA}xyQGJ5t6Gpi6eJ=pAY?iAY}UnVTVp#Riu&)29k0?w5jiDq z<~`56naOF!KF}a|k|nlfK?_uqWEm)GL6malov>b&{Y z4&aaHqqA|KD(@!a2s?s6g1S|AThX5O0??zjF?aOk>$j)-&mVuhf1J$dlU0s%?J z9-#-MBI;u^lj48?T=4)hA@CH$E{mS$OyrQfcSz+D7%{<&e4s0WY`}a~5ORM6x2x%s zi(xW_=tjs^PE9ji)+qTM3I%+7`DS`y0+fPAI&6AEP(i2jn!D{Y$TCtdjw8^E Tlry;chY*jxTueEJ#mnL^#TPd1 literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.create.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..826083c390329adad485ef66ee7c1600f62bd3ed GIT binary patch literal 904 zcmZuwO>f&U487-91Uj!ld)=+TdMMCtz;@eE5R618%JemfY8nLj@1x|VwbS}wSk!yu z<0E}sESCyXa#kbT7}VEgsLp-q;mXlVR71jpr@-Kex6za-NMq3CTqi>&Eb|=N*+wj+ zGqLd0_a8qWZy)Y|-+fcPh{Tb}$komD`57;2k@A!qN!J3GL_{)5svNZbp9 z-PAm;gb{hx&E{}{k9~#>ag?o-b!=mKJIVRAX?O>o-R$r{ypQ?sM0O8n`d6FNyv;<= zCaY_1&M7?awd(aw@*a)55XOf@P1c`@EctxuCKnqvj-VETPli%tq_uHXsag{m+3-%Q S1vgzp90rk8O8e&)r^SDAeIsiC literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.list.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.list.1.json new file mode 100644 index 0000000000000000000000000000000000000000..4b772d80c89cf6da8b8221838e1eb81362d71f89 GIT binary patch literal 1117 zcmaJ=O>f&U487-97&@=%a@}pfb||o|KzG|P5R62}>SW22sAfTs|2|4doY?7_LtyCf z#?CZb0;xIU?k!|n-`t01h5y~8TK{O1w>&Y|p#9c6H9;nf4 za;_GENSJPGX=h7;L^={nzWVm~^!4MHhaaCmsj;D8$Ycawy+8jhU`|4ZVoBCH!D|H! zB^~YX+AysPTQD|~F6hk&wsci_*hDl0>m6u}2DX+v2$@AXGD031bjUIXdIP=nw$DAZ zA;RF$16zuBci)Ng@Zed-T{@e1xmrFKLB>HGrXqwy0mT@~Koi+TN0JC+rhX_|O;P(o zeJ~{NExJTw*wL4C>Q#{!a;U1V=l*)zImW6O_sya;2hdSA~OzN@#WqoTwm7^<7 P?_XB;*ISX);;{G!OpHui literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.retrieve.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--SetupIntent.retrieve.1.json new file mode 100644 index 0000000000000000000000000000000000000000..826083c390329adad485ef66ee7c1600f62bd3ed GIT binary patch literal 904 zcmZuwO>f&U487-91Uj!ld)=+TdMMCtz;@eE5R618%JemfY8nLj@1x|VwbS}wSk!yu z<0E}sESCyXa#kbT7}VEgsLp-q;mXlVR71jpr@-Kex6za-NMq3CTqi>&Eb|=N*+wj+ zGqLd0_a8qWZy)Y|-+fcPh{Tb}$komD`57;2k@A!qN!J3GL_{)5svNZbp9 z-PAm;gb{hx&E{}{k9~#>ag?o-b!=mKJIVRAX?O>o-R$r{ypQ?sM0O8n`d6FNyv;<= zCaY_1&M7?awd(aw@*a)55XOf@P1c`@EctxuCKnqvj-VETPli%tq_uHXsag{m+3-%Q S1vgzp90rk8O8e&)r^SDAeIsiC literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.create.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.create.1.json new file mode 100644 index 0000000000000000000000000000000000000000..3248efa9f42ea968a4b7c5705d3711b4a362e30e GIT binary patch literal 2159 zcmah~$!-)e5WVLsqCRkfX>vu106`=omPiCHAXM_WYtja9c$s8~^6yl++dbWrLCkH+ z?poe^^?ZMFdfJFh!T@;ZRS-!z+q^inS?j0eOlx-wJ~-p}2&C&UE-o0CZGxEB$t9tW z96gTbCwrRWx*o3-!WiOs@uINM}kZn#BrJ8)Tp;;(KQg zLL_inEHwTACXTBDGjsW9K&aIxrptC>1i^_8$S&$?My0}f2U3I%ZdK~R<{0%rZ&uf|J*1CS0TNedtDlj4p$J0Rts|OdXfY& zerVRMf71S!GJVS3SA zCJUtJ>pySP_}aC&WeE>;+m|s>MkG0u4W>0Yzkl=Y;?4W3uV3K$;`;jX>JwbPeHcVq t-sWR!%nIr{^)B)oQ2>go9xj1<^`3rOGyp{j} literal 0 HcmV?d00001 diff --git a/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.list.1.json b/corporate/tests/stripe_fixtures/upgrade_by_card_with_outdated_seat_count_and_minimum_for_plan_tier--checkout.Session.list.1.json new file mode 100644 index 0000000000000000000000000000000000000000..f8607c906e36ec311bab309bc62fe342151ff44e GIT binary patch literal 2574 zcmai0OK%%F48G@A7&`Q{_0-n_L3hyxXwcmT*laIb6ojmyGivpi)x(J!SKG?w31@n1Z3|3QQ0f9f!#gZ7MhKBDI)^vE_%4121EK2gdR5F|v zk;vo&53wZJ7x7ZAGPrG54!x&pltR(h%^dz0rK5<0zu-oog6L9BtO=ogTU9@! zlI=F24<6kST@~90$7`(KX>KA{prkC)Tvn3$*~qq?v}^%E^0;u5c&$Cy1EeldM}P}~ZAcyM zA6e0(OCKHCsag-8@BaSlk3Vn!z4W8hLH7^c;B%v+a%nw(SM zhHHi4_l{-4>LE1MYPc@R7hvhMZLB$SOan!Ojk-MpYqH7QqQr}fKtRcA#-6Me=z*t) z&k!iHnDtWu`x6N6YIu~P0UHD95Z2Tb9*9UuHn^!lOCxn8=2!=<;s(;FynZbj6hG+B z_MWDd__ocU<94_G?n$c(227fxr4}zxEyovIrQ{Jc2^!s-Neoj~aJ70)Q$u?dopdyu z+T_V{k+DtX4T({6BGIp#YqopCR!H~Zna2>@;U2U5@1#rl*#d#@AQ*jGeoEQ`(u6Z2 zP^_ePKbE)@8x_>pdae_Ut4DtF>o9|}Imn0DZHo!VXAD^cux*mq#Uv!WD6tVq0xKyn z=_-WAAwpsaiB3kBmpxG++-zP}U@pR@&SVwp9VtK#+J7CjsoWcu2QwDR;d(3Nc>@#m zKFPpzg^a~4x7R9Hhr*JI(kL8gxh^~8`H?Iog&z75#u?a|IwK1bmE>9JDq6Y None: + hamlet = self.example_user("hamlet") + self.login_user(hamlet) + # New seat count is under the minimum for the plan tier + minimum_for_plan_tier = self.seat_count - 1 + new_seat_count = self.seat_count - 2 + initial_upgrade_request = InitialUpgradeRequest( + manual_license_management=False, + tier=CustomerPlan.TIER_CLOUD_STANDARD, + billing_modality="charge_automatically", + ) + billing_session = RealmBillingSession(hamlet) + _, context_when_upgrade_page_is_rendered = billing_session.get_initial_upgrade_context( + initial_upgrade_request + ) + assert context_when_upgrade_page_is_rendered is not None + assert context_when_upgrade_page_is_rendered.get("seat_count") == self.seat_count + # Change the current and minimum license counts in do_upgrade + with ( + patch( + "corporate.lib.stripe.BillingSession.min_licenses_for_plan", + return_value=minimum_for_plan_tier, + ), + patch("corporate.lib.stripe.get_latest_seat_count", return_value=new_seat_count), + patch( + "corporate.lib.stripe.RealmBillingSession.get_initial_upgrade_context", + return_value=(_, context_when_upgrade_page_is_rendered), + ), + ): + self.add_card_and_upgrade(hamlet) + + customer = Customer.objects.first() + assert customer is not None + stripe_customer_id: str = assert_is_not_none(customer.stripe_customer_id) + # Check that the Charge used the minimum seat count + [charge] = iter(stripe.Charge.list(customer=stripe_customer_id)) + self.assertEqual(8000 * minimum_for_plan_tier, charge.amount) + [upgrade_invoice] = iter(stripe.Invoice.list(customer=stripe_customer_id)) + self.assertEqual( + [8000 * minimum_for_plan_tier], + [item.amount for item in upgrade_invoice.lines], + ) + # Check LicenseLedger has the minimum license count + ledger_entry = LicenseLedger.objects.last() + assert ledger_entry is not None + self.assertEqual(ledger_entry.licenses, minimum_for_plan_tier) + self.assertEqual(ledger_entry.licenses_at_next_renewal, minimum_for_plan_tier) + def test_upgrade_with_tampered_seat_count(self) -> None: hamlet = self.example_user("hamlet") self.login_user(hamlet)