Skip to content

Commit 045cded

Browse files
authored
Merge pull request #363 from ej2/0.9.10
0.9.10
2 parents 6943dec + 99bd245 commit 045cded

12 files changed

+286
-117
lines changed

CHANGELOG.rst

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
* 0.9.10 (August 7, 2024)
5+
* Update intuit-oauth dependency
6+
* Fix issues with Invoice Sharable Link
7+
* Added optional params to get
8+
49
* 0.9.9 (July 9, 2024)
510
* Removed simplejson
611
* Added use_decimal option (See PR: https://github.com/ej2/python-quickbooks/pull/356 for details)

Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pytest-cov = "*"
1111

1212
[packages]
1313
urllib3 = ">=2.1.0"
14-
intuit-oauth = "==1.2.5"
14+
intuit-oauth = "==1.2.6"
1515
requests = ">=2.31.0"
1616
requests_oauthlib = ">=1.3.1"
1717
setuptools = "*"

Pipfile.lock

+208-95
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+12-4
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,23 @@ One example is `include=allowduplicatedocnum` on the Purchase object. You can ad
252252

253253
purchase.save(qb=self.qb_client, params={'include': 'allowduplicatedocnum'})
254254

255-
Other operations
255+
Sharable Invoice Link
256256
----------------
257-
Add Sharable link for an invoice sent to external customers (minorversion must be set to 36 or greater):
257+
To add a sharable link for an invoice, make sure the AllowOnlineCreditCardPayment is set to True and BillEmail is set to a invalid email address:
258258

259-
invoice.invoice_link = true
259+
invoice.AllowOnlineCreditCardPayment = True
260+
invoice.BillEmail = EmailAddress()
261+
invoice.BillEmail.Address = '[email protected]'
260262

263+
When you query the invoice include the following params (minorversion must be set to 36 or greater):
261264

262-
Void an invoice:
265+
invoice = Invoice.get(id, qb=self.qb_client, params={'include': 'invoiceLink'})
263266

267+
268+
Void an invoice
269+
----------------
270+
Call `void` on any invoice with an Id:
271+
264272
invoice = Invoice()
265273
invoice.Id = 7
266274
invoice.void(qb=client)

quickbooks/client.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,6 @@ def make_request(self, request_type, url, request_body=None, content_type='appli
155155
if request_id:
156156
params['requestid'] = request_id
157157

158-
if self.invoice_link:
159-
params['include'] = 'invoiceLink'
160-
161158
if not request_body:
162159
request_body = {}
163160

@@ -242,9 +239,9 @@ def process_request(self, request_type, url, headers="", params="", data=""):
242239
return self.session.request(
243240
request_type, url, headers=headers, params=params, data=data)
244241

245-
def get_single_object(self, qbbo, pk):
242+
def get_single_object(self, qbbo, pk, params=None):
246243
url = "{0}/company/{1}/{2}/{3}/".format(self.api_url, self.company_id, qbbo.lower(), pk)
247-
result = self.get(url, {})
244+
result = self.get(url, {}, params=params)
248245

249246
return result
250247

quickbooks/mixins.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ class ReadMixin(object):
9494
qbo_json_object_name = ""
9595

9696
@classmethod
97-
def get(cls, id, qb=None):
97+
def get(cls, id, qb=None, params=None):
9898
if not qb:
9999
qb = QuickBooks()
100100

101-
json_data = qb.get_single_object(cls.qbo_object_name, pk=id)
101+
json_data = qb.get_single_object(cls.qbo_object_name, pk=id, params=params)
102102

103103
if cls.qbo_json_object_name != '':
104104
return cls.from_json(json_data[cls.qbo_json_object_name])

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
intuit-oauth==1.2.4
1+
intuit-oauth==1.2.6
22
requests_oauthlib>=1.3.1
33
requests>=2.31.0

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def read(*parts):
1010
return fp.read()
1111

1212

13-
VERSION = (0, 9, 9)
13+
VERSION = (0, 9, 10)
1414
version = '.'.join(map(str, VERSION))
1515

1616
setup(
@@ -31,7 +31,7 @@ def read(*parts):
3131

3232
install_requires=[
3333
'setuptools',
34-
'intuit-oauth==1.2.5',
34+
'intuit-oauth==1.2.6',
3535
'requests_oauthlib>=1.3.1',
3636
'requests>=2.31.0',
3737
'python-dateutil',

tests/integration/test_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def setUp(self):
1717
)
1818

1919
self.qb_client = QuickBooks(
20-
minorversion=69,
20+
minorversion=73,
2121
auth_client=self.auth_client,
2222
refresh_token=os.environ.get('REFRESH_TOKEN'),
2323
company_id=os.environ.get('COMPANY_ID'),

tests/integration/test_invoice.py

+41-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
from datetime import datetime
2+
13
from quickbooks.objects.base import CustomerMemo
24
from quickbooks.objects.customer import Customer
35
from quickbooks.objects.detailline import SalesItemLine, SalesItemLineDetail
46
from quickbooks.objects.invoice import Invoice
57
from quickbooks.objects.item import Item
8+
from quickbooks.objects.base import EmailAddress
69
from tests.integration.test_base import QuickbooksTestCase
710
import uuid
811

9-
class InvoiceTest(QuickbooksTestCase):
10-
def create_invoice(self, customer, request_id=None):
11-
invoice = Invoice()
1212

13+
class InvoiceTest(QuickbooksTestCase):
14+
def create_invoice_line(self):
1315
line = SalesItemLine()
1416
line.LineNum = 1
1517
line.Description = "description"
@@ -18,7 +20,11 @@ def create_invoice(self, customer, request_id=None):
1820
item = Item.all(max_results=1, qb=self.qb_client)[0]
1921

2022
line.SalesItemLineDetail.ItemRef = item.to_ref()
21-
invoice.Line.append(line)
23+
return line
24+
25+
def create_invoice(self, customer, request_id=None):
26+
invoice = Invoice()
27+
invoice.Line.append(self.create_invoice_line())
2228

2329
invoice.CustomerRef = customer.to_ref()
2430

@@ -86,3 +92,34 @@ def test_void(self):
8692
self.assertEqual(query_invoice.Balance, 0.0)
8793
self.assertEqual(query_invoice.TotalAmt, 0.0)
8894
self.assertIn('Voided', query_invoice.PrivateNote)
95+
96+
def test_invoice_link(self):
97+
# Sharable link for the invoice sent to external customers.
98+
# The link is generated only for invoices with online payment enabled and having a valid customer email address.
99+
# Include query param `include=invoiceLink` to get the link back on query response.
100+
101+
# Create test customer
102+
customer_name = datetime.now().strftime('%d%H%M%S')
103+
customer = Customer()
104+
customer.DisplayName = customer_name
105+
customer.save(qb=self.qb_client)
106+
107+
# Create an invoice with sharable link flags set
108+
invoice = Invoice()
109+
invoice.CustomerRef = customer.to_ref()
110+
invoice.DueDate = '2024-12-31'
111+
invoice.AllowOnlineCreditCardPayment = True
112+
invoice.AllowOnlineACHPayment = True
113+
invoice.Line.append(self.create_invoice_line())
114+
115+
# BillEmail must be set for Sharable link to work!
116+
invoice.BillEmail = EmailAddress()
117+
invoice.BillEmail.Address = '[email protected]'
118+
119+
invoice.save(qb=self.qb_client)
120+
121+
# You must add 'include': 'invoiceLink' to the params when doing a query for the invoice
122+
query_invoice = Invoice.get(invoice.Id, qb=self.qb_client, params={'include': 'invoiceLink'})
123+
124+
self.assertIsNotNone(query_invoice.InvoiceLink)
125+
self.assertIn('https', query_invoice.InvoiceLink)

tests/unit/test_client.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,16 @@ def test_get_single_object(self, make_req):
138138

139139
qb_client.get_single_object("test", 1)
140140
url = "https://sandbox-quickbooks.api.intuit.com/v3/company/1234/test/1/"
141-
make_req.assert_called_with("GET", url, {})
141+
make_req.assert_called_with("GET", url, {}, params=None)
142+
143+
@patch('quickbooks.client.QuickBooks.make_request')
144+
def test_get_single_object_with_params(self, make_req):
145+
qb_client = client.QuickBooks(auth_client=self.auth_client)
146+
qb_client.company_id = "1234"
147+
148+
qb_client.get_single_object("test", 1, params={'param':'value'})
149+
url = "https://sandbox-quickbooks.api.intuit.com/v3/company/1234/test/1/"
150+
make_req.assert_called_with("GET", url, {}, params={'param':'value'})
142151

143152
@patch('quickbooks.client.QuickBooks.process_request')
144153
def test_make_request(self, process_request):

tests/unit/test_mixins.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class ReadMixinTest(QuickbooksUnitTestCase):
210210
@patch('quickbooks.mixins.QuickBooks.get_single_object')
211211
def test_get(self, get_single_object):
212212
Department.get(1)
213-
get_single_object.assert_called_once_with("Department", pk=1)
213+
get_single_object.assert_called_once_with("Department", pk=1, params=None)
214214

215215
def test_get_with_qb(self):
216216
with patch.object(self.qb_client, 'get_single_object') as get_single_object:

0 commit comments

Comments
 (0)