From 72c187f95aef5ceae409a97d5d19cc36207f9b2f Mon Sep 17 00:00:00 2001 From: Caitlin Johnson Date: Thu, 16 Jul 2015 16:27:23 -0700 Subject: [PATCH 1/3] Add top-level dispute methods. --- bin/stripe | 17 ++++++++++ stripe/__init__.py | 3 +- stripe/resource.py | 11 ++++++- stripe/test/helper.py | 6 ++++ stripe/test/test_resources.py | 62 ++++++++++++++++++++++++++++++++++- 5 files changed, 96 insertions(+), 3 deletions(-) diff --git a/bin/stripe b/bin/stripe index b85a83e5c..ff3e945d2 100755 --- a/bin/stripe +++ b/bin/stripe @@ -159,6 +159,14 @@ class CustomerClient(CreateableAPIResourceClient, UpdateableAPIResourceClient, url = self.instance_url() + '/subscription' self.logged_curl('delete', url, params) +class DisputeClient(CreateableAPIResourceClient, ListableAPIResourceClient, + UpdateableAPIResourceClient): + client_for = stripe.Dispute + + def close(self): + url = self.instance_url() + '/close' + self.logged_curl('post', url, {}}) + class InvoiceClient(CreateableAPIResourceClient, ListableAPIResourceClient, UpdateableAPIResourceClient): client_for = stripe.Invoice @@ -204,6 +212,8 @@ def main(): 'charges' : ChargeClient, 'customer' : CustomerClient, 'customers' : CustomerClient, + 'dispute' : Dispute, + 'disputes' : Dispute, 'invoice' : InvoiceClient, 'invoices' : InvoiceClient, 'invoiceitem' : InvoiceItemClient, @@ -250,6 +260,13 @@ customer update_subscription cancel_subscription +dispute + all + close + create + retrieve + update + invoice all retrieve diff --git a/stripe/__init__.py b/stripe/__init__.py index 3d564deae..ef4f77cc4 100644 --- a/stripe/__init__.py +++ b/stripe/__init__.py @@ -18,7 +18,8 @@ Account, Balance, BalanceTransaction, BankAccount, Card, Charge, Customer, Invoice, InvoiceItem, Plan, Token, Coupon, Event, Transfer, Recipient, FileUpload, - ApplicationFee, Subscription, BitcoinReceiver, BitcoinTransaction) + ApplicationFee, Subscription, BitcoinReceiver, BitcoinTransaction, + Dispute) # Error imports. Note that we may want to move these out of the root # namespace in the future and you should prefer to access them via diff --git a/stripe/resource.py b/stripe/resource.py index 77a6f8198..b6201515f 100644 --- a/stripe/resource.py +++ b/stripe/resource.py @@ -17,7 +17,7 @@ def convert_to_stripe_object(resp, api_key, account): 'fee_refund': ApplicationFeeRefund, 'bitcoin_receiver': BitcoinReceiver, 'bitcoin_transaction': BitcoinTransaction, - 'transfer_reversal': Reversal} + 'transfer_reversal': Reversal, 'dispute': Dispute} if isinstance(resp, list): return [convert_to_stripe_object(i, api_key, account) for i in resp] @@ -525,6 +525,15 @@ def mark_as_safe(self, idempotency_key=None): return self +class Dispute(CreateableAPIResource, ListableAPIResource, + UpdateableAPIResource): + def close(self, idempotency_key=None): + url = self.instance_url() + '/close' + headers = populate_headers(idempotency_key) + self.refresh_from(self.request('post', url, {}, headers)) + return self + + class Customer(CreateableAPIResource, UpdateableAPIResource, ListableAPIResource, DeletableAPIResource): diff --git a/stripe/test/helper.py b/stripe/test/helper.py index e3a434498..0e24f9a12 100644 --- a/stripe/test/helper.py +++ b/stripe/test/helper.py @@ -28,6 +28,12 @@ 'card': DUMMY_CARD } +DUMMY_DISPUTE = { + 'status': 'needs_response', + 'currency': 'usd', + 'metadata': {} +} + DUMMY_PLAN = { 'amount': 2000, 'interval': 'month', diff --git a/stripe/test/test_resources.py b/stripe/test/test_resources.py index 950ddff80..f24fd442d 100644 --- a/stripe/test/test_resources.py +++ b/stripe/test/test_resources.py @@ -12,7 +12,7 @@ MySingleton, MyListable, MyCreatable, MyUpdateable, MyDeletable, MyResource, SAMPLE_INVOICE, NOW, DUMMY_CARD, DUMMY_CHARGE, DUMMY_PLAN, DUMMY_COUPON, - DUMMY_INVOICE_ITEM) + DUMMY_INVOICE_ITEM, DUMMY_DISPUTE) from stripe import util @@ -823,6 +823,66 @@ def test_create_with_source_param(self): ) +class DisputeTest(StripeResourceTest): + + def test_list_all_disputes(self): + stripe.Dispute.all(created={'lt': NOW}) + + self.requestor_mock.request.assert_called_with( + 'get', + '/v1/disputes', + { + 'created': {'lt': NOW}, + } + ) + + def test_create_dispute(self): + stripe.Dispute.create(idempotency_key='foo', **DUMMY_DISPUTE) + + self.requestor_mock.request.assert_called_with( + 'post', + '/v1/disputes', + DUMMY_DISPUTE, + {'Idempotency-Key': 'foo'}, + ) + + def test_retrieve_dispute(self): + stripe.Dispute.retrieve('dp_test_id') + + self.requestor_mock.request.assert_called_with( + 'get', + '/v1/disputes/dp_test_id', + {}, + None + ) + + def test_update_dispute(self): + dispute = stripe.Dispute.construct_from({ + 'id': 'dp_update_id', + 'metadata': {'extra_info': 'foo'}, + }, 'api_key') + dispute.metadata['extra_info'] = 'foo' + dispute.save() + + self.requestor_mock.request.assert_called_with( + 'post', + '/v1/disputes/dp_update_id', + {'metadata': {'extra_info': 'foo'}}, + None + ) + + def test_close_dispute(self): + dispute = stripe.Dispute(id='dp_close_id') + dispute.close(idempotency_key='foo') + + self.requestor_mock.request.assert_called_with( + 'post', + '/v1/disputes/dp_close_id/close', + {}, + {'Idempotency-Key': 'foo'}, + ) + + class AccountTest(StripeResourceTest): def test_retrieve_account_deprecated(self): From 1d5f288fc0af47722279475ea9676ad329ecfba1 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Fri, 17 Jul 2015 16:54:40 -0700 Subject: [PATCH 2/3] Back changes out to bin/stripe --- bin/stripe | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/bin/stripe b/bin/stripe index ff3e945d2..b85a83e5c 100755 --- a/bin/stripe +++ b/bin/stripe @@ -159,14 +159,6 @@ class CustomerClient(CreateableAPIResourceClient, UpdateableAPIResourceClient, url = self.instance_url() + '/subscription' self.logged_curl('delete', url, params) -class DisputeClient(CreateableAPIResourceClient, ListableAPIResourceClient, - UpdateableAPIResourceClient): - client_for = stripe.Dispute - - def close(self): - url = self.instance_url() + '/close' - self.logged_curl('post', url, {}}) - class InvoiceClient(CreateableAPIResourceClient, ListableAPIResourceClient, UpdateableAPIResourceClient): client_for = stripe.Invoice @@ -212,8 +204,6 @@ def main(): 'charges' : ChargeClient, 'customer' : CustomerClient, 'customers' : CustomerClient, - 'dispute' : Dispute, - 'disputes' : Dispute, 'invoice' : InvoiceClient, 'invoices' : InvoiceClient, 'invoiceitem' : InvoiceItemClient, @@ -260,13 +250,6 @@ customer update_subscription cancel_subscription -dispute - all - close - create - retrieve - update - invoice all retrieve From 60b6abb2824203a051bb21164ecba248ac337c9d Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Fri, 17 Jul 2015 17:03:50 -0700 Subject: [PATCH 3/3] Add tests for dispute evidence. Re-order parts of the file in alpha order. --- stripe/__init__.py | 47 +++++++++++++++++++++++++++-------- stripe/resource.py | 38 +++++++++++++++++++--------- stripe/test/test_resources.py | 12 ++++++--- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/stripe/__init__.py b/stripe/__init__.py index ef4f77cc4..187abd8d3 100644 --- a/stripe/__init__.py +++ b/stripe/__init__.py @@ -15,19 +15,39 @@ # Resource from stripe.resource import ( # noqa - Account, Balance, BalanceTransaction, BankAccount, Card, - Charge, Customer, Invoice, InvoiceItem, Plan, Token, Coupon, - Event, Transfer, Recipient, FileUpload, - ApplicationFee, Subscription, BitcoinReceiver, BitcoinTransaction, - Dispute) + Account, + ApplicationFee, + Balance, + BalanceTransaction, + BankAccount, + BitcoinReceiver, + BitcoinTransaction, + Card, + Charge, + Coupon, + Customer, + Dispute, + Event, + FileUpload, + Invoice, + InvoiceItem, + Plan, + Recipient, + Subscription, + Token, + Transfer) # Error imports. Note that we may want to move these out of the root # namespace in the future and you should prefer to access them via # the fully qualified `stripe.error` module. from stripe.error import ( # noqa - StripeError, APIError, APIConnectionError, AuthenticationError, CardError, - InvalidRequestError) + APIConnectionError, + APIError, + AuthenticationError, + CardError, + InvalidRequestError, + StripeError) # DEPRECATED: These imports will be moved out of the root stripe namespace # in version 2.0 @@ -35,7 +55,14 @@ from stripe.version import VERSION # noqa from stripe.api_requestor import APIRequestor # noqa from stripe.resource import ( # noqa - convert_to_stripe_object, StripeObject, StripeObjectEncoder, - APIResource, ListObject, SingletonAPIResource, ListableAPIResource, - CreateableAPIResource, UpdateableAPIResource, DeletableAPIResource) + APIResource, + CreateableAPIResource, + DeletableAPIResource, + ListObject, + ListableAPIResource, + SingletonAPIResource, + StripeObject, + StripeObjectEncoder, + UpdateableAPIResource, + convert_to_stripe_object) from stripe.util import json, logger # noqa diff --git a/stripe/resource.py b/stripe/resource.py index b6201515f..6cf9a3e84 100644 --- a/stripe/resource.py +++ b/stripe/resource.py @@ -6,18 +6,31 @@ def convert_to_stripe_object(resp, api_key, account): - types = {'account': Account, 'charge': Charge, 'customer': Customer, - 'invoice': Invoice, 'invoiceitem': InvoiceItem, - 'plan': Plan, 'coupon': Coupon, 'token': Token, 'event': Event, - 'transfer': Transfer, 'list': ListObject, 'recipient': Recipient, - 'bank_account': BankAccount, - 'card': Card, 'application_fee': ApplicationFee, - 'subscription': Subscription, 'refund': Refund, - 'file_upload': FileUpload, - 'fee_refund': ApplicationFeeRefund, - 'bitcoin_receiver': BitcoinReceiver, - 'bitcoin_transaction': BitcoinTransaction, - 'transfer_reversal': Reversal, 'dispute': Dispute} + types = { + 'account': Account, + 'application_fee': ApplicationFee, + 'bank_account': BankAccount, + 'bitcoin_receiver': BitcoinReceiver, + 'bitcoin_transaction': BitcoinTransaction, + 'card': Card, + 'charge': Charge, + 'coupon': Coupon, + 'customer': Customer, + 'dispute': Dispute, + 'event': Event, + 'fee_refund': ApplicationFeeRefund, + 'file_upload': FileUpload, + 'invoice': Invoice, + 'invoiceitem': InvoiceItem, + 'list': ListObject, + 'plan': Plan, + 'recipient': Recipient, + 'refund': Refund, + 'subscription': Subscription, + 'token': Token, + 'transfer': Transfer, + 'transfer_reversal': Reversal, + } if isinstance(resp, list): return [convert_to_stripe_object(i, api_key, account) for i in resp] @@ -527,6 +540,7 @@ def mark_as_safe(self, idempotency_key=None): class Dispute(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource): + def close(self, idempotency_key=None): url = self.instance_url() + '/close' headers = populate_headers(idempotency_key) diff --git a/stripe/test/test_resources.py b/stripe/test/test_resources.py index f24fd442d..d6280a130 100644 --- a/stripe/test/test_resources.py +++ b/stripe/test/test_resources.py @@ -859,15 +859,21 @@ def test_retrieve_dispute(self): def test_update_dispute(self): dispute = stripe.Dispute.construct_from({ 'id': 'dp_update_id', - 'metadata': {'extra_info': 'foo'}, + 'evidence': { + 'product_description': 'description', + }, }, 'api_key') - dispute.metadata['extra_info'] = 'foo' + dispute.evidence['customer_name'] = 'customer' + dispute.evidence['uncategorized_text'] = 'text' dispute.save() self.requestor_mock.request.assert_called_with( 'post', '/v1/disputes/dp_update_id', - {'metadata': {'extra_info': 'foo'}}, + {'evidence': { + 'customer_name': 'customer', + 'uncategorized_text': 'text', + }}, None )