mirror of
https://github.com/zulip/zulip.git
synced 2025-11-02 04:53:36 +00:00
stripe: Prepare to switch to stripe inline annotations.
https://github.com/stripe/stripe-python/wiki/Inline-type-annotations Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
committed by
Tim Abbott
parent
2c9c105bbb
commit
7a4ca3135d
@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from functools import wraps
|
||||
from typing import Any, Callable, Dict, Generator, Optional, Tuple, TypeVar, Union
|
||||
from typing import Any, Callable, Dict, Generator, Optional, Tuple, TypedDict, TypeVar, Union
|
||||
|
||||
import stripe
|
||||
from django.conf import settings
|
||||
@@ -335,6 +335,7 @@ def catch_stripe_errors(func: Callable[ParamT, ReturnT]) -> Callable[ParamT, Ret
|
||||
# https://stripe.com/docs/api/ruby#error_handling suggests there are additional fields, and
|
||||
# https://stripe.com/docs/error-codes gives a more detailed set of error codes
|
||||
except stripe.error.StripeError as e:
|
||||
assert isinstance(e.json_body, dict)
|
||||
err = e.json_body.get("error", {})
|
||||
if isinstance(e, stripe.error.CardError):
|
||||
billing_logger.info(
|
||||
@@ -1170,8 +1171,10 @@ class RealmBillingSession(BillingSession):
|
||||
def stripe_customer_has_credit_card_as_default_payment_method(
|
||||
stripe_customer: stripe.Customer,
|
||||
) -> bool:
|
||||
assert stripe_customer.invoice_settings is not None
|
||||
if not stripe_customer.invoice_settings.default_payment_method:
|
||||
return False
|
||||
assert isinstance(stripe_customer.invoice_settings.default_payment_method, stripe.PaymentMethod)
|
||||
return stripe_customer.invoice_settings.default_payment_method.type == "card"
|
||||
|
||||
|
||||
@@ -1361,6 +1364,12 @@ def get_plan_renewal_or_end_date(plan: CustomerPlan, event_time: datetime) -> da
|
||||
return billing_period_end
|
||||
|
||||
|
||||
class PriceArgs(TypedDict, total=False):
|
||||
amount: int
|
||||
unit_amount: int
|
||||
quantity: int
|
||||
|
||||
|
||||
def invoice_plan(plan: CustomerPlan, event_time: datetime) -> None:
|
||||
if plan.invoicing_status == CustomerPlan.STARTED:
|
||||
raise NotImplementedError("Plan with invoicing_status==STARTED needs manual resolution.")
|
||||
@@ -1386,7 +1395,7 @@ def invoice_plan(plan: CustomerPlan, event_time: datetime) -> None:
|
||||
for ledger_entry in LicenseLedger.objects.filter(
|
||||
plan=plan, id__gt=invoiced_through_id, event_time__lte=event_time
|
||||
).order_by("id"):
|
||||
price_args: Dict[str, int] = {}
|
||||
price_args: PriceArgs = {}
|
||||
if ledger_entry.is_renewal:
|
||||
if plan.fixed_price is not None:
|
||||
price_args = {"amount": plan.fixed_price}
|
||||
@@ -1536,6 +1545,7 @@ def void_all_open_invoices(realm: Realm) -> int:
|
||||
voided_invoices_count = 0
|
||||
for invoice in invoices:
|
||||
if invoice.status == "open":
|
||||
assert invoice.id is not None
|
||||
stripe.Invoice.void_invoice(invoice.id)
|
||||
voided_invoices_count += 1
|
||||
return voided_invoices_count
|
||||
|
||||
@@ -69,13 +69,16 @@ def handle_checkout_session_completed_event(
|
||||
session.status = Session.COMPLETED
|
||||
session.save()
|
||||
|
||||
assert isinstance(stripe_session.setup_intent, str)
|
||||
stripe_setup_intent = stripe.SetupIntent.retrieve(stripe_session.setup_intent)
|
||||
assert session.customer.realm is not None
|
||||
assert stripe_session.metadata is not None
|
||||
user_id = stripe_session.metadata.get("user_id")
|
||||
assert user_id is not None
|
||||
user = get_active_user_profile_by_id_in_realm(user_id, session.customer.realm)
|
||||
user = get_active_user_profile_by_id_in_realm(int(user_id), session.customer.realm)
|
||||
billing_session = RealmBillingSession(user)
|
||||
payment_method = stripe_setup_intent.payment_method
|
||||
assert isinstance(payment_method, (str, type(None)))
|
||||
|
||||
if session.type in [
|
||||
Session.UPGRADE_FROM_BILLING_PAGE,
|
||||
@@ -124,7 +127,10 @@ def handle_payment_intent_succeeded_event(
|
||||
user = get_active_user_profile_by_id_in_realm(user_id, payment_intent.customer.realm)
|
||||
|
||||
description = ""
|
||||
charge: stripe.Charge
|
||||
for charge in stripe_payment_intent.charges:
|
||||
assert charge.payment_method_details is not None
|
||||
assert charge.payment_method_details.card is not None
|
||||
description = f"Payment (Card ending in {charge.payment_method_details.card.last4})"
|
||||
break
|
||||
|
||||
@@ -163,6 +169,7 @@ def handle_payment_intent_succeeded_event(
|
||||
def handle_payment_intent_payment_failed_event(
|
||||
stripe_payment_intent: stripe.PaymentIntent, payment_intent: PaymentIntent
|
||||
) -> None:
|
||||
assert stripe_payment_intent.last_payment_error is not None
|
||||
payment_intent.status = PaymentIntent.get_status_integer_from_status_text(
|
||||
stripe_payment_intent.status
|
||||
)
|
||||
|
||||
@@ -162,6 +162,7 @@ def generate_and_save_stripe_fixture(
|
||||
stripe_object = mocked_function(*args, **kwargs)
|
||||
except stripe.error.StripeError as e:
|
||||
with open(fixture_path, "w") as f:
|
||||
assert e.headers is not None
|
||||
error_dict = {**vars(e), "headers": dict(e.headers)}
|
||||
f.write(
|
||||
json.dumps(error_dict, indent=2, separators=(",", ": "), sort_keys=True) + "\n"
|
||||
@@ -485,7 +486,7 @@ class StripeTestCase(ZulipTestCase):
|
||||
payment_method: str,
|
||||
stripe_session: Optional[stripe.checkout.Session] = None,
|
||||
) -> None:
|
||||
[checkout_setup_intent] = stripe.SetupIntent.list(limit=1)
|
||||
[checkout_setup_intent] = iter(stripe.SetupIntent.list(limit=1))
|
||||
stripe_setup_intent = stripe.SetupIntent.create(
|
||||
payment_method=payment_method,
|
||||
confirm=True,
|
||||
@@ -495,7 +496,7 @@ class StripeTestCase(ZulipTestCase):
|
||||
usage=checkout_setup_intent.usage,
|
||||
)
|
||||
if stripe_session is None:
|
||||
[stripe_session] = stripe.checkout.Session.list(limit=1)
|
||||
[stripe_session] = iter(stripe.checkout.Session.list(limit=1))
|
||||
stripe_session_dict = stripe_session.to_dict_recursive()
|
||||
stripe_session_dict["setup_intent"] = stripe_setup_intent.id
|
||||
|
||||
@@ -528,7 +529,7 @@ class StripeTestCase(ZulipTestCase):
|
||||
most_recent_event = events_old_to_new[-1]
|
||||
|
||||
def send_last_stripe_webhook_event(self) -> None:
|
||||
[last_event] = stripe.Event.list(limit=1)
|
||||
[last_event] = iter(stripe.Event.list(limit=1))
|
||||
self.send_stripe_webhook_event(last_event)
|
||||
|
||||
def upgrade(
|
||||
@@ -570,7 +571,7 @@ class StripeTestCase(ZulipTestCase):
|
||||
del params[key]
|
||||
|
||||
if talk_to_stripe:
|
||||
[last_event] = stripe.Event.list(limit=1)
|
||||
[last_event] = iter(stripe.Event.list(limit=1))
|
||||
|
||||
upgrade_json_response = self.client_post("/json/billing/upgrade", params)
|
||||
|
||||
@@ -719,6 +720,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(stripe_customer.description, "zulip (Zulip Dev)")
|
||||
self.assertEqual(stripe_customer.discount, None)
|
||||
self.assertEqual(stripe_customer.email, user.delivery_email)
|
||||
assert stripe_customer.metadata is not None
|
||||
metadata_dict = dict(stripe_customer.metadata)
|
||||
self.assertEqual(metadata_dict["realm_str"], "zulip")
|
||||
try:
|
||||
@@ -727,7 +729,7 @@ class StripeTest(StripeTestCase):
|
||||
raise AssertionError("realm_id is not a number")
|
||||
|
||||
# Check Charges in Stripe
|
||||
[charge] = stripe.Charge.list(customer=stripe_customer.id)
|
||||
[charge] = iter(stripe.Charge.list(customer=stripe_customer.id))
|
||||
self.assertEqual(charge.amount, 8000 * self.seat_count)
|
||||
# TODO: fix Decimal
|
||||
self.assertEqual(
|
||||
@@ -736,7 +738,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(charge.receipt_email, user.delivery_email)
|
||||
self.assertEqual(charge.statement_descriptor, "Zulip Cloud Standard")
|
||||
# Check Invoices in Stripe
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
self.assertIsNotNone(invoice.status_transitions.finalized_at)
|
||||
invoice_params = {
|
||||
# auto_advance is False because the invoice has been paid
|
||||
@@ -751,7 +753,7 @@ class StripeTest(StripeTestCase):
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
# Check Line Items on Stripe Invoice
|
||||
[item0, item1] = invoice.lines
|
||||
[item0, item1] = iter(invoice.lines)
|
||||
line_item_params = {
|
||||
"amount": 8000 * self.seat_count,
|
||||
"description": "Zulip Cloud Standard",
|
||||
@@ -883,7 +885,7 @@ class StripeTest(StripeTestCase):
|
||||
# Check Charges in Stripe
|
||||
self.assertFalse(stripe.Charge.list(customer=stripe_customer.id))
|
||||
# Check Invoices in Stripe
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
self.assertIsNotNone(invoice.due_date)
|
||||
self.assertIsNotNone(invoice.status_transitions.finalized_at)
|
||||
invoice_params = {
|
||||
@@ -899,7 +901,7 @@ class StripeTest(StripeTestCase):
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
# Check Line Items on Stripe Invoice
|
||||
[item] = invoice.lines
|
||||
[item] = iter(invoice.lines)
|
||||
line_item_params = {
|
||||
"amount": 8000 * 123,
|
||||
"description": "Zulip Cloud Standard",
|
||||
@@ -1024,6 +1026,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(stripe_customer.description, "zulip (Zulip Dev)")
|
||||
self.assertEqual(stripe_customer.discount, None)
|
||||
self.assertEqual(stripe_customer.email, user.delivery_email)
|
||||
assert stripe_customer.metadata is not None
|
||||
metadata_dict = dict(stripe_customer.metadata)
|
||||
self.assertEqual(metadata_dict["realm_str"], "zulip")
|
||||
try:
|
||||
@@ -1142,7 +1145,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(customer_plan.status, CustomerPlan.ACTIVE)
|
||||
self.assertEqual(customer_plan.next_invoice_date, add_months(free_trial_end_date, 1))
|
||||
self.assertEqual(realm.plan_type, Realm.PLAN_TYPE_STANDARD)
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
invoice_params = {
|
||||
"amount_due": 15 * 80 * 100,
|
||||
"amount_paid": 0,
|
||||
@@ -1157,7 +1160,7 @@ class StripeTest(StripeTestCase):
|
||||
}
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
[invoice_item] = invoice.get("lines")
|
||||
[invoice_item] = iter(invoice.lines)
|
||||
invoice_item_params = {
|
||||
"amount": 15 * 80 * 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -1174,7 +1177,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(invoice_item[key], value)
|
||||
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 1))
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
|
||||
with patch("corporate.lib.stripe.get_latest_seat_count", return_value=19):
|
||||
update_license_ledger_if_needed(realm, add_months(free_trial_end_date, 10))
|
||||
@@ -1185,14 +1188,14 @@ class StripeTest(StripeTestCase):
|
||||
(19, 19),
|
||||
)
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 10))
|
||||
[invoice0, invoice1] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice0, invoice1] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
invoice_params = {
|
||||
"amount_due": 5172,
|
||||
"auto_advance": True,
|
||||
"collection_method": "charge_automatically",
|
||||
"customer_email": "hamlet@zulip.com",
|
||||
}
|
||||
[invoice_item] = invoice0.get("lines")
|
||||
[invoice_item] = iter(invoice0.lines)
|
||||
invoice_item_params = {
|
||||
"amount": 5172,
|
||||
"description": "Additional license (Jan 2, 2013 - Mar 2, 2013)",
|
||||
@@ -1205,7 +1208,7 @@ class StripeTest(StripeTestCase):
|
||||
}
|
||||
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 12))
|
||||
[invoice0, invoice1, invoice2] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice0, invoice1, invoice2] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
|
||||
# Check /billing/ has correct information for fixed price customers.
|
||||
plan.fixed_price = 127
|
||||
@@ -1250,6 +1253,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(stripe_customer.description, "zulip (Zulip Dev)")
|
||||
self.assertEqual(stripe_customer.discount, None)
|
||||
self.assertEqual(stripe_customer.email, user.delivery_email)
|
||||
assert stripe_customer.metadata is not None
|
||||
metadata_dict = dict(stripe_customer.metadata)
|
||||
self.assertEqual(metadata_dict["realm_str"], "zulip")
|
||||
try:
|
||||
@@ -1305,6 +1309,7 @@ class StripeTest(StripeTestCase):
|
||||
)
|
||||
self.assertEqual(stripe_customer.discount, None)
|
||||
self.assertEqual(stripe_customer.email, user.delivery_email)
|
||||
assert stripe_customer.metadata is not None
|
||||
metadata_dict = dict(stripe_customer.metadata)
|
||||
self.assertEqual(metadata_dict["realm_str"], "zulip")
|
||||
try:
|
||||
@@ -1395,7 +1400,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(customer_plan.status, CustomerPlan.ACTIVE)
|
||||
self.assertEqual(customer_plan.next_invoice_date, add_months(free_trial_end_date, 12))
|
||||
self.assertEqual(realm.plan_type, Realm.PLAN_TYPE_STANDARD)
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
invoice_params = {
|
||||
"amount_due": 123 * 80 * 100,
|
||||
"amount_paid": 0,
|
||||
@@ -1410,7 +1415,7 @@ class StripeTest(StripeTestCase):
|
||||
}
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
[invoice_item] = invoice.get("lines")
|
||||
[invoice_item] = iter(invoice.lines)
|
||||
invoice_item_params = {
|
||||
"amount": 123 * 80 * 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -1427,13 +1432,13 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(invoice_item[key], value)
|
||||
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 1))
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 10))
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
|
||||
invoice_plans_as_needed(add_months(free_trial_end_date, 12))
|
||||
[invoice0, invoice1] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice0, invoice1] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
|
||||
@mock_stripe(tested_timestamp_fields=["created"])
|
||||
def test_upgrade_by_card_with_outdated_seat_count(self, *mocks: Mock) -> None:
|
||||
@@ -1450,10 +1455,10 @@ class StripeTest(StripeTestCase):
|
||||
assert customer is not None
|
||||
stripe_customer_id: str = assert_is_not_none(customer.stripe_customer_id)
|
||||
# Check that the Charge used the old quantity, not new_seat_count
|
||||
[charge] = stripe.Charge.list(customer=stripe_customer_id)
|
||||
[charge] = iter(stripe.Charge.list(customer=stripe_customer_id))
|
||||
self.assertEqual(8000 * self.seat_count, charge.amount)
|
||||
# Check that the invoice has a credit for the old amount and a charge for the new one
|
||||
[stripe_invoice] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[stripe_invoice] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(
|
||||
[8000 * new_seat_count, -8000 * self.seat_count],
|
||||
[item.amount for item in stripe_invoice.lines],
|
||||
@@ -1515,7 +1520,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertFalse(CustomerPlan.objects.exists())
|
||||
# Check that we created a Customer in stripe, a failed Charge, and no Invoices or Invoice Items
|
||||
self.assertTrue(stripe_get_customer(stripe_customer_id))
|
||||
[charge] = stripe.Charge.list(customer=stripe_customer_id)
|
||||
[charge] = iter(stripe.Charge.list(customer=stripe_customer_id))
|
||||
self.assertEqual(charge.failure_code, "card_declined")
|
||||
self.assertFalse(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertFalse(stripe.InvoiceItem.list(customer=stripe_customer_id))
|
||||
@@ -1537,7 +1542,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual("/upgrade/", response["Location"])
|
||||
|
||||
[last_event] = stripe.Event.list(limit=1)
|
||||
[last_event] = iter(stripe.Event.list(limit=1))
|
||||
retry_payment_intent_json_response = self.client_post(
|
||||
"/json/billing/session/start_retry_payment_intent_session",
|
||||
{
|
||||
@@ -1601,9 +1606,9 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(ledger_entry.licenses, self.seat_count)
|
||||
self.assertEqual(ledger_entry.licenses_at_next_renewal, self.seat_count)
|
||||
# Check the Charges and Invoices in Stripe
|
||||
[charge0, charge1] = stripe.Charge.list(customer=stripe_customer_id)
|
||||
[charge0, charge1] = iter(stripe.Charge.list(customer=stripe_customer_id))
|
||||
self.assertEqual(8000 * self.seat_count, charge0.amount)
|
||||
[stripe_invoice] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[stripe_invoice] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(
|
||||
[8000 * self.seat_count, -8000 * self.seat_count],
|
||||
[item.amount for item in stripe_invoice.lines],
|
||||
@@ -1683,7 +1688,7 @@ class StripeTest(StripeTestCase):
|
||||
self.assertFalse(CustomerPlan.objects.exists())
|
||||
# Check that we created a Customer in stripe, a failed Charge, and no Invoices or Invoice Items
|
||||
self.assertTrue(stripe_get_customer(stripe_customer_id))
|
||||
[charge] = stripe.Charge.list(customer=stripe_customer_id)
|
||||
[charge] = iter(stripe.Charge.list(customer=stripe_customer_id))
|
||||
self.assertEqual(charge.failure_code, "card_declined")
|
||||
# TODO: figure out what these actually are
|
||||
self.assertFalse(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
@@ -1738,9 +1743,9 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(ledger_entry.licenses, 23)
|
||||
self.assertEqual(ledger_entry.licenses_at_next_renewal, 23)
|
||||
# Check the Charges and Invoices in Stripe
|
||||
[charge0, charge1] = stripe.Charge.list(customer=stripe_customer_id)
|
||||
[charge0, charge1] = iter(stripe.Charge.list(customer=stripe_customer_id))
|
||||
self.assertEqual(8000 * 23, charge0.amount)
|
||||
[stripe_invoice] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[stripe_invoice] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual([8000 * 23, -8000 * 23], [item.amount for item in stripe_invoice.lines])
|
||||
# Check that we correctly populated RealmAuditLog
|
||||
audit_log_entries = list(
|
||||
@@ -1793,8 +1798,8 @@ class StripeTest(StripeTestCase):
|
||||
"license_management": "automatic",
|
||||
},
|
||||
)
|
||||
[hamlet_stripe_session] = stripe.checkout.Session.list(limit=1)
|
||||
[hamlet_payment_intent] = stripe.PaymentIntent.list(limit=1)
|
||||
[hamlet_stripe_session] = iter(stripe.checkout.Session.list(limit=1))
|
||||
[hamlet_payment_intent] = iter(stripe.PaymentIntent.list(limit=1))
|
||||
|
||||
self.login_user(othello)
|
||||
self.upgrade()
|
||||
@@ -1868,7 +1873,7 @@ class StripeTest(StripeTestCase):
|
||||
customer = get_customer_by_realm(get_realm("zulip"))
|
||||
assert customer is not None
|
||||
assert customer.stripe_customer_id is not None
|
||||
[invoice, _] = stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
[invoice, _] = iter(stripe.Invoice.list(customer=customer.stripe_customer_id))
|
||||
self.assertEqual(invoice.total, -1 * charged_amount)
|
||||
stripe_customer = stripe.Customer.retrieve(customer.stripe_customer_id)
|
||||
self.assertEqual(stripe_customer.balance, -1 * charged_amount)
|
||||
@@ -2640,6 +2645,9 @@ class StripeTest(StripeTestCase):
|
||||
|
||||
with patch("corporate.views.billing_page.timezone_now", return_value=self.now):
|
||||
mock_customer = Mock(email=user.delivery_email)
|
||||
mock_customer.invoice_settings.default_payment_method = Mock(
|
||||
spec=stripe.PaymentMethod, type=Mock()
|
||||
)
|
||||
with patch(
|
||||
"corporate.views.billing_page.stripe_get_customer", return_value=mock_customer
|
||||
):
|
||||
@@ -2812,9 +2820,11 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(monthly_plan.next_invoice_date, None)
|
||||
|
||||
assert customer.stripe_customer_id
|
||||
[invoice0, invoice1, invoice2] = stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
[invoice0, invoice1, invoice2] = iter(
|
||||
stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
)
|
||||
|
||||
[invoice_item0, invoice_item1] = invoice0.get("lines")
|
||||
[invoice_item0, invoice_item1] = iter(invoice0.lines)
|
||||
annual_plan_invoice_item_params = {
|
||||
"amount": 5 * 80 * 100,
|
||||
"description": "Additional license (Feb 2, 2012 - Feb 2, 2013)",
|
||||
@@ -2845,7 +2855,7 @@ class StripeTest(StripeTestCase):
|
||||
for key, value in annual_plan_invoice_item_params.items():
|
||||
self.assertEqual(invoice_item1[key], value)
|
||||
|
||||
[monthly_plan_invoice_item] = invoice1.get("lines")
|
||||
[monthly_plan_invoice_item] = iter(invoice1.lines)
|
||||
monthly_plan_invoice_item_params = {
|
||||
"amount": 14 * 8 * 100,
|
||||
"description": "Additional license (Jan 2, 2012 - Feb 2, 2012)",
|
||||
@@ -2865,11 +2875,11 @@ class StripeTest(StripeTestCase):
|
||||
update_license_ledger_if_needed(user.realm, add_months(self.next_month, 1))
|
||||
invoice_plans_as_needed(add_months(self.next_month, 1))
|
||||
|
||||
[invoice0, invoice1, invoice2, invoice3] = stripe.Invoice.list(
|
||||
customer=customer.stripe_customer_id
|
||||
[invoice0, invoice1, invoice2, invoice3] = iter(
|
||||
stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
)
|
||||
|
||||
[monthly_plan_invoice_item] = invoice0.get("lines")
|
||||
[monthly_plan_invoice_item] = iter(invoice0.lines)
|
||||
monthly_plan_invoice_item_params = {
|
||||
"amount": 5 * 7366,
|
||||
"description": "Additional license (Mar 2, 2012 - Feb 2, 2013)",
|
||||
@@ -2886,11 +2896,11 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(monthly_plan_invoice_item[key], value)
|
||||
invoice_plans_as_needed(add_months(self.now, 13))
|
||||
|
||||
[invoice0, invoice1, invoice2, invoice3, invoice4] = stripe.Invoice.list(
|
||||
customer=customer.stripe_customer_id
|
||||
[invoice0, invoice1, invoice2, invoice3, invoice4] = iter(
|
||||
stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
)
|
||||
|
||||
[invoice_item] = invoice0.get("lines")
|
||||
[invoice_item] = iter(invoice0.lines)
|
||||
annual_plan_invoice_item_params = {
|
||||
"amount": 30 * 80 * 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -2977,9 +2987,9 @@ class StripeTest(StripeTestCase):
|
||||
self.assertEqual(annual_plan.invoicing_status, CustomerPlan.DONE)
|
||||
|
||||
assert customer.stripe_customer_id
|
||||
[invoice0, invoice1] = stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
[invoice0, invoice1] = iter(stripe.Invoice.list(customer=customer.stripe_customer_id))
|
||||
|
||||
[invoice_item] = invoice0.get("lines")
|
||||
[invoice_item] = iter(invoice0.lines)
|
||||
annual_plan_invoice_item_params = {
|
||||
"amount": num_licenses * 80 * 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -3001,9 +3011,11 @@ class StripeTest(StripeTestCase):
|
||||
|
||||
invoice_plans_as_needed(add_months(self.now, 13))
|
||||
|
||||
[invoice0, invoice1, invoice2] = stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
[invoice0, invoice1, invoice2] = iter(
|
||||
stripe.Invoice.list(customer=customer.stripe_customer_id)
|
||||
)
|
||||
|
||||
[invoice_item] = invoice0.get("lines")
|
||||
[invoice_item] = iter(invoice0.lines)
|
||||
annual_plan_invoice_item_params = {
|
||||
"amount": num_licenses * 80 * 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -3231,7 +3243,7 @@ class StripeTest(StripeTestCase):
|
||||
stripe_customer = stripe_get_customer(
|
||||
assert_is_not_none(Customer.objects.get(realm=user.realm).stripe_customer_id)
|
||||
)
|
||||
[invoice, _] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice, _] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
invoice_params = {
|
||||
"amount_due": 8000 * 150 + 8000 * 50,
|
||||
"amount_paid": 0,
|
||||
@@ -3244,7 +3256,7 @@ class StripeTest(StripeTestCase):
|
||||
}
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
[renewal_item, extra_license_item] = invoice.lines
|
||||
[renewal_item, extra_license_item] = iter(invoice.lines)
|
||||
line_item_params = {
|
||||
"amount": 8000 * 150,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -3281,7 +3293,7 @@ class StripeTest(StripeTestCase):
|
||||
stripe_customer = stripe_get_customer(
|
||||
assert_is_not_none(Customer.objects.get(realm=user.realm).stripe_customer_id)
|
||||
)
|
||||
[invoice, _, _] = stripe.Invoice.list(customer=stripe_customer.id)
|
||||
[invoice, _, _] = iter(stripe.Invoice.list(customer=stripe_customer.id))
|
||||
invoice_params = {
|
||||
"amount_due": 8000 * 120,
|
||||
"amount_paid": 0,
|
||||
@@ -3294,7 +3306,7 @@ class StripeTest(StripeTestCase):
|
||||
}
|
||||
for key, value in invoice_params.items():
|
||||
self.assertEqual(invoice.get(key), value)
|
||||
[renewal_item] = invoice.lines
|
||||
[renewal_item] = iter(invoice.lines)
|
||||
line_item_params = {
|
||||
"amount": 8000 * 120,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -3818,7 +3830,7 @@ class StripeTest(StripeTestCase):
|
||||
# customer's balance.
|
||||
stripe_customer_id = customer.stripe_customer_id
|
||||
assert stripe_customer_id is not None
|
||||
_, cb_txn = stripe.Customer.list_balance_transactions(stripe_customer_id)
|
||||
_, cb_txn = iter(stripe.Customer.list_balance_transactions(stripe_customer_id))
|
||||
self.assertEqual(cb_txn.amount, -7200)
|
||||
self.assertEqual(
|
||||
cb_txn.description,
|
||||
@@ -3828,7 +3840,7 @@ class StripeTest(StripeTestCase):
|
||||
|
||||
# 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)
|
||||
(invoice,) = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(invoice.amount_due, 7200)
|
||||
|
||||
@mock_stripe()
|
||||
@@ -4736,9 +4748,9 @@ class InvoiceTest(StripeTestCase):
|
||||
invoice_plan(plan, self.now + timedelta(days=400))
|
||||
stripe_cutomer_id = plan.customer.stripe_customer_id
|
||||
assert stripe_cutomer_id is not None
|
||||
[invoice0, invoice1] = stripe.Invoice.list(customer=stripe_cutomer_id)
|
||||
[invoice0, invoice1] = iter(stripe.Invoice.list(customer=stripe_cutomer_id))
|
||||
self.assertIsNotNone(invoice0.status_transitions.finalized_at)
|
||||
[item0, item1, item2] = invoice0.lines
|
||||
[item0, item1, item2] = iter(invoice0.lines)
|
||||
line_item_params = {
|
||||
"amount": int(8000 * (1 - ((400 - 366) / 365)) + 0.5),
|
||||
"description": "Additional license (Feb 5, 2013 - Jan 2, 2014)",
|
||||
@@ -4791,9 +4803,9 @@ class InvoiceTest(StripeTestCase):
|
||||
invoice_plan(plan, self.next_year)
|
||||
stripe_customer_id = plan.customer.stripe_customer_id
|
||||
assert stripe_customer_id is not None
|
||||
[invoice0, invoice1] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[invoice0, invoice1] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(invoice0.collection_method, "send_invoice")
|
||||
[item] = invoice0.lines
|
||||
[item] = iter(invoice0.lines)
|
||||
line_item_params = {
|
||||
"amount": 100,
|
||||
"description": "Zulip Cloud Standard - renewal",
|
||||
@@ -4920,11 +4932,11 @@ class TestSupportBillingHelpers(StripeTestCase):
|
||||
self.upgrade()
|
||||
customer = Customer.objects.first()
|
||||
assert customer is not None
|
||||
[charge] = stripe.Charge.list(customer=customer.stripe_customer_id)
|
||||
[charge] = iter(stripe.Charge.list(customer=customer.stripe_customer_id))
|
||||
self.assertEqual(1200 * self.seat_count, charge.amount)
|
||||
stripe_customer_id = customer.stripe_customer_id
|
||||
assert stripe_customer_id is not None
|
||||
[invoice] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[invoice] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(
|
||||
[1200 * self.seat_count, -1200 * self.seat_count],
|
||||
[item.amount for item in invoice.lines],
|
||||
@@ -4938,11 +4950,11 @@ class TestSupportBillingHelpers(StripeTestCase):
|
||||
attach_discount_to_realm(user.realm, Decimal(25), acting_user=support_admin)
|
||||
with patch("corporate.lib.stripe.timezone_now", return_value=self.now):
|
||||
self.upgrade(license_management="automatic", billing_modality="charge_automatically")
|
||||
[charge, _] = stripe.Charge.list(customer=customer.stripe_customer_id)
|
||||
[charge, _] = iter(stripe.Charge.list(customer=customer.stripe_customer_id))
|
||||
self.assertEqual(6000 * self.seat_count, charge.amount)
|
||||
stripe_customer_id = customer.stripe_customer_id
|
||||
assert stripe_customer_id is not None
|
||||
[invoice, _] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[invoice, _] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual(
|
||||
[6000 * self.seat_count, -6000 * self.seat_count],
|
||||
[item.amount for item in invoice.lines],
|
||||
@@ -4958,7 +4970,7 @@ class TestSupportBillingHelpers(StripeTestCase):
|
||||
invoice_plans_as_needed(self.next_year + timedelta(days=10))
|
||||
stripe_customer_id = customer.stripe_customer_id
|
||||
assert stripe_customer_id is not None
|
||||
[invoice, _, _] = stripe.Invoice.list(customer=stripe_customer_id)
|
||||
[invoice, _, _] = iter(stripe.Invoice.list(customer=stripe_customer_id))
|
||||
self.assertEqual([4000 * self.seat_count], [item.amount for item in invoice.lines])
|
||||
realm_audit_log = RealmAuditLog.objects.filter(
|
||||
event_type=RealmAuditLog.REALM_DISCOUNT_CHANGED
|
||||
|
||||
@@ -51,11 +51,14 @@ CARD_CAPITALIZATION = {
|
||||
|
||||
# Should only be called if the customer is being charged automatically
|
||||
def payment_method_string(stripe_customer: stripe.Customer) -> str:
|
||||
assert stripe_customer.invoice_settings is not None
|
||||
default_payment_method = stripe_customer.invoice_settings.default_payment_method
|
||||
if default_payment_method is None:
|
||||
return _("No payment method on file.")
|
||||
|
||||
assert isinstance(default_payment_method, stripe.PaymentMethod)
|
||||
if default_payment_method.type == "card":
|
||||
assert default_payment_method.card is not None
|
||||
brand_name = default_payment_method.card.brand
|
||||
if brand_name in CARD_CAPITALIZATION:
|
||||
brand_name = CARD_CAPITALIZATION[default_payment_method.card.brand]
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from stripe.webhook import Webhook
|
||||
|
||||
from corporate.lib.stripe import STRIPE_API_VERSION
|
||||
from corporate.lib.stripe_event_handler import (
|
||||
@@ -27,7 +28,7 @@ def stripe_webhook(request: HttpRequest) -> HttpResponse:
|
||||
): # nocoverage: We can't verify the signature in test suite since we fetch the events
|
||||
# from Stripe events API and manually post to the webhook endpoint.
|
||||
try:
|
||||
stripe_event = stripe.Webhook.construct_event(
|
||||
stripe_event = Webhook.construct_event(
|
||||
request.body,
|
||||
request.headers["Stripe-Signature"],
|
||||
stripe_webhook_endpoint_secret,
|
||||
|
||||
Reference in New Issue
Block a user