1# gnucash_business.py -- High level python wrapper classes for the business
2#                        parts of GnuCash
3#
4# Copyright (C) 2008,2010 ParIT Worker Co-operative <paritinfo@parit.ca>
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; either version 2 of
8# the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, contact:
17# Free Software Foundation           Voice:  +1-617-542-5942
18# 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
19# Boston, MA  02110-1301,  USA       gnu@gnu.org
20#
21# @author Mark Jenkins, ParIT Worker Co-operative <mark@parit.ca>
22# @author Jeff Green,   ParIT Worker Co-operative <jeff@parit.ca>
23##  @file
24#   @brief High level python wrapper classes for the business parts of GnuCash
25#   @author Mark Jenkins, ParIT Worker Co-operative <mark@parit.ca>
26#   @author Jeff Green,   ParIT Worker Co-operative <jeff@parit.ca>
27#   @ingroup python_bindings
28
29import gnucash.gnucash_core_c as gnucash_core_c
30
31from gnucash.function_class import \
32     ClassFromFunctions, extract_attributes_with_prefix, \
33     default_arguments_decorator, method_function_returns_instance, \
34     methods_return_instance, methods_return_instance_lists
35
36from gnucash.gnucash_core import \
37     GnuCashCoreClass, GncNumeric, GncCommodity, Transaction, \
38     Split, Book, GncLot, Account, GUID
39
40from gnucash.gnucash_core_c import GNC_OWNER_CUSTOMER, GNC_OWNER_JOB, \
41    GNC_OWNER_EMPLOYEE, GNC_OWNER_VENDOR, \
42    GNC_PAYMENT_CASH, GNC_PAYMENT_CARD, \
43    GNC_DISC_PRETAX, GNC_DISC_SAMETIME, GNC_DISC_POSTTAX, \
44    GNC_TAXINCLUDED_YES, GNC_TAXINCLUDED_NO, GNC_TAXINCLUDED_USEGLOBAL, \
45    GNC_AMT_TYPE_VALUE, GNC_AMT_TYPE_PERCENT, GNC_ID_INVOICE
46
47import datetime
48
49class GnuCashBusinessEntity(GnuCashCoreClass):
50    def __init__(self, book=None, id=None, currency=None, name=None,
51                 instance=None):
52        if instance == None:
53            if book==None or id==None or currency==None:
54                raise Exception(
55                    "you must call GnuCashBusinessEntity.__init__ "
56                    "with either a book, id, and currency, or an existing "
57                    "low level swig proxy in the argument instance")
58            GnuCashCoreClass.__init__(self, book)
59            self.BeginEdit()
60            self.SetID(id)
61            self.SetCurrency(currency)
62            if name != None:
63                self.SetName(name)
64            self.CommitEdit()
65        else:
66            GnuCashCoreClass.__init__(self, instance=instance)
67
68class Customer(GnuCashBusinessEntity): pass
69
70class Employee(GnuCashBusinessEntity): pass
71
72class Vendor(GnuCashBusinessEntity): pass
73
74class Job(GnuCashBusinessEntity):
75    # override the superclass constructor, as Job doesn't require
76    # a currency but it does require an owner
77    def __init__(self, book=None, id=None, owner=None, name=None,
78                 instance=None):
79        if instance == None:
80            if book==None or id==None or owner==None:
81                raise Exception(
82                    "you must call Job.__init__ "
83                    "with either a book, id, and owner or an existing "
84                    "low level swig proxy in the argument instance")
85            GnuCashCoreClass.__init__(self, book)
86            self.SetID(id)
87            self.SetOwner(owner)
88            if name != None:
89                self.SetName(name)
90        else:
91            GnuCashCoreClass.__init__(self, instance=instance)
92
93class Address(GnuCashCoreClass): pass
94
95class BillTerm(GnuCashCoreClass): pass
96
97class TaxTable(GnuCashCoreClass):
98    def __init__(self, book=None, name=None, first_entry=None, instance=None):
99        if instance == None:
100            if book==None or name==None or first_entry==None:
101                raise Exception(
102                    "you must call TaxTable.__init__  with either a "
103                    "book, name, and first_entry, or an existing "
104                    "low level swig proxy in the argument instance")
105            GnuCashCoreClass.__init__(self, book)
106            self.SetName(name)
107            self.AddEntry(first_entry)
108        else:
109            GnuCashCoreClass.__init__(self, instance=instance)
110
111class TaxTableEntry(GnuCashCoreClass):
112    def __init__(self, account=None, percent=True, amount=None, instance=None):
113        """TaxTableEntry constructor
114
115        You must provide an account, or be initizing this with an existing
116        swig proxy object via the instance keyword argument.
117
118        You may also optionally set the percent keyword argument to False to get
119        a fixed value instead of percentage based tax (which is the default, or
120        when percent=True).
121
122        The tax will be zero percent or zero unless you set the amount keyword
123        argument to a GncNumeric value as well.
124        """
125
126        if instance == None:
127            if account==None:
128                raise Exception(
129                    "you must call TaxTableEntry.__init__  with either a "
130                    "account or an existing "
131                    "low level swig proxy in the argument instance")
132            GnuCashCoreClass.__init__(self)
133            self.SetAccount(account)
134            if percent:
135                self.SetType(GNC_AMT_TYPE_PERCENT)
136            else:
137                self.SetType(GNC_AMT_TYPE_VALUE)
138            if amount != None:
139                self.SetAmount(amount)
140        else:
141            GnuCashCoreClass.__init__(self, instance=instance)
142
143class Invoice(GnuCashCoreClass):
144    def __init__(self, book=None, id=None, currency=None, owner=None,
145                 date_opened=None, instance=None):
146        """Invoice Constructor
147
148        You must provide a book, id, currency and owner
149        (Customer, Job, Employee, Vendor) or an existing swig proxy object
150        in the keyword argument instance.
151
152        Optionally, you may provide a date the invoice is opened on
153        (datetime.date or datetime.datetime), otherwise today's date is used.
154        """
155        if instance == None:
156            if book==None or id==None or currency==None or owner==None:
157                raise Exception(
158                    "you must call Invoice.__init__ "
159                    "with either a book, id, currency and owner, or an existing"
160                    "low level swig proxy in the argument instance")
161            GnuCashCoreClass.__init__(self, book)
162            self.BeginEdit()
163            self.SetID(id)
164            self.SetCurrency(currency)
165            self.SetOwner(owner)
166            if date_opened == None:
167                date_opened = datetime.date.today()
168            self.SetDateOpened(date_opened)
169            self.CommitEdit()
170        else:
171            GnuCashCoreClass.__init__(self, instance=instance)
172
173class Bill(Invoice):
174    pass
175
176def decorate_to_return_instance_instead_of_owner(dec_function):
177    def new_get_owner_function(self):
178        (owner_type, instance) = dec_function(self)
179        if owner_type == GNC_OWNER_CUSTOMER:
180            return Customer(instance=instance)
181        elif owner_type == GNC_OWNER_JOB:
182            return Job(instance=instance)
183        elif owner_type == GNC_OWNER_EMPLOYEE:
184            return Employee(instance=instance)
185        elif owner_type == GNC_OWNER_VENDOR:
186            return Vendor(instance=instance)
187        else:
188            return None
189    return new_get_owner_function
190
191class Entry(GnuCashCoreClass):
192    def __init__(self, book=None, invoice=None, date=None, instance=None):
193        """Invoice Entry constructor
194
195        You must provide a book or be initizing this with an existing
196        swig proxy object via the instance keyword argument.
197
198        The optional invoice argument can be set to a Bill or Invoice
199        that you would like to associate the entry with. You might as well
200        assign one now, as an Entry can't exist without one, but you can
201        always use Invoice.AddEntry or Bill.AddEntry later on.
202
203        By default, the entry will be set to today's date unless you
204        override with the date argument.
205        """
206        if instance == None:
207            if book==None:
208                raise Exception(
209                    "you must call Entry.__init__  with either a "
210                    "book or an existing "
211                    "low level swig proxy in the argument instance")
212            GnuCashCoreClass.__init__(self, book)
213
214            if date == None:
215                date = datetime.date.today()
216            self.SetDate(date)
217            if invoice != None:
218                invoice.AddEntry(self)
219        else:
220            GnuCashCoreClass.__init__(self, instance=instance)
221
222    def test_type(self, invoice):
223        if invoice.GetTypeString() == "Invoice" and self.GetInvoice() == None:
224            raise Exception("Entry type error. Check that Entry type matches Invoice.")
225        if invoice.GetTypeString() == "Bill" and self.GetBill() == None:
226            raise Exception("Entry type error. Check that Entry type matches Bill.")
227
228# Owner
229GnuCashBusinessEntity.add_methods_with_prefix('gncOwner')
230
231owner_dict = {
232                    'GetGUID' : GUID,
233                    'GetCustomer' : Customer,
234                    'GetVendor' : Vendor,
235                    'GetEmployee' : Employee,
236                    'GetJob' : Job,
237                    'GetAddr' : Address,
238                    'GetCurrency' : GncCommodity,
239                    'GetEndOwner': GnuCashBusinessEntity,
240                    'GetBalanceInCurrency': GncNumeric,
241              }
242methods_return_instance(GnuCashBusinessEntity, owner_dict)
243
244methods_return_instance_lists(
245    GnuCashBusinessEntity, {
246        'GetCommoditiesList': GncCommodity
247    })
248
249# Customer
250Customer.add_constructor_and_methods_with_prefix('gncCustomer', 'Create')
251Customer.add_method('gncOwnerApplyPaymentSecs', 'ApplyPayment')
252
253customer_dict = {
254                    'GetAddr' : Address,
255                    'GetShipAddr' : Address,
256                    'GetDiscount' : GncNumeric,
257                    'GetCredit' : GncNumeric,
258                    'GetTerms' : BillTerm,
259                    'GetCurrency' : GncCommodity,
260                    'GetTaxTable': TaxTable,
261                }
262methods_return_instance(Customer, customer_dict)
263
264# Employee
265Employee.add_constructor_and_methods_with_prefix('gncEmployee', 'Create')
266
267employee_dict = {
268                    'GetBook' : Book,
269                    'GetAddr' : Address,
270                    'GetWorkday' : GncNumeric,
271                    'GetRate' : GncNumeric,
272                    'GetCurrency' : GncCommodity
273                }
274methods_return_instance(Employee, employee_dict)
275
276# Vendor
277Vendor.add_constructor_and_methods_with_prefix('gncVendor', 'Create')
278
279vendor_dict =   {
280                    'GetAddr' : Address,
281                    'GetTerms' : BillTerm,
282                    'GetCurrency' : GncCommodity,
283                    'GetTaxTable': TaxTable,
284                }
285methods_return_instance(Vendor, vendor_dict)
286
287# Job
288Job.add_constructor_and_methods_with_prefix('gncJob', 'Create')
289Job.decorate_functions(
290    decorate_to_return_instance_instead_of_owner,
291    'GetOwner')
292
293# Address
294Address.add_constructor_and_methods_with_prefix('gncAddress', 'Create')
295
296# BillTerm
297BillTerm.add_constructor_and_methods_with_prefix('gncBillTerm', 'Create')
298
299billterm_dict = {
300                    'LookupByName' : BillTerm,
301                    'GetDiscount' : GncNumeric,
302                    'GetParent' : BillTerm,
303                    'ReturnChild' : BillTerm
304                }
305methods_return_instance(BillTerm, billterm_dict)
306
307# TaxTable
308TaxTable.add_constructor_and_methods_with_prefix('gncTaxTable', 'Create')
309
310taxtable_dict = {
311                    'GetParent': TaxTable,
312                }
313methods_return_instance(TaxTable, taxtable_dict)
314
315# TaxTableEntry
316TaxTableEntry.add_constructor_and_methods_with_prefix(
317    'gncTaxTableEntry', 'Create')
318
319taxtableentry_dict = {
320                         'GetAccount': Account,
321                         'GetAmount': GncNumeric,
322                     }
323
324# Invoice
325Invoice.add_constructor_and_methods_with_prefix('gncInvoice', 'Create')
326methods_return_instance_lists(
327    Invoice, { 'GetEntries': Entry })
328
329Invoice.add_method('gncInvoiceRemoveEntry', 'RemoveEntry')
330Invoice.add_method('gncInvoiceUnpost', 'Unpost')
331
332# Bill
333Bill.add_methods_with_prefix('gncBill')
334
335invoice_dict = {
336                   'GetTerms': BillTerm,
337                   'GetCurrency': GncCommodity,
338                   'GetToChargeAmount': GncNumeric,
339                   'GetPostedLot': GncLot,
340                   'GetPostedTxn': Transaction,
341                   'GetPostedAcc': Account,
342                   'GetTotal': GncNumeric,
343                   'GetTotalOf': GncNumeric,
344                   'GetTotalSubtotal': GncNumeric,
345                   'GetTotalTax': GncNumeric,
346                   'PostToAccount': Transaction,
347                   'GetBook': Book,
348               }
349methods_return_instance(Invoice, invoice_dict)
350Invoice.decorate_functions(
351    decorate_to_return_instance_instead_of_owner,
352    'GetOwner', 'GetBillTo')
353
354# Entry
355Entry.add_constructor_and_methods_with_prefix('gncEntry', 'Create')
356
357Entry.add_method('gncEntryGetGUID', 'GetGUID')
358Entry.add_method('gncEntryDestroy', 'Destroy')
359
360entry_dict = {
361                 'GetGUID' : GUID,
362                 'GetQuantity': GncNumeric,
363                 'GetInvAccount': Account,
364                 'GetInvPrice': GncNumeric,
365                 'GetInvDiscount': GncNumeric,
366                 'GetInvTaxTable': TaxTable,
367                 'GetBillAccount': Account,
368                 'GetBillPrice': GncNumeric,
369                 'GetBillTaxTable': TaxTable,
370                 'Copy': Entry,
371                 'GetInvoice': Invoice,
372                 'GetBill': Invoice
373             }
374methods_return_instance(Entry, entry_dict)
375Entry.decorate_functions(
376    decorate_to_return_instance_instead_of_owner,
377    'GetBillTo' )
378
379from gnucash.gnucash_core import decorate_monetary_list_returning_function
380Entry.decorate_functions(decorate_monetary_list_returning_function, 'GetBalTaxValues')
381