Skip to content

Commit

Permalink
Merge pull request #356 from laf-rge/master
Browse files Browse the repository at this point in the history
Convert to Using Decimal and Fix Related Test
  • Loading branch information
ej2 authored Jul 9, 2024
2 parents cea08b2 + 031831e commit ea194e8
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 293 deletions.
1 change: 0 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ pytest-cov = "*"
urllib3 = ">=2.1.0"
intuit-oauth = "==1.2.5"
requests = ">=2.31.0"
simplejson = ">=3.19.1"
requests_oauthlib = ">=1.3.1"
457 changes: 181 additions & 276 deletions Pipfile.lock

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions quickbooks/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import base64
import hashlib
import hmac
import decimal

from . import exceptions
from requests_oauthlib import OAuth2Session

to_bytes = lambda value, *args, **kwargs: bytes(value, "utf-8", *args, **kwargs)
def to_bytes(value, *args, **kwargs):
return bytes(value, "utf-8", *args, **kwargs)


class Environments(object):
Expand All @@ -24,6 +26,7 @@ class QuickBooks(object):
minorversion = None
verifier_token = None
invoice_link = False
use_decimal = False

sandbox_api_url_v3 = "https://sandbox-quickbooks.api.intuit.com/v3"
api_url_v3 = "https://quickbooks.api.intuit.com/v3"
Expand Down Expand Up @@ -79,6 +82,9 @@ def __new__(cls, **kwargs):
if 'verifier_token' in kwargs:
instance.verifier_token = kwargs.get('verifier_token')

if 'use_decimal' in kwargs:
instance.use_decimal = kwargs.get('use_decimal')

return instance

def _start_session(self):
Expand Down Expand Up @@ -206,7 +212,10 @@ def make_request(self, request_type, url, request_body=None, content_type='appli
"Application authentication failed", error_code=req.status_code, detail=req.text)

try:
result = req.json()
if (self.use_decimal):
result = json.loads(req.text, parse_float=decimal.Decimal)
else:
result = json.loads(req.text)
except:
raise exceptions.QuickbooksException("Error reading json response: {0}".format(req.text), 10000)

Expand Down
18 changes: 11 additions & 7 deletions quickbooks/mixins.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import decimal
import json
from urllib.parse import quote

try: import simplejson as json
except ImportError: import json

from .utils import build_where_clause, build_choose_clause
from .client import QuickBooks
from .exceptions import QuickbooksException
from .utils import build_choose_clause, build_where_clause

class DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, decimal.Decimal):
return str(obj)
return super(DecimalEncoder, self).default(obj)

class ToJsonMixin(object):
def to_json(self):
return json.dumps(self, default=self.json_filter(), sort_keys=True, indent=4)
return json.dumps(self, cls=DecimalEncoder, default=self.json_filter(), sort_keys=True, indent=4)

def json_filter(self):
"""
Expand Down Expand Up @@ -178,7 +182,7 @@ def void(self, qb=None):

data = self.get_void_data()
params = self.get_void_params()
results = qb.post(url, json.dumps(data), params=params)
results = qb.post(url, json.dumps(data, cls=DecimalEncoder), params=params)

return results

Expand Down Expand Up @@ -232,7 +236,7 @@ def delete(self, qb=None, request_id=None):
'Id': self.Id,
'SyncToken': self.SyncToken,
}
return qb.delete_object(self.qbo_object_name, json.dumps(data), request_id=request_id)
return qb.delete_object(self.qbo_object_name, json.dumps(data, cls=DecimalEncoder), request_id=request_id)


class DeleteNoIdMixin(object):
Expand Down
1 change: 0 additions & 1 deletion quickbooks/objects/payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from ..client import QuickBooks
from .creditcardpayment import CreditCardPayment
from ..mixins import DeleteMixin, VoidMixin
import json


class PaymentLine(QuickbooksBaseObject):
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
intuit-oauth==1.2.4
requests_oauthlib>=1.3.1
requests>=2.31.0
simplejson>=3.19.1
requests>=2.31.0
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ def read(*parts):
'intuit-oauth==1.2.5',
'requests_oauthlib>=1.3.1',
'requests>=2.31.0',
'simplejson>=3.19.1',
'python-dateutil',
],

Expand Down
19 changes: 16 additions & 3 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from tests.integration.test_base import QuickbooksUnitTestCase

try:
Expand All @@ -6,7 +7,7 @@
from unittest.mock import patch, mock_open

from quickbooks.exceptions import QuickbooksException, SevereException, AuthorizationException
from quickbooks import client
from quickbooks import client, mixins
from quickbooks.objects.salesreceipt import SalesReceipt


Expand Down Expand Up @@ -141,7 +142,7 @@ def test_get_single_object(self, make_req):

@patch('quickbooks.client.QuickBooks.process_request')
def test_make_request(self, process_request):
process_request.return_value = MockResponse()
process_request.return_value = MockResponseJson()

qb_client = client.QuickBooks()
qb_client.company_id = "1234"
Expand Down Expand Up @@ -220,7 +221,7 @@ def test_download_pdf_not_authorized(self, process_request):
@patch('quickbooks.client.QuickBooks.process_request')
def test_make_request_file_closed(self, process_request):
file_path = '/path/to/file.txt'
process_request.return_value = MockResponse()
process_request.return_value = MockResponseJson()
with patch('builtins.open', mock_open(read_data=b'file content')) as mock_file:
qb_client = client.QuickBooks(auth_client=self.auth_client)
qb_client.make_request('POST',
Expand Down Expand Up @@ -253,6 +254,18 @@ def json(self):
def content(self):
return ''

class MockResponseJson:
def __init__(self, json_data=None, status_code=200):
self.json_data = json_data or {}
self.status_code = status_code

@property
def text(self):
return json.dumps(self.json_data, cls=mixins.DecimalEncoder)

def json(self):
return self.json_data


class MockUnauthorizedResponse(object):
@property
Expand Down

0 comments on commit ea194e8

Please sign in to comment.