Skip to content

Commit 556f59f

Browse files
authored
Merge pull request #12 from yaqwsx/master
Add support for Expenses
2 parents 85cef49 + a2fde2e commit 556f59f

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

fakturoid/api.py

+76-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import requests
77

8-
from fakturoid.models import Account, Subject, Invoice, Generator, Message
8+
from fakturoid.models import Account, Subject, Invoice, Generator, Message, Expense
99
from fakturoid.paging import ModelList
1010

1111
__all__ = ['Fakturoid']
@@ -31,6 +31,7 @@ def __init__(self, slug, email, api_key, user_agent=None):
3131
Account: AccountApi(self),
3232
Subject: SubjectsApi(self),
3333
Invoice: InvoicesApi(self),
34+
Expense: ExpensesApi(self),
3435
Generator: GeneratorsApi(self),
3536
Message: MessagesApi(self),
3637
}
@@ -89,6 +90,18 @@ def invoices(self, mapi, *args, **kwargs):
8990
def fire_invoice_event(self, mapi, id, event, **kwargs):
9091
return mapi.fire(id, event, **kwargs)
9192

93+
@model_api(Expense)
94+
def expense(self, mapi, id):
95+
return mapi.load(id)
96+
97+
@model_api(Expense)
98+
def expenses(self, mapi, *args, **kwargs):
99+
return mapi.find(*args, **kwargs)
100+
101+
@model_api(Expense)
102+
def fire_expense_event(self, mapi, id, event, **kwargs):
103+
return mapi.fire(id, event, **kwargs)
104+
92105
@model_api(Generator)
93106
def generator(self, mapi, id):
94107
return mapi.load(id)
@@ -308,6 +321,68 @@ def find(self, proforma=None, subject_id=None, since=None, updated_since=None, n
308321
return ModelList(self, endpoint, params)
309322

310323

324+
class ExpensesApi(CrudModelApi):
325+
"""If number argument is givent returms single Expense object (or None),
326+
otherwise iterable list of expenses are returned.
327+
"""
328+
model_type = Expense
329+
endpoint = 'expenses'
330+
331+
STATUSES = ['open', 'overdue', 'paid']
332+
EVENTS = ['remove_payment', 'deliver', 'pay', 'lock', 'unlock']
333+
EVENT_ARGS = {
334+
'pay': {'paid_on', 'paid_amount', 'variable_symbol', 'bank_account_id'}
335+
}
336+
337+
def fire(self, expense_id, event, **kwargs):
338+
if not isinstance(expense_id, int):
339+
raise TypeError('expense_id must be int')
340+
if event not in self.EVENTS:
341+
raise ValueError('invalid event, expected one of {0}'.format(', '.join(self.EVENTS)))
342+
343+
allowed_args = self.EVENT_ARGS.get(event, set())
344+
if not set(kwargs.keys()).issubset(allowed_args):
345+
msg = "invalid event arguments, only {0} can be used with {1}".format(', '.join(allowed_args), event)
346+
raise ValueError(msg)
347+
348+
params = {'event': event}
349+
params.update(kwargs)
350+
351+
if 'paid_on' in params:
352+
if not isinstance(params['paid_on'], date):
353+
raise TypeError("'paid_on' argument must be date")
354+
params['paid_on'] = params['paid_on'].isoformat()
355+
356+
self.session._post('expenses/{0}/fire'.format(expense_id), {}, params=params)
357+
358+
def find(self, subject_id=None, since=None, updated_since=None, number=None, status=None, custom_id=None, variable_symbol=None):
359+
params = {}
360+
if subject_id:
361+
if not isinstance(subject_id, int):
362+
raise TypeError("'subject_id' parameter must be int")
363+
params['subject_id'] = subject_id
364+
if since:
365+
if not isinstance(since, (datetime, date)):
366+
raise TypeError("'since' parameter must be date or datetime")
367+
params['since'] = since.isoformat()
368+
if updated_since:
369+
if not isinstance(updated_since, (datetime, date)):
370+
raise TypeError("'updated_since' parameter must be date or datetime")
371+
params['updated_since'] = updated_since.isoformat()
372+
if number:
373+
params['number'] = number
374+
if custom_id:
375+
params['custom_id'] = custom_id
376+
if status:
377+
if status not in self.STATUSES:
378+
raise ValueError('invalid invoice status, expected one of {0}'.format(', '.join(self.STATUSES)))
379+
params['status'] = status
380+
if variable_symbol:
381+
params['variable_symbol'] = variable_symbol
382+
383+
return ModelList(self, self.endpoint, params)
384+
385+
311386
class GeneratorsApi(CrudModelApi):
312387
model_type = Generator
313388
endpoint = 'generators'

fakturoid/models.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
from fakturoid import six
77

8-
__all__ = ['Account', 'Subject', 'InvoiceLine', 'Invoice', 'Generator', 'Message']
8+
__all__ = ['Account', 'Subject', 'InvoiceLine', 'Invoice', 'Generator',
9+
'Message', 'Expense']
910

1011

1112
class Model(six.UnicodeMixin):
@@ -160,6 +161,27 @@ def __unicode__(self):
160161
return self.number
161162

162163

164+
class Expense(AbstractInvoice):
165+
"""See http://docs.fakturoid.apiary.io/ for complete field reference."""
166+
number = None
167+
168+
class Meta:
169+
readonly = [
170+
'id', 'supplier_name', 'supplier_street', 'supplier_city',
171+
'supplier_zip', 'supplier_country', 'supplier_registration_no',
172+
'supplier_vat_no', 'status', 'paid_on', 'subtotal', 'total',
173+
'native_subtotal', 'native_total', 'html_url', 'url', 'subject_url',
174+
'created_at', 'updated_at'
175+
]
176+
decimal = [
177+
'exchange_rate', 'subtotal', 'total',
178+
'native_subtotal', 'native_total'
179+
]
180+
181+
def __unicode__(self):
182+
return self.number
183+
184+
163185
class Generator(AbstractInvoice):
164186
"""See http://docs.fakturoid.apiary.io/ for complete field reference."""
165187
name = None

0 commit comments

Comments
 (0)