Skip to content

Commit

Permalink
add end to end ach items
Browse files Browse the repository at this point in the history
  • Loading branch information
suejung-sentry committed Jan 13, 2025
1 parent 058e85f commit fea79e0
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 8 deletions.
9 changes: 9 additions & 0 deletions api/internal/owner/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,17 @@ class StripeCardSerializer(serializers.Serializer):
last4 = serializers.CharField()


class StripeUSBankAccountSerializer(serializers.Serializer):
account_holder_type = serializers.CharField()
account_type = serializers.CharField()
bank_name = serializers.CharField()
last4 = serializers.CharField()
routing_number = serializers.CharField()


class StripePaymentMethodSerializer(serializers.Serializer):
card = StripeCardSerializer(read_only=True)
us_bank_account = StripeUSBankAccountSerializer(read_only=True)
billing_details = serializers.JSONField(read_only=True)


Expand Down
3 changes: 2 additions & 1 deletion api/internal/owner/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ def update_email(self, request, *args, **kwargs):
raise ValidationError(detail="No new_email sent")
owner = self.get_object()
billing = BillingService(requesting_user=request.current_owner)
billing.update_email_address(owner, new_email)
should_propagate = request.data.get("should_propagate_to_payment_methods", False)
billing.update_email_address(owner, new_email, should_propagate_to_payment_methods=should_propagate)
return Response(self.get_serializer(owner).data)

@action(detail=False, methods=["patch"])
Expand Down
3 changes: 3 additions & 0 deletions billing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ def customer_subscription_created(self, subscription: stripe.Subscription) -> No
self._log_updated([owner])

def customer_subscription_updated(self, subscription: stripe.Subscription) -> None:
print("CUSTOMER SUBSCRIPTION UPDATED", subscription)
owners: QuerySet[Owner] = Owner.objects.filter(
stripe_subscription_id=subscription.id,
stripe_customer_id=subscription.customer,
Expand Down Expand Up @@ -408,6 +409,8 @@ def customer_subscription_updated(self, subscription: stripe.Subscription) -> No
)

def customer_updated(self, customer: stripe.Customer) -> None:
print("CUSTOMER UPDATED", customer)

new_default_payment_method = customer["invoice_settings"][
"default_payment_method"
]
Expand Down
6 changes: 3 additions & 3 deletions codecov/settings_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@
"setup", "graphql", "query_cost_threshold", default=10000
)

GRAPHQL_RATE_LIMIT_ENABLED = get_config(
"setup", "graphql", "rate_limit_enabled", default=True
)
GRAPHQL_RATE_LIMIT_ENABLED = get_config("setup", "graphql", "rate_limit_enabled", default=True)

GRAPHQL_RATE_LIMIT_RPM = get_config("setup", "graphql", "rate_limit_rpm", default=300)

Expand Down Expand Up @@ -428,6 +426,8 @@
SHELTER_PUBSUB_PROJECT_ID = get_config("setup", "shelter", "pubsub_project_id")
SHELTER_PUBSUB_SYNC_REPO_TOPIC_ID = get_config("setup", "shelter", "sync_repo_topic_id")

STRIPE_PAYMENT_METHOD_CONFIGURATION_ID = get_config("setup", "stripe", "payment_method_configuration", default=None)

# Allows to do migrations from another module
MIGRATION_MODULES = {
"codecov_auth": "shared.django_apps.codecov_auth.migrations",
Expand Down
8 changes: 8 additions & 0 deletions graphql_api/types/invoice/invoice.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ type Card {
last4: String
}

type BankAccount {
accountHolderType: String
accountType: String
bankName: String
last4: String
routingNumber: String
}

type BillingDetails {
address: Address
email: String
Expand Down
31 changes: 27 additions & 4 deletions services/billing.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,8 @@ def create_checkout_session(self, owner: Owner, desired_plan):
)

session = stripe.checkout.Session.create(
payment_method_configuration=settings.STRIPE_PAYMENT_METHOD_CONFIGURATION_ID,
billing_address_collection="required",
payment_method_types=["card"],
payment_method_collection="if_required",
client_reference_id=str(owner.ownerid),
success_url=success_url,
Expand Down Expand Up @@ -601,7 +601,7 @@ def update_payment_method(self, owner: Owner, payment_method):
)

@_log_stripe_error
def update_email_address(self, owner: Owner, email_address: str):
def update_email_address(self, owner: Owner, email_address: str, should_propagate_to_payment_methods: bool = False):
if not re.fullmatch(r"[^@]+@[^@]+\.[^@]+", email_address):
return None

Expand All @@ -616,6 +616,29 @@ def update_email_address(self, owner: Owner, email_address: str):
f"Stripe successfully updated email address for owner {owner.ownerid} by user #{self.requesting_user.ownerid}"
)

if should_propagate_to_payment_methods:
try:
default_payment_method = stripe.Customer.retrieve(

Check warning on line 621 in services/billing.py

View check run for this annotation

Codecov Notifications / codecov/patch

services/billing.py#L620-L621

Added lines #L620 - L621 were not covered by tests
owner.stripe_customer_id
).invoice_settings.default_payment_method

stripe.PaymentMethod.modify(

Check warning on line 625 in services/billing.py

View check run for this annotation

Codecov Notifications / codecov/patch

services/billing.py#L625

Added line #L625 was not covered by tests
default_payment_method,
billing_details={"email": email_address},
)

stripe.Customer.modify(owner.stripe_customer_id, address=billing_address)
log.info(

Check warning on line 631 in services/billing.py

View check run for this annotation

Codecov Notifications / codecov/patch

services/billing.py#L630-L631

Added lines #L630 - L631 were not covered by tests
f"Stripe successfully updated billing email for payment method {default_payment_method}"
)
except Exception:
log.error(

Check warning on line 635 in services/billing.py

View check run for this annotation

Codecov Notifications / codecov/patch

services/billing.py#L634-L635

Added lines #L634 - L635 were not covered by tests
"Unable to update billing email for payment method",
extra=dict(
payment_method=default_payment_method,
),
)

@_log_stripe_error
def update_billing_address(self, owner: Owner, name, billing_address):
log.info(f"Stripe update billing address for owner {owner.ownerid}")
Expand Down Expand Up @@ -786,14 +809,14 @@ def update_payment_method(self, owner, payment_method):
"""
return self.payment_service.update_payment_method(owner, payment_method)

def update_email_address(self, owner: Owner, email_address: str):
def update_email_address(self, owner: Owner, email_address: str, should_propagate_to_payment_methods: bool = False):
"""
Takes an owner and a new email. Email is a string coming directly from
the front-end. If the owner has a payment id and if it's a valid email,
the payment service will update the email address in the upstream service.
Otherwise returns None.
"""
return self.payment_service.update_email_address(owner, email_address)
return self.payment_service.update_email_address(owner, email_address, should_propagate_to_payment_methods)

def update_billing_address(self, owner: Owner, name: str, billing_address):
"""
Expand Down

0 comments on commit fea79e0

Please sign in to comment.