|
6 | 6 | import stripe |
7 | 7 | from dateutil.relativedelta import relativedelta |
8 | 8 | from django.conf import settings |
9 | | -from shared.plan.constants import ( |
10 | | - PlanBillingRate, |
11 | | - TierName, |
12 | | -) |
| 9 | +from shared.plan.constants import PlanBillingRate, TierName |
13 | 10 | from shared.plan.service import PlanService |
14 | 11 |
|
15 | 12 | from billing.constants import REMOVED_INVOICE_STATUSES |
@@ -756,6 +753,75 @@ def create_setup_intent(self, owner: Owner) -> stripe.SetupIntent: |
756 | 753 | customer=owner.stripe_customer_id, |
757 | 754 | ) |
758 | 755 |
|
| 756 | + @_log_stripe_error |
| 757 | + def get_unverified_payment_methods(self, owner: Owner): |
| 758 | + log.info( |
| 759 | + "Getting unverified payment methods", |
| 760 | + extra=dict( |
| 761 | + owner_id=owner.ownerid, stripe_customer_id=owner.stripe_customer_id |
| 762 | + ), |
| 763 | + ) |
| 764 | + if not owner.stripe_customer_id: |
| 765 | + return [] |
| 766 | + |
| 767 | + unverified_payment_methods = [] |
| 768 | + |
| 769 | + # Check payment intents |
| 770 | + has_more = True |
| 771 | + starting_after = None |
| 772 | + while has_more: |
| 773 | + payment_intents = stripe.PaymentIntent.list( |
| 774 | + customer=owner.stripe_customer_id, |
| 775 | + limit=20, |
| 776 | + starting_after=starting_after, |
| 777 | + ) |
| 778 | + for intent in payment_intents.data or []: |
| 779 | + if ( |
| 780 | + intent.get("next_action") |
| 781 | + and intent.next_action |
| 782 | + and intent.next_action.get("type") == "verify_with_microdeposits" |
| 783 | + ): |
| 784 | + unverified_payment_methods.extend( |
| 785 | + [ |
| 786 | + { |
| 787 | + "payment_method_id": intent.payment_method, |
| 788 | + "hosted_verification_url": intent.next_action.verify_with_microdeposits.hosted_verification_url, |
| 789 | + } |
| 790 | + ] |
| 791 | + ) |
| 792 | + has_more = payment_intents.has_more |
| 793 | + if has_more and payment_intents.data: |
| 794 | + starting_after = payment_intents.data[-1].id |
| 795 | + |
| 796 | + # Check setup intents |
| 797 | + has_more = True |
| 798 | + starting_after = None |
| 799 | + while has_more: |
| 800 | + setup_intents = stripe.SetupIntent.list( |
| 801 | + customer=owner.stripe_customer_id, |
| 802 | + limit=20, |
| 803 | + starting_after=starting_after, |
| 804 | + ) |
| 805 | + for intent in setup_intents.data: |
| 806 | + if ( |
| 807 | + intent.get("next_action") |
| 808 | + and intent.next_action |
| 809 | + and intent.next_action.get("type") == "verify_with_microdeposits" |
| 810 | + ): |
| 811 | + unverified_payment_methods.extend( |
| 812 | + [ |
| 813 | + { |
| 814 | + "payment_method_id": intent.payment_method, |
| 815 | + "hosted_verification_url": intent.next_action.verify_with_microdeposits.hosted_verification_url, |
| 816 | + } |
| 817 | + ] |
| 818 | + ) |
| 819 | + has_more = setup_intents.has_more |
| 820 | + if has_more and setup_intents.data: |
| 821 | + starting_after = setup_intents.data[-1].id |
| 822 | + |
| 823 | + return unverified_payment_methods |
| 824 | + |
759 | 825 |
|
760 | 826 | class EnterprisePaymentService(AbstractPaymentService): |
761 | 827 | # enterprise has no payments setup so these are all noops |
@@ -796,6 +862,9 @@ def apply_cancellation_discount(self, owner: Owner): |
796 | 862 | def create_setup_intent(self, owner): |
797 | 863 | pass |
798 | 864 |
|
| 865 | + def get_unverified_payment_methods(self, owner: Owner): |
| 866 | + pass |
| 867 | + |
799 | 868 |
|
800 | 869 | class BillingService: |
801 | 870 | payment_service = None |
@@ -826,6 +895,9 @@ def get_invoice(self, owner, invoice_id): |
826 | 895 | def list_filtered_invoices(self, owner, limit=10): |
827 | 896 | return self.payment_service.list_filtered_invoices(owner, limit) |
828 | 897 |
|
| 898 | + def get_unverified_payment_methods(self, owner: Owner): |
| 899 | + return self.payment_service.get_unverified_payment_methods(owner) |
| 900 | + |
829 | 901 | def update_plan(self, owner, desired_plan): |
830 | 902 | """ |
831 | 903 | Takes an owner and desired plan, and updates the owner's plan. Depending |
|
0 commit comments