11import json
2- from unittest .mock import MagicMock , patch
2+ from unittest .mock import MagicMock , call , patch
33
44import requests
55from django .conf import settings
@@ -1847,6 +1847,7 @@ def test_get_unverified_payment_methods(
18471847 owner = OwnerFactory (stripe_customer_id = "test-customer-id" )
18481848 payment_intent = PaymentIntent .construct_from (
18491849 {
1850+ "id" : "pi_123" ,
18501851 "payment_method" : "pm_123" ,
18511852 "next_action" : {
18521853 "type" : "verify_with_microdeposits" ,
@@ -1860,6 +1861,7 @@ def test_get_unverified_payment_methods(
18601861
18611862 setup_intent = SetupIntent .construct_from (
18621863 {
1864+ "id" : "si_123" ,
18631865 "payment_method" : "pm_456" ,
18641866 "next_action" : {
18651867 "type" : "verify_with_microdeposits" ,
@@ -1872,7 +1874,9 @@ def test_get_unverified_payment_methods(
18721874 )
18731875
18741876 payment_intent_list_mock .return_value .data = [payment_intent ]
1877+ payment_intent_list_mock .return_value .has_more = False
18751878 setup_intent_list_mock .return_value .data = [setup_intent ]
1879+ setup_intent_list_mock .return_value .has_more = False
18761880
18771881 expected = [
18781882 {
@@ -1886,6 +1890,123 @@ def test_get_unverified_payment_methods(
18861890 ]
18871891 assert self .stripe .get_unverified_payment_methods (owner ) == expected
18881892
1893+ @patch ("services.billing.stripe.PaymentIntent.list" )
1894+ @patch ("services.billing.stripe.SetupIntent.list" )
1895+ def test_get_unverified_payment_methods_pagination (
1896+ self , setup_intent_list_mock , payment_intent_list_mock
1897+ ):
1898+ owner = OwnerFactory (stripe_customer_id = "test-customer-id" )
1899+
1900+ # Create 42 payment intents with only 2 having microdeposits verification
1901+ payment_intents = []
1902+ for i in range (42 ):
1903+ next_action = None
1904+ if i in [0 , 41 ]: # First and last have verification
1905+ next_action = {
1906+ "type" : "verify_with_microdeposits" ,
1907+ "verify_with_microdeposits" : {
1908+ "hosted_verification_url" : f"https://verify.stripe.com/pi_{ i } "
1909+ },
1910+ }
1911+ payment_intents .append (
1912+ PaymentIntent .construct_from (
1913+ {
1914+ "id" : f"pi_{ i } " ,
1915+ "payment_method" : f"pm_pi_{ i } " ,
1916+ "next_action" : next_action ,
1917+ },
1918+ "fake_api_key" ,
1919+ )
1920+ )
1921+
1922+ # Create 42 setup intents with only 2 having microdeposits verification
1923+ setup_intents = []
1924+ for i in range (42 ):
1925+ next_action = None
1926+ if i in [0 , 41 ]: # First and last have verification
1927+ next_action = {
1928+ "type" : "verify_with_microdeposits" ,
1929+ "verify_with_microdeposits" : {
1930+ "hosted_verification_url" : f"https://verify.stripe.com/si_{ i } "
1931+ },
1932+ }
1933+ setup_intents .append (
1934+ SetupIntent .construct_from (
1935+ {
1936+ "id" : f"si_{ i } " ,
1937+ "payment_method" : f"pm_si_{ i } " ,
1938+ "next_action" : next_action ,
1939+ },
1940+ "fake_api_key" ,
1941+ )
1942+ )
1943+
1944+ # Split into pages of 20
1945+ payment_intent_pages = [
1946+ type (
1947+ "obj" ,
1948+ (object ,),
1949+ {
1950+ "data" : payment_intents [i : i + 20 ],
1951+ "has_more" : i + 20 < len (payment_intents ),
1952+ },
1953+ )
1954+ for i in range (0 , len (payment_intents ), 20 )
1955+ ]
1956+
1957+ setup_intent_pages = [
1958+ type (
1959+ "obj" ,
1960+ (object ,),
1961+ {
1962+ "data" : setup_intents [i : i + 20 ],
1963+ "has_more" : i + 20 < len (setup_intents ),
1964+ },
1965+ )
1966+ for i in range (0 , len (setup_intents ), 20 )
1967+ ]
1968+
1969+ payment_intent_list_mock .side_effect = payment_intent_pages
1970+ setup_intent_list_mock .side_effect = setup_intent_pages
1971+
1972+ expected = [
1973+ {
1974+ "payment_method_id" : "pm_pi_0" ,
1975+ "hosted_verification_url" : "https://verify.stripe.com/pi_0" ,
1976+ },
1977+ {
1978+ "payment_method_id" : "pm_pi_41" ,
1979+ "hosted_verification_url" : "https://verify.stripe.com/pi_41" ,
1980+ },
1981+ {
1982+ "payment_method_id" : "pm_si_0" ,
1983+ "hosted_verification_url" : "https://verify.stripe.com/si_0" ,
1984+ },
1985+ {
1986+ "payment_method_id" : "pm_si_41" ,
1987+ "hosted_verification_url" : "https://verify.stripe.com/si_41" ,
1988+ },
1989+ ]
1990+
1991+ result = self .stripe .get_unverified_payment_methods (owner )
1992+ assert result == expected
1993+ assert len (result ) == 4 # Verify we got exactly 4 results
1994+
1995+ # Verify pagination calls
1996+ payment_intent_calls = [
1997+ call (customer = "test-customer-id" , limit = 20 , starting_after = None ),
1998+ call (customer = "test-customer-id" , limit = 20 , starting_after = "pi_19" ),
1999+ call (customer = "test-customer-id" , limit = 20 , starting_after = "pi_39" ),
2000+ ]
2001+ setup_intent_calls = [
2002+ call (customer = "test-customer-id" , limit = 20 , starting_after = None ),
2003+ call (customer = "test-customer-id" , limit = 20 , starting_after = "si_19" ),
2004+ call (customer = "test-customer-id" , limit = 20 , starting_after = "si_39" ),
2005+ ]
2006+
2007+ payment_intent_list_mock .assert_has_calls (payment_intent_calls )
2008+ setup_intent_list_mock .assert_has_calls (setup_intent_calls )
2009+
18892010
18902011class MockPaymentService (AbstractPaymentService ):
18912012 def list_filtered_invoices (self , owner , limit = 10 ):
0 commit comments