Skip to content

Commit f8a6511

Browse files
committed
Attachable objects
1 parent 95f4044 commit f8a6511

2 files changed

Lines changed: 109 additions & 9 deletions

File tree

quickbooks/client.py

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from urlparse import parse_qsl
77

88
from .exceptions import QuickbooksException, SevereException
9+
import textwrap
910

1011
try:
1112
from rauth import OAuth1Session, OAuth1Service
@@ -116,18 +117,18 @@ def get_authorize_url(self):
116117
Returns the Authorize URL as returned by QB, and specified by OAuth 1.0a.
117118
:return URI:
118119
"""
119-
self.authorize_url = self.authorize_url[:self.authorize_url.find('?')] if '?' in self.authorize_url else self.authorize_url
120+
self.authorize_url = self.authorize_url[:self.authorize_url.find('?')] \
121+
if '?' in self.authorize_url else self.authorize_url
120122
if self.qbService is None:
121123
self.set_up_service()
122124

123125
response = self.qbService.get_raw_request_token(
124-
params={'oauth_callback': self.callback_url})
126+
params={'oauth_callback': self.callback_url})
125127

126128
oauth_resp = dict(parse_qsl(response.text))
127129

128130
self.request_token = oauth_resp['oauth_token']
129131
self.request_token_secret = oauth_resp['oauth_token_secret']
130-
131132
return self.qbService.get_authorize_url(self.request_token)
132133

133134
def set_up_service(self):
@@ -157,7 +158,7 @@ def get_access_tokens(self, oauth_verifier):
157158

158159
return session
159160

160-
def make_request(self, request_type, url, request_body=None, content_type='application/json'):
161+
def make_request(self, request_type, url, request_body=None, content_type='application/json', file=None):
161162

162163
params = {}
163164

@@ -169,13 +170,52 @@ def make_request(self, request_type, url, request_body=None, content_type='appli
169170

170171
if self.session is None:
171172
self.create_session()
172-
173173
headers = {
174174
'Content-Type': content_type,
175175
'Accept': 'application/json'
176176
}
177-
178-
req = self.session.request(request_type, url, True, self.company_id, headers=headers, params=params, data=request_body)
177+
if file:
178+
url = url.replace('attachable', 'upload')
179+
file_name = file.name + ""
180+
if "/" in file_name:
181+
file_name = file_name.rsplit("/", 1)[1]
182+
boundary = '-------------PythonMultipartPost'
183+
headers.update({
184+
'Content-Type': 'multipart/form-data; boundary=%s' % boundary,
185+
'Accept-Encoding': 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
186+
'User-Agent': 'OAuth gem v0.4.7',
187+
'Accept': 'application/json',
188+
'Connection': 'close'
189+
})
190+
extension = file_name.rsplit(".", 1)[1]
191+
192+
mime_type = {
193+
"pdf": "pdf",
194+
"xlsx": "vnd.ms-excel",
195+
"pptx": "vnd.ms-powerpoint"}.get(extension, "plain/text")
196+
binary_data = file.read()
197+
198+
request_body = textwrap.dedent(
199+
"""
200+
--%s
201+
Content-Disposition: form-data; name="file_metadata_01"
202+
Content-Type: application/json
203+
204+
%s
205+
206+
--%s
207+
Content-Disposition: form-data; name="file_content_01"; filename="%s"
208+
Content-Type: application/%s
209+
Content-Length: %d
210+
Content-Transfer-Encoding: binary
211+
212+
%s
213+
214+
--%s--
215+
"""
216+
) % (boundary, request_body, boundary, file_name, mime_type, len(binary_data), binary_data, boundary)
217+
req = self.session.request(request_type, url, True, self.company_id, headers=headers, params=params,
218+
data=request_body)
179219

180220
try:
181221
result = req.json()
@@ -212,11 +252,11 @@ def handle_exceptions(self, results):
212252
else:
213253
raise QuickbooksException(message, code, detail)
214254

215-
def create_object(self, qbbo, request_body):
255+
def create_object(self, qbbo, request_body, _file=None):
216256
self.isvalid_object_name(qbbo)
217257

218258
url = self.api_url + "/company/{0}/{1}".format(self.company_id, qbbo.lower())
219-
results = self.make_request("POST", url, request_body)
259+
results = self.make_request("POST", url, request_body, file=file)
220260

221261
return results
222262

quickbooks/objects/attachable.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from six import python_2_unicode_compatible
2+
from .base import Ref, QuickbooksManagedObject, QuickbooksTransactionEntity
3+
from ..client import QuickBooks
4+
5+
6+
@python_2_unicode_compatible
7+
class Attachable(QuickbooksManagedObject, QuickbooksTransactionEntity):
8+
"""
9+
QBO definition: This page covers the Attachable, Upload, and Download resources used for attachment management. Attachments are supplemental information linked to a transaction or Item object. They can be files, notes, or a combination of both.
10+
In the case of file attachments, use an upload endpoint multipart request to upload the files to the QuickBooks attachment list and, optionally, to supply metadata for each via an attachable object. If meta data is not supplied with the upload request, the system creates it.
11+
In the case of a note, use the create attachable endpoint.
12+
For information about attachments, see the Attachments Developer Guide.
13+
"""
14+
15+
class_dict = {
16+
"EntityRef": Ref,
17+
}
18+
19+
qbo_object_name = "Attachable"
20+
21+
def __init__(self):
22+
super(Attachable, self).__init__()
23+
24+
self.AttachableRef = []
25+
self.FileName = None
26+
self._File = None
27+
self.Note = ""
28+
self.FileAccessUri = None
29+
self.TempDownloadUri = None
30+
self.Size = None
31+
self.ContentType = None
32+
self.Category = None
33+
self.Lat = None
34+
self.Long = None
35+
self.PlaceName = None
36+
self.ThumbnailFileAccessUri = None
37+
self.ThumbnailTempDownloadUri = None
38+
39+
def __str__(self):
40+
return self.FileName
41+
42+
def to_ref(self):
43+
ref = Ref()
44+
ref.name = self.FileName
45+
ref.type = self.qbo_object_name
46+
ref.value = self.Id
47+
return ref
48+
49+
def save(self):
50+
qb = QuickBooks()
51+
52+
if self.Id and self.Id > 0:
53+
json_data = qb.update_object(self.qbo_object_name, self.to_json(), _file=self._File)
54+
else:
55+
json_data = qb.create_object(self.qbo_object_name, self.to_json(), _file=self._File)
56+
57+
obj = type(self).from_json(json_data['AttachableResponse'][0]['Attachable'])
58+
self.Id = obj.Id
59+
60+
return obj

0 commit comments

Comments
 (0)