Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.

Commit 8294d4c

Browse files
authored
[WIP] marcidy/quick fix customer (#32)
* adding customer retrieval and charge by customer, not token * logging.warn deprecation fix * adding test coverage for customer retrieval issue * guarding against null email * whoops, param swap
1 parent 59516d9 commit 8294d4c

File tree

4 files changed

+65
-17
lines changed

4 files changed

+65
-17
lines changed

donate/routes.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ def get_donation_params(form):
5555
charges = [charge for charge
5656
in form.getlist('charge[amount]')
5757
if charge not in ["", "other", ' ']]
58+
59+
if form['donor[email]'] == '':
60+
raise KeyError('email')
61+
5862
ret = {
5963
'charge': charges[0],
6064
'email': form['donor[email]'],
@@ -155,14 +159,19 @@ def donation():
155159
flash(msg)
156160
return redirect('/index#form')
157161
except se.RateLimitError as error:
158-
app.logger.warn("RateLimitError hit!")
162+
app.logger.warning("RateLimitError hit!")
159163
flash("Rate limit hit, please try again in a few seconds")
160164
return redirect('/index#form')
161165
except se.StripeError as error:
162166
app.logger.error("StripeError: {}".format(error))
163167
flash("Unexpected error, please check data and try again."
164168
" If the error persists, please contact Noisebridge support")
165169
return redirect('/index#form')
170+
except ValueError as error:
171+
app.logger.error("ValueError: {}".format(error))
172+
flash("Unexpected error, please check data and try again."
173+
" If the error persists, please contact Noisebridge support")
174+
return redirect('/index#form')
166175
# TODO log request data, make sure charge failed
167176

168177
if params['recurring']:

donate/vendor/stripe.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ def create_charge(recurring, cc_token, amount_in_cents,
4040
if recurring:
4141
charge = charge_monthly(
4242
cc_token,
43-
amount_in_cents,
4443
email,
44+
amount_in_cents,
4545
description)
4646

4747
else:
4848
charge = charge_once(
4949
cc_token,
50+
email,
5051
amount_in_cents,
5152
description)
5253

@@ -92,37 +93,46 @@ def create_plan(amount, currency, interval):
9293
return {'plan_id': plan}
9394

9495

95-
def charge_monthly(cc_token, amount_in_cents, email, description):
96+
def charge_monthly(cc_token, email, amount_in_cents, description):
9697
"""creates a recurring charge, in this case hard coded to the defaults
9798
in 'get_plan' which is USD and monthly.
9899
"""
99100
customer = get_customer(cc_token=cc_token, email=email)
100101
plan = get_plan(amount_in_cents)
101102

102103
with stripe_api() as api:
103-
subscription = stripe.Subscription.create(
104+
subscription = api.Subscription.create(
104105
customer=customer['customer_id'],
105106
items=[{'plan': plan['plan_id']}])
106107

107108
return {**customer, **plan, 'subscription_id': subscription.id}
108109

109110

110-
def charge_once(cc_token, amount_in_cents, description):
111+
def charge_once(cc_token, email, amount_in_cents, description):
111112
""" Returns the id of a one-off charge"""
113+
customer = get_customer(cc_token=cc_token, email=email)
112114
with stripe_api() as api:
113115
charge = api.Charge.create(
114116
amount=amount_in_cents,
115117
currency='usd',
116118
description=description,
117-
source=cc_token)
119+
customer=customer['customer_id'])
118120

119121
return {'charge_id': charge.id, 'customer_id': charge.customer}
120122

121123

122124
def get_customer(cc_token, email):
123125
with stripe_api() as api:
124-
customer = api.Customer.create(
125-
source=cc_token,
126-
email=email)
126+
customer_list = api.Customer.list(email=email)
127+
128+
if len(customer_list) == 0:
129+
with stripe_api() as api:
130+
customer = api.Customer.create(
131+
source=cc_token,
132+
email=email)
133+
elif len(customer_list) == 1:
134+
customer = customer_list.data[0]
135+
elif len(customer_list) > 1:
136+
raise ValueError("More than one customer for: {}".format(email))
127137

128138
return {'customer_id': customer.id}

tests/test_stripe.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,34 @@ def test_stringify_stripe_error():
3838
assert msg == "An unexpected error occured processing your payment request"
3939

4040

41-
@patch('donate.vendor.stripe.stripe.Charge')
42-
def test_create_onetime_charge(charge):
41+
@patch('donate.vendor.stripe.stripe.Charge.create')
42+
@patch('donate.vendor.stripe.stripe.Customer.list')
43+
@patch('donate.vendor.stripe.stripe.Customer.create')
44+
def test_create_onetime_charge(customer_create, customer_list, charge):
4345

4446
tok = "token"
47+
4548
amt = 10000
4649
desc = "lasers"
47-
charge_id = stripe_utils.charge_once(tok, amt, desc)
50+
customer_list.return_value = []
51+
m = Mock
52+
m.id = "test_customer"
53+
customer_create.return_value = m
54+
55+
charge_id = stripe_utils.charge_once(tok, email, amt, desc)
4856

49-
assert charge.create.called
50-
charge.create.assert_called_with(amount=amt,
51-
currency="usd",
52-
description=desc,
53-
source=tok)
57+
assert charge.called
58+
assert customer_create.called
59+
customer_create.called_with(source=tok, email=email)
60+
charge.assert_called_with(amount=amt, currency='usd',
61+
description=desc,
62+
customer="test_customer")
63+
64+
customer_list.return_value = [Mock(data=m)]
65+
assert charge.called
66+
charge.assert_called_with(amount=amt, currency='usd',
67+
description=desc,
68+
customer="test_customer")
5469

5570

5671
@patch('donate.vendor.stripe.create_plan')
@@ -91,6 +106,7 @@ def test_get_plan(plan, create_plan):
91106
plan = stripe_utils.get_plan(amt, ccy, interval)
92107
assert plan['plan_id'] == 10
93108

109+
94110
@patch('donate.vendor.stripe.stripe.Plan')
95111
def test_create_plan(plan):
96112

tests/test_views.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ def test_get_donation_params(testapp, test_form):
160160
assert result['project_select'] == form.vals['project_select']
161161

162162

163+
def test_get_donation_params_error(testapp, test_form):
164+
app = testapp
165+
form = test_form
166+
form.vals["donor[email]"] = ''
167+
with pytest.raises(KeyError):
168+
get_donation_params(form)
169+
170+
163171
@pytest.mark.usefixtures('test_db_project')
164172
def test_model_stripe_data(testapp, test_form, db):
165173
app = testapp
@@ -238,3 +246,8 @@ def test_donation_post(flash, create_charge, get_params, testapp,
238246

239247
create_charge.return_value = {'charge_id': 0, 'customer_id': 1}
240248
response = app.post("/donation", data=test_form, follow_redirects=True)
249+
250+
create_charge.side_effect = ValueError("[email protected]")
251+
response = app.post("/donation", data=test_form)
252+
assert response.status_code == 302
253+

0 commit comments

Comments
 (0)