Commit Graph

223 Commits

Author SHA1 Message Date
Eeshan Garg a808f02a22 billing/sponsorship: Allow blank organization URLs.
We ran into a bug in production caused by two issues:
- Some users came from orgs that didn't have a website and since
  the URL field was required, they submitted invalid URLs.
- We didn't properly respond to invalid form submissions, which
  led to UnboundLocalError exceptions in another part of the
  code.

This commit solves this by doing the following:
- We now allow blank URLs and have a convenient placeholder text
  label that tells users that they may leave the URL field blank.
- This commit refactors the code such that invalid form submissions
  result in an informative error message about what exactly went
  wrong.
2021-08-19 03:08:17 -07:00
Anders Kaseorg 4206e5f00b python: Remove locally dead code.
These changes are all independent of each other; I just didn’t feel
like making dozens of commits for them.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2021-08-19 01:51:37 -07:00
Anders Kaseorg 9756ac0db7 test_stripe: Convert NamedTuple to dataclass.
The locally defined NamedTuple was triggering a mypy caching bug
(https://github.com/python/mypy/issues/10913), and we don’t use the
tuple behavior anyway.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2021-08-02 21:43:51 -07:00
Anders Kaseorg ad5f0c05b5 python: Remove default "utf8" argument for encode(), decode().
Partially generated by pyupgrade.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2021-08-02 15:53:52 -07:00
Mateusz Mandera a3cd3d6865 bots: Pass realm to get_system_bot calls in stripe. 2021-07-26 15:33:13 -07:00
PIG208 91de2cbe03 typing: Avoid scoped redefinition of different types.
Mypy doesn't allow redefinition of a variable using a different type
within the same scope.
https://github.com/python/mypy/issues/1174
2021-07-26 15:09:07 -07:00
PIG208 d2af20eb2a typing: Do explicit type conversion when appropriate.
When calling some functions or assigning values to certain attributes,
the arguments/right operand do not match the exact type that the
functions/attributes expect, and thus we fix that by converting types
beforehand.
2021-07-26 15:09:07 -07:00
PIG208 7d1c475f69 typing: Use assertions for function arguments.
Utilize the assert_is_not_None helper to eliminate errors of
'Argument x to "Foo" has incompatible type "Optional[Bar]"...'
2021-07-26 14:48:45 -07:00
PIG208 66b1a4e7ca backend: Add None-checks with assertions and if-elses.
This fixes a batch of mypy errors of the following format:
'Item "None" of "Optional[Something]" has no attribute "abc"'
2021-07-24 15:00:21 -07:00
PIG208 de2678a319 tests: Fix missed mypy errors in tests.
This fixes a batch of mypy errors of the following format:
'Item "None" of "Optional[Something]" has no attribute "abc"
as a follow-up for 9892951703.
2021-07-24 14:59:19 -07:00
PIG208 495a8476be tests: Use assertion to enforce None-checks in tests.
This fixes a batch of mypy errors of the following format:
'Item "None" of "Optional[Something]" has no attribute "abc"

Since we have already been recklessly using these attritbutes
in the tests, adding assertions beforehand is justified presuming
that they oughtn't to be None.
2021-07-24 09:54:21 -07:00
Vishnu KS 158cec84ec stripe: Upgrade stripe API to 2020-08-27 version.
This upgrades the Stripe API to the most recent version. Going through
the Git history, it looks like our current API version is at 2019-03-14.

The API version should be manually changed in Stripe dashboard at the same
time as the commit is deployed in production.

Backward incompatible changes that are relevant to our codebase between
(2019-03-14, 2020-08-27].
* 2020-08-27 - The `sources` property on Customers is no longer included by
  default.
* 2020-03-02 - Nothing applicable
* 2019-12-03 - The `id` field of all invoice line items have changed and are
  now prefixed
  with `il_`. We only rely on this while we normalize the fixtures.
* 2019-11-05 - Nothing applicable
* 2019-10-17 - The `billing` attribute on invoices, subscriptions, and
  subscription schedules is renamed to`collection_method`. The invoice
  change is the one that is relevant to us.
* The customer object’s `account_balance` value has been renamed to
  `balance`. Only used for the stubs at the moment.
* 2019-10-08 - Nothing applicable
* 2019-09-09 - Nothing applicable
* 2019-08-14 - Nothing applicable
* 2019-05-16 - Nothing applicable

https://stripe.com/docs/upgrades

Also normalize the following IDs in stripe fixtures

* price_[A-Za-z0-9]{24}
* prod_[A-Za-z0-9]{14}
* pi_[A-Za-z0-9]{24}
* il_[A-Za-z0-9]{24}
2021-07-23 21:44:41 -07:00
Vishnu KS 50950de24c billing: Void open invoices of small realms without an active plan.
Previously, we only downgraded and voided small organizations behind
payments only if they had an active plan.

This left us with a bunch of invoices from small realms which used to
have an active plan. It doesn't make much sense for us to get these
realms to pay the invoices so we have decided to just void them. This
commit voids the open invoices of all the small realms without an active
plan and has the last invoice open. Unlike, the realms with an active
plan we don't email them about us voiding the invoice. It's not super
obvious whether Stripe sends an email to the customer when the Invoice
is voided. But they do get the message that the invoice is voided if
they try to pay the invoice through the hosted invoice page.
2021-07-22 17:56:35 -07:00
Vishnu KS 7e51fe31f3 tests: Generate invoices inside create_realm helper function.
To minimize the code duplication.
2021-07-22 17:56:35 -07:00
Vishnu KS 292932f3a4 tests: Use expected values list for avoiding duplicate code.
This avoid some duplicate code as well as improve the readability since
before we were checking for the expected values far away from the
definition of realm. Now we define the expected values right after the
realm definition which improves the code readability.
Also, this get removes the postfixing of realm variable names with numbers.
The postfixing is kind of mess since if we want add any new realm in between
the realms we need to renumber a lot of realm variables.
2021-07-22 17:56:35 -07:00
Vishnu KS eee02a3403 billing: Create customer_has_last_n_invoices_open function.
An additional check for whether customer.stripe_customer_id is
None is added to the function. That check was not really required before
since all the customers with a plan also have a valid value for
stripe_customer_id. So all the calls to stripe.Invoice.list would have
non None value for customer argument.

Even though that is the case, mypy should still have complained about
the possibility of customer.stripe_customer_id being None when passed to
stripe.Invoice.list as customer paramater since mypy don't know that
customers with a plan will always have a non empty value for
stripe_customer_id. Our stripe stubs expect a non empty value for
the customer parameter of stripe.Invoice.list. This is despite the
fact that stripe.Invoice.list can actually be called with customer set
to None. This returns the invoices from the entire organization.
Though, we still decided to ensure that the value of customer should be
non empty since there is no reason for us to ever call this function
with customer set to None. You can just call the function wuthout the
customer argument instead. So this requirement of a non None customer
paramater is useful for catching bugs.

The reason mypy didn't complain was because the type of
Customer.objects.all() is Any and not QuerySet[Customer]. So mypy has no
idea that customer.stripe_customer_id can be theoratically None even
though it was not possible in this [articular case as explained before.
I verified that this was the reason mypy didn't complain by using the
reveal_type function on Customer.objects.all() and the customer object.
After the refactoring it's super to obvious to mypy that the type of the
customer is Customer since it's mentioned in the function defintion. So it
was able to complain about the possibility of customer.stripe_customer_id
being None after the refactoring.
2021-07-22 17:56:35 -07:00
Vishnu KS 55a9a019a0 billing: Split views into upgrade and billing page views.
This is a prep commit for the Stripe checkout migration.

The Stripe migration commit adds a lot of new view functions. Keeping
all of the views in one view file makes it super hard for readbability.
So creating a new views folder and splitting the existing view file into
two so that we minimize the changes in the big migration commit.
2021-07-20 14:43:39 -07:00
Eeshan Garg 0ac7d7d21d corporate: Store sponsorship request data in the database.
We are starting to run into situations where this data could be
quite useful for making future decisions, so it makes to store it
in the database, not just in an email.
2021-07-15 10:31:03 -07:00
Tim Abbott c804ab27d5 actions: Rename do_activate_user to do_activate_mirror_dummy_user.
This function had a confusing name, which could result in someone
using it unintentionally when they meant do_reactivate_user.

We also add docstrings for both functions.
2021-07-08 17:33:17 -07:00
Vishnu KS 19b25b3fa3 billing tests: Remove unnecessary orjson.dumps of params.
This should have been in https://github.com/zulip/zulip/pull/18066.

The reason, the tests were not failing inspite of the params being
json encoded was because pretty much all these tests did not test
the functionality of the endpoint. Rather they were testing things
like whether the user has the right to access the endpoint and all.
So the value of the params did not matter.

The only one test which is an exception is test_replace_payment_source.
Even though a json encoded token was passed to an endpoint that
expecteda string, the test continued to work becausethe fixtures were
not updated for the test in that PR, so instead of sending an incorrect
json encoded token to stripe endpoint it was sending the correct string
token. Now that we removed the json.dumps of token, we no longer have to
update the fixtures.

I have run the tests with --generate-stripe-fixtures set to True and all
the tests are passing. Not including the fixture changes since the tests
conntinue to work the same with both the existing and new fixtures.
2021-07-05 18:06:13 -07:00
Vishnu KS ee0d375f81 billing tests: Don't use UserProfile.objects.filter for fetching users. 2021-07-05 18:05:48 -07:00
Vishnu KS 731eda8abe billing tests: Set email visibility to EMAIL_ADDRESS_VISIBILITY_NOBODY.
Billing system uses delivery_email instead of email. We used to make
the email address visible to everyone in tests which means the value
of email and delivery_email is the same. This commit disables that
so that we can distinguish between email and delivery_email in tests.
2021-07-05 18:05:48 -07:00
PIG208 72f9f964a1 billing: Refactor BillingError to subclass JsonableError.
This lets us remove unnecessary BillingError to json_error conversion
code.
2021-07-05 10:43:49 -07:00
Vishnu KS e0f5fadb79 billing: Downgrade small realms that are behind on payments.
An organization with at most 5 users that is behind on payments isn't
worth spending time on investigating the situation.

For larger organizations, we likely want somewhat different logic that
at least does not void invoices.
2021-07-02 13:19:12 -07:00
Vishnu KS e64296b3e9 stripe: Create get_all_invoices function.
stripe.Invoice.list by default would only get 10 invoices at a
time. So a function like this would be really handy if we have
to go through a lot of invoices.

This also means void_all_open_invoices used to void only the last
10 invoices. The main reason we implemented this function was to
void the invoices generated by realms on free trial so I don't
think there were cases where we had to void realms with more than
10 invoices.
2021-07-02 12:04:41 -07:00
Vishnu KS 1d579ec567 billing: Fix the type annotation of Customer.stripe_customer_id.
This also fixes a bug in void_all_open_invoices function. If a realm
with a local Customer object but without an associated stripe.Customer
is passed to void_all_open_invoices, then the function will end up
voiding the last 10 invoices created by billing system instead of voiding
no invoices at all. This is because stripe.Invoice.list(customer=None)
return last 10 invoices across all customers.

But this bug won't cauuse any issue in production since
void_all_open_invoices can be only invoked from /support page. And we
show the option to void invoices in support page only if the realm
has a paid plan. And it's not really possible for a realm to have
a paid plan without having an associated stripe_customer_id. Plus I
went through the void events in stripe stream since the PR to add
void invoices was merged and there does not seems to be any suspicious
events.
2021-07-02 12:04:41 -07:00
Vishnu KS 127d3de125 billing fixtures: Normalize account_name values in fixtures. 2021-07-02 12:04:41 -07:00
Vishnu KS 1eb83cbadc billing: Create is_sponsored_realm function. 2021-06-14 16:49:53 -07:00
Vishnu KS cdf683e36f billing: Create customer_has_credit_card_as_default_source function. 2021-06-14 16:49:53 -07:00
Vishnu KS f55dbe33bb billing: Create is_realm_on_free_trial helper function. 2021-06-14 16:49:53 -07:00
Vishnu KS 40ab415005 activity: Show effective rate of realms in /activity page. 2021-06-11 07:41:02 -07:00
Vishnu KS 7197c8ae89 test_classes: Create helper function for subscribing realm to manual plan. 2021-06-09 17:42:38 -07:00
Abhijeet Prasad Bodas 352634a851 tests: Consistently use assert_length helper.
This helper does some nice things like printing out
the data structure incase of failure.
2021-05-19 11:55:56 -07:00
Vishnu KS 5ad50b19cb billing: Show billing email in /billing page. 2021-05-18 17:46:38 -07:00
Vishnu KS e019045abe actions: Create send_message_to_signup_notification_stream. 2021-05-14 15:10:02 -07:00
Vishnu KS 13cf34f283 billing: Add test for billing page when the plan is scheduled for downgrade. 2021-05-14 15:10:02 -07:00
Vishnu KS 323ad83d98 billing: Allow updating licenses of plans on manual license management. 2021-05-14 15:10:02 -07:00
Vishnu KS 20d2e00cf9 billing: Create update_license_ledger_for_manual_plan. 2021-05-14 15:10:02 -07:00
Vishnu KS 611866e3d6 billing: Create CustomerPlan.licenses_at_next_renewal function. 2021-05-14 15:10:02 -07:00
Vishnu KS 922cfac689 billing: Create CustomerPlan.licenses function. 2021-05-14 15:10:02 -07:00
Vishnu KS 878dcd95d0 billing: Call make_end_of_cycle_updates_if_needed before plan is updated. 2021-05-14 15:10:02 -07:00
Vishnu KS c9f4439850 billing: Extract out validate_licenses function. 2021-05-14 15:10:02 -07:00
Vishnu KS d9baa681b2 billing: Use PATCH request for changing plan status.
I think it's much more cleaner to use PATCH request on
/json/billing/plan than using a POST request on
/json/billing/plan/change to update the plan.
2021-05-14 15:10:02 -07:00
Vishnu KS d88f1103b7 corporate: Use check_int_in in change_plan_status. 2021-05-07 09:37:41 -07:00
Vishnu KS 752fd2e2d1 corporate: Fix string encoding in billing and sponsorship endpoints. 2021-05-07 09:37:40 -07:00
Siddharth Asthana 80c9243c6a support: Create RealmAuditLog when updating sponsorship status. 2021-04-03 08:01:46 -07:00
Siddharth Asthana 233c4d520c support: Create RealmAuditLog when updating billing_method.
This commit also makes acting_user as a mandantory argument and fixes
the tests accordingly.
2021-04-03 08:01:46 -07:00
Siddharth Asthana 44c34cb39a support: Create RealmAuditLog when approving sponsorship. 2021-04-03 08:01:46 -07:00
Siddharth Asthana 6945ed3587 support: Pass acting_user to attach_discount_to_realm. 2021-04-03 08:01:46 -07:00
Siddharth Asthana c3f37c2a64 support: Pass acting_user to do_change_plan_type.
acting_user is now a mandatory field, so wherever this function is used,
we are passing acting_user as well.
2021-04-03 08:01:46 -07:00