Skip to content
This repository has been archived by the owner on May 12, 2020. It is now read-only.

Commit

Permalink
Merge 2330891 into 3849518
Browse files Browse the repository at this point in the history
  • Loading branch information
siddick committed Mar 31, 2014
2 parents 3849518 + 2330891 commit d1d98ef
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 3 deletions.
1 change: 1 addition & 0 deletions paypalrestsdk/__init__.py
@@ -1,5 +1,6 @@
from paypalrestsdk.api import Api, set_config, configure
from paypalrestsdk.payments import Payment, Sale, Refund, Authorization, Capture
from paypalrestsdk.invoices import Invoice
from paypalrestsdk.vault import CreditCard
from paypalrestsdk.openid_connect import Tokeninfo, Userinfo
from paypalrestsdk.exceptions import ResourceNotFound, UnauthorizedAccess, MissingConfig
Expand Down
11 changes: 8 additions & 3 deletions paypalrestsdk/api.py
Expand Up @@ -147,10 +147,10 @@ def http_call(self, url, method, **kwargs):
"""
Makes a http call. Logs response information.
"""
logging.info('Request[%s]: %s' % (method, url))
logging.info('Request[%s]: %s' % (method, url))
start_time = datetime.datetime.now()
response = requests.request(method, url, proxies=self.proxies, **kwargs)

response = requests.request(method, url, proxies=self.proxies, **kwargs)

duration = datetime.datetime.now() - start_time
logging.info('Response[%d]: %s, Duration: %s.%ss.' % (response.status_code, response.reason, duration.seconds, duration.microseconds))
Expand Down Expand Up @@ -224,6 +224,11 @@ def post(self, action, params=None, headers=None, refresh_token=None):
"""
return self.request(util.join_url(self.endpoint, action), 'POST', body=params or {}, headers=headers or {}, refresh_token=refresh_token)

def put(self, action, params=None, headers=None, refresh_token=None):
"""Make PUT request
"""
return self.request(util.join_url(self.endpoint, action), 'PUT', body=params or {}, headers=headers or {}, refresh_token=refresh_token)

def delete(self, action, headers=None):
"""Make DELETE request
"""
Expand Down
36 changes: 36 additions & 0 deletions paypalrestsdk/invoices.py
@@ -0,0 +1,36 @@
import paypalrestsdk.util as util
from paypalrestsdk.resource import List, Find, Delete, Create, Update, Post, Resource
from paypalrestsdk.api import default as default_api

class Invoice(List, Find, Create, Delete, Update, Post):
"""Invoice class wrapping the REST v1/invoices/invoice endpoint
Usage::
>>> invoice_histroy = Invoice.all({"count": 5})
>>> invoice = Invoice.new({})
>>> invoice.create() # return True or False
"""
path = "v1/invoices/invoice"

def send(self):
return self.post('send', {}, self)

def remind(self, attributes):
return self.post('remind', attributes, self)

def cancel(self, attributes):
return self.post('cancel', attributes, self)

@classmethod
def search(cls, params=None, api=None):
api = api or default_api()
params = params or {}

url = util.join_url(cls.path, 'search')

return Resource(api.post(url, params), api=api)

Invoice.convert_resources['invoices'] = Invoice
Invoice.convert_resources['invoice'] = Invoice
15 changes: 15 additions & 0 deletions paypalrestsdk/resource.py
Expand Up @@ -160,6 +160,21 @@ def create(self, refresh_token=None, correlation_id=None):
self.merge(new_attributes)
return self.success()

class Update(Resource):
""" Update a resource
Usage::
>>> invoice.update()
"""

def update(self, attributes=None, refresh_token=None):
attributes = attributes or self.to_dict()
url = util.join_url(self.path, str(self['id']))
new_attributes = self.api.put(url, attributes, self.http_headers(), refresh_token)
self.error = None
self.merge(new_attributes)
return self.success()

class Delete(Resource):

Expand Down
118 changes: 118 additions & 0 deletions test/unit_tests/invoices_test.py
@@ -0,0 +1,118 @@
from test_helper import paypal, unittest
from mock import patch, ANY

class TestInvoice(unittest.TestCase):

def setUp(self):
self.invoice_attributes = {
'merchant_info': {
'email': 'ppaas_default@paypal.com'
},
'billing_info': [
{ 'email': 'example@example.com' }
],
'items': [
{
'name': 'Sutures',
'quantity': 100,
'unit_price': {
'currency': 'USD',
'value': 5
}
}
]
}
self.invoice = paypal.Invoice(self.invoice_attributes)
self.invoice.id = 'INV2-RUVR-ADWQ-H89Y-ABCD'

@patch('test_helper.paypal.Api.post', autospec=True)
def test_create(self, mock):
invoice = paypal.Invoice(self.invoice_attributes)
response = invoice.create()

mock.assert_called_once_with(invoice.api,'v1/invoices/invoice', self.invoice_attributes, {'PayPal-Request-Id' : invoice.request_id}, None)
self.assertEqual(response, True)

@patch('test_helper.paypal.Api.get', autospec=True)
def test_find(self, mock):
invoice = paypal.Invoice.find(self.invoice.id)

mock.assert_called_once_with(self.invoice.api, 'v1/invoices/invoice/'+self.invoice.id)
self.assertTrue(isinstance(invoice, paypal.Invoice))

@patch('test_helper.paypal.Api.get', autospec=True)
def test_all(self, mock):
mock.return_value = {'total_count': 1, 'invoices': [self.invoice_attributes]}
history = paypal.Invoice.all({'count': 1})

mock.assert_called_once_with(self.invoice.api, 'v1/invoices/invoice?count=1')
self.assertEqual(history.total_count, 1)
self.assertTrue(isinstance(history.invoices[0], paypal.Invoice))



@patch('test_helper.paypal.Api.delete', autospec=True)
def test_delete(self, mock):
response = self.invoice.delete()

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/'+self.invoice.id)
self.assertEqual(response, True)

@patch('test_helper.paypal.Api.put', autospec=True)
def test_update(self, mock):
response = self.invoice.update(self.invoice_attributes)

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/'+self.invoice.id, self.invoice_attributes, {'PayPal-Request-Id' : self.invoice.request_id}, None)
self.assertEqual(response, True)

@patch('test_helper.paypal.Api.post', autospec=True)
def test_send(self, mock):
response = self.invoice.send()

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/'+self.invoice.id+'/send', {}, {'PayPal-Request-Id' : ANY})
self.assertEqual(response, True)


@patch('test_helper.paypal.Api.post', autospec=True)
def test_search(self, mock):
search_attributes = {
"start_invoice_date" : "2010-05-10 PST",
"end_invoice_date" : "2013-05-11 PST",
"page" : 1,
"page_size" : 20,
"total_count_required" : True
}
mock.return_value = {'total_count': 1, 'invoices': [self.invoice_attributes]}

history = paypal.Invoice.search(search_attributes);

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/search', search_attributes)
self.assertEqual(history.total_count, 1)
self.assertTrue(isinstance(history.invoices[0], paypal.Invoice))

@patch('test_helper.paypal.Api.post', autospec=True)
def test_remind(self, mock):
remind_attributes = {
'subject': 'Past due',
'note': 'Please pay soon',
'send_to_merchant': True
}

response = self.invoice.remind(remind_attributes);

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/'+self.invoice.id+'/remind', remind_attributes, {'PayPal-Request-Id' : ANY})
self.assertEqual(response, True)

@patch('test_helper.paypal.Api.post', autospec=True)
def test_cancel(self, mock):
cancel_attributes = {
'subject': 'Past due',
'note': 'Canceling invoice',
'send_to_merchant': True,
'send_to_payer': True
}

response = self.invoice.cancel(cancel_attributes);

mock.assert_called_once_with(self.invoice.api,'v1/invoices/invoice/'+self.invoice.id+'/cancel', cancel_attributes, {'PayPal-Request-Id' : ANY})
self.assertEqual(response, True)

0 comments on commit d1d98ef

Please sign in to comment.