@@ -22,30 +22,27 @@ class XeroExceptionUnknown(XeroException):
22
22
pass
23
23
24
24
class Manager (object ):
25
-
26
25
DECORATED_METHODS = ('get' , 'save' , 'filter' , 'all' , 'put' )
27
- DATETIME_FIELDS = (u'UpdatedDateUTC' ,)
28
- BOOLEAN_FIELDS = (u'IsSupplier' , u'IsCustomer' )
29
- MULTY_LINES = (u'LineItem' , u'Phone' , u'Address' )
26
+ DATETIME_FIELDS = (u'UpdatedDateUTC' ,)
27
+ BOOLEAN_FIELDS = (u'IsSupplier' , u'IsCustomer' )
28
+ MULTI_LINES = (u'LineItem' , u'Phone' , u'Address' , 'TaxRate ' )
30
29
PLURAL_EXCEPTIONS = {'Addresse' :'Address' }
31
30
32
31
def __init__ (self , name , client ):
33
- self .client = client
34
- self .__name__ = name
35
- self .__list_word = name [:len (name )- 1 ].title ()
36
- self .__set_decorators ()
32
+ self .client = client
33
+ self .name = name
34
+
35
+ # setup our singular variants of the name
36
+ # only if the name ends in 0
37
+ if name [- 1 ] == "s" :
38
+ self .singular = name [:len (name )- 1 ]
39
+ else :
40
+ self .singular = name
37
41
38
- def __set_decorators (self ):
39
42
for method_name in self .DECORATED_METHODS :
40
43
method = getattr (self , method_name )
41
44
setattr (self , method_name , self .__get_data (method ))
42
45
43
- def get_url_postfix (self ):
44
- return self .__name__ .title ()
45
-
46
- def get_not_plural (self ):
47
- return self .__name__ [:len (self .__name__ )- 1 ].title ()
48
-
49
46
def walk_dom (self , dom ):
50
47
tree_list = tuple ()
51
48
for node in dom .childNodes :
@@ -67,13 +64,13 @@ def convert_to_dict(self, deep_list):
67
64
68
65
if len (data ) == 1 :
69
66
out [key ] = data [0 ]
70
- elif len (data ) > 1 and key in self .MULTY_LINES and out :
67
+ elif len (data ) > 1 and key in self .MULTI_LINES and out :
71
68
out += (self .convert_to_dict (data ),)
72
- elif len (data ) > 1 and key in self .MULTY_LINES :
69
+ elif len (data ) > 1 and key in self .MULTI_LINES :
73
70
out = (self .convert_to_dict (data ),)
74
- elif len (data ) > 1 and key == self .__list_word and out :
71
+ elif len (data ) > 1 and key == self .singular and out :
75
72
out += (self .convert_to_dict (data ),)
76
- elif len (data ) > 1 and key == self .__list_word :
73
+ elif len (data ) > 1 and key == self .singular :
77
74
out = (self .convert_to_dict (data ),)
78
75
elif len (data ) > 1 :
79
76
out [key ] = self .convert_to_dict (data )
@@ -122,7 +119,7 @@ def dict_to_xml( self, root_elm, dict_data ):
122
119
123
120
elif _list_data :
124
121
for _d in _data :
125
- _plural_name = self .PLURAL_EXCEPTIONS .get (_plural_name , _plural_name )
122
+ _plural_name = self .PLURAL_EXCEPTIONS .get (_plural_name , _plural_name )
126
123
__elm = self .dict_to_xml (SubElement (_elm , _plural_name ), _d )
127
124
128
125
else :
@@ -131,31 +128,32 @@ def dict_to_xml( self, root_elm, dict_data ):
131
128
return root_elm
132
129
133
130
def __prepare_data__for_save (self , data ):
134
- name = self .get_url_postfix ()
135
131
if isinstance (data , list ) or isinstance (data , tuple ):
136
- root_elm = Element (name )
132
+ root_elm = Element (self . name )
137
133
for d in data :
138
- sub_elm = SubElement (root_elm , self .get_not_plural () )
134
+ sub_elm = SubElement (root_elm , self .singular )
139
135
self .dict_to_xml (sub_elm , d )
140
136
else :
141
- root_elm = self .dict_to_xml (Element (self .get_not_plural () ), data )
137
+ root_elm = self .dict_to_xml (Element (self .singular ), data )
142
138
143
139
return tostring (root_elm )
144
140
145
141
def __get_results (self , data ):
146
- name = self .get_url_postfix ()
147
142
response = data [u'Response' ]
148
- result = response .get (name , {})
149
- single = name [:len (name )- 1 ]
150
- return result if isinstance (result , tuple ) else result [single ] \
151
- if result .has_key (single ) else None
143
+ result = response .get (self .name , {})
144
+
145
+ if isinstance (result , tuple ):
146
+ return result
147
+
148
+ if isinstance (result , dict ) and result .has_key (self .singular ):
149
+ return result [self .singular ]
152
150
153
151
def __get_data (self , func ):
154
152
def wrapper (* args , ** kwargs ):
155
153
req_args = func (* args , ** kwargs )
156
154
response = self .client .request (* req_args )
157
- body = response [1 ]
158
- headers = response [0 ]
155
+ body = response [1 ]
156
+ headers = response [0 ]
159
157
if headers ['status' ] == '200' :
160
158
if headers ['content-type' ] == 'application/pdf' :
161
159
return body
@@ -186,76 +184,81 @@ def wrapper(*args, **kwargs):
186
184
return wrapper
187
185
188
186
def get (self , id , headers = None ):
189
- name = self .get_url_postfix ()
190
- uri = '/' .join ([XERO_API_URL , name , id ])
187
+ uri = '/' .join ([XERO_API_URL , self .name , id ])
191
188
return uri , 'GET' , None , headers
192
189
193
- def __save_data (self , data , method = 'PUT ' ):
194
- headers = {"Content-Type" :
195
- "application/x-www-form-urlencoded; charset=utf-8" }
196
- name = self . get_url_postfix ()
197
- uri = '/' .join ([XERO_API_URL , name ])
190
+ def save (self , data , method = 'post ' ):
191
+ headers = {
192
+ "Content-Type" : "application/x-www-form-urlencoded; charset=utf-8"
193
+ }
194
+ uri = '/' .join ([XERO_API_URL , self . name ])
198
195
body = 'xml=' + urllib .quote (self .__prepare_data__for_save (data ))
199
196
return uri , method , body , headers
200
197
201
- def save (self , data ):
202
- return self .__save_data (data , method = 'post' )
203
-
204
198
def put (self , data ):
205
- return self .__save_data (data , method = 'PUT' )
206
-
207
- def get_filter_params (self , key , val ):
208
- if key in self .BOOLEAN_FIELDS :
209
- return 'true' if val else 'false'
210
- elif key in self .DATETIME_FIELDS :
211
- return val .isoformat ()
212
- else :
213
- return '"%s"' % str (val )
199
+ return self .save (data , method = 'PUT' )
214
200
215
201
def prepare_filtering_date (self , val ):
216
- isdt = isinstance (val , datetime )
217
- val = val .strftime ('%a, %d %b %Y %H:%M:%S GMT' ) if isdt else '"%s"' % val
218
- return {'If-Modified-Since' : val }
202
+ if isinstance (val , datetime ):
203
+ val = val .strftime ('%a, %d %b %Y %H:%M:%S GMT' )
204
+ else :
205
+ val = '"%s"' % val
206
+ return {'If-Modified-Since' : val }
219
207
220
208
def filter (self , ** kwargs ):
221
209
headers = None
222
- name = self .get_url_postfix ()
223
- uri = '/' .join ([XERO_API_URL , name ])
210
+ uri = '/' .join ([XERO_API_URL , self .name ])
224
211
if kwargs :
225
212
if kwargs .has_key ('Since' ):
226
213
val = kwargs ['Since' ]
227
214
headers = self .prepare_filtering_date (val )
228
215
del kwargs ['Since' ]
229
216
230
- params = ['%s==%s' % (key .replace ('_' ,'.' ),
231
- self .get_filter_params (key , kwargs [key ])) \
232
- for key in kwargs .keys ()]
217
+ def get_filter_params ():
218
+ if key in self .BOOLEAN_FIELDS :
219
+ return 'true' if kwargs [key ] else 'false'
220
+ elif key in self .DATETIME_FIELDS :
221
+ return kwargs [key ].isoformat ()
222
+ else :
223
+ return '"%s"' % str (kwargs [key ])
224
+
225
+ def generate_param (key ):
226
+ return '%s==%s' % (
227
+ key .replace ('_' ,'.' ),
228
+ get_filter_params ()
229
+ )
230
+
231
+ params = [generate_param (key ) for key in kwargs .keys ()]
233
232
234
233
if params :
235
234
uri += '?where=' + urllib .quote ('&&' .join (params ))
236
235
237
236
return uri , 'GET' , None , headers
238
237
239
238
def all (self ):
240
- name = self .get_url_postfix ()
241
- uri = '/' .join ([XERO_API_URL , name ])
239
+ uri = '/' .join ([XERO_API_URL , self .name ])
242
240
return uri , 'GET' , None , None
243
241
244
242
class Xero (object ):
245
- """ Main object for retriving data from XERO """
243
+ """
244
+ An ORM interface to the Xero API
245
+
246
+ This has only been tested with the Private API
247
+ """
246
248
247
- INSTANCES__LIST = (u'Contacts' , u'Accounts' , u'CreditNotes' ,
248
- u'Currencies' , u'Invoices' , u'Organisation' ,
249
- u'Payments' , u'TaxRates' , u'TrackingCategories' )
249
+ OBJECT_LIST = (u'Contacts' , u'Accounts' , u'CreditNotes' ,
250
+ u'Currencies' , u'Invoices' , u'Organisation' ,
251
+ u'Payments' , u'TaxRates' , u'TrackingCategories' )
250
252
251
253
def __init__ (self , consumer_key , consumer_secret , privatekey ):
252
- self .consumer_key = consumer_key
253
- self .consumer_secret = consumer_secret
254
- self .privatekey = privatekey
255
- self .client = XeroPrivateClient (consumer_key , consumer_secret ,
256
- privatekey )
257
- self .__set_managers (self .client )
258
-
259
- def __set_managers (self , client ):
260
- for name in self .INSTANCES__LIST :
254
+ # instantiate our private api client
255
+ client = XeroPrivateClient (consumer_key ,
256
+ consumer_secret ,
257
+ privatekey )
258
+
259
+ # iterate through the list of objects we support, for
260
+ # each of them create an attribute on our self that is
261
+ # the lowercase name of the object and attach it to an
262
+ # instance of a Manager object to operate on it
263
+ for name in self .OBJECT_LIST :
261
264
setattr (self , name .lower (), Manager (name , client ))
0 commit comments