GnuCash c935c2f+
Loading...
Searching...
No Matches
gnucash_core.py
Go to the documentation of this file.
1# gnucash_core.py -- High level python wrapper classes for the core parts
2# of GnuCash
3#
4# Copyright (C) 2008 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
24# The following is for doxygen
25
26
28
29
32
33
152
153
154
159
160import operator
161
162from enum import IntEnum
163from urllib.parse import urlparse
164
165from gnucash import gnucash_core_c
166from gnucash import _sw_core_utils
167
168from gnucash.function_class import \
169 ClassFromFunctions, extract_attributes_with_prefix, \
170 default_arguments_decorator, method_function_returns_instance, \
171 methods_return_instance, process_list_convert_to_instance, \
172 method_function_returns_instance_list, methods_return_instance_lists
173
174from gnucash.gnucash_core_c import gncInvoiceLookup, gncInvoiceGetInvoiceFromTxn, \
175 gncInvoiceGetInvoiceFromLot, gncEntryLookup, gncInvoiceLookup, \
176 gncCustomerLookup, gncVendorLookup, gncJobLookup, gncEmployeeLookup, \
177 gncTaxTableLookup, gncTaxTableLookupByName, gnc_search_invoice_on_id, \
178 gnc_search_customer_on_id, gnc_search_bill_on_id , \
179 gnc_search_vendor_on_id, gncInvoiceNextID, gncCustomerNextID, \
180 gncVendorNextID, gncTaxTableGetTables, gnc_numeric_zero, \
181 gnc_numeric_create, double_to_gnc_numeric, gnc_numeric_from_string, \
182 gnc_numeric_to_string, gnc_numeric_check
183
184from gnucash.deprecation import (
185 deprecated_args_session,
186 deprecated_args_session_init,
187 deprecated_args_session_begin,
188 deprecated
189)
190
191try:
192 import gettext
193
194 _localedir = _sw_core_utils.gnc_path_get_localedir()
195 gettext.install(_sw_core_utils.GETTEXT_PACKAGE, _localedir)
196except:
197 print()
198 print("Problem importing gettext!")
199 import traceback
200 import sys
201 exc_type, exc_value, exc_traceback = sys.exc_info()
202 traceback.print_exception(exc_type, exc_value, exc_traceback)
203 print()
204
205 def _(s):
206 """Null translator function, gettext not available"""
207 return s
208
209 import builtins
210 builtins.__dict__['_'] = _
211
212class GnuCashCoreClass(ClassFromFunctions):
213 _module = gnucash_core_c
214
215 def do_lookup_create_oo_instance(self, lookup_function, cls, *args):
216 thing = lookup_function(self.get_instance(), *args)
217 if thing != None:
218 thing = cls(instance=thing)
219 return thing
220
221
222class GnuCashBackendException(Exception):
223 def __init__(self, msg, errors):
224 Exception.__init__(self, msg)
225 self.errors = errors
226
227
228class SessionOpenMode(IntEnum):
229 """Mode for opening sessions.
230
231 This replaces three booleans that were passed in order: ignore_lock, create,
232 and force. It's structured so that one can use it as a bit field with the
233 values in the same order, i.e. ignore_lock = 1 << 2, create_new = 1 << 1, and
234 force_new = 1.
235
236 enumeration members
237 -------------------
238
239 SESSION_NORMAL_OPEN = 0 (All False)
240 Open will fail if the URI doesn't exist or is locked.
241
242 SESSION_NEW_STORE = 2 (False, True, False (create))
243 Create a new store at the URI. It will fail if the store already exists and is found to contain data that would be overwritten.
244
245 SESSION_NEW_OVERWRITE = 3 (False, True, True (create | force))
246 Create a new store at the URI even if a store already exists there.
247
248 SESSION_READ_ONLY = 4, (True, False, False (ignore_lock))
249 Open the session read-only, ignoring any existing lock and not creating one if the URI isn't locked.
250
251 SESSION_BREAK_LOCK = 5 (True, False, True (ignore_lock | force))
252 Open the session, taking over any existing lock.
253
254 source: lignucash/engine/qofsession.h
255 """
256
257 SESSION_NORMAL_OPEN = gnucash_core_c.SESSION_NORMAL_OPEN
258 """All False
259 Open will fail if the URI doesn't exist or is locked."""
260
261 SESSION_NEW_STORE = gnucash_core_c.SESSION_NEW_STORE
262 """False, True, False (create)
263 Create a new store at the URI. It will fail if the store already exists and is found to contain data that would be overwritten."""
264
265 SESSION_NEW_OVERWRITE = gnucash_core_c.SESSION_NEW_OVERWRITE
266 """False, True, True (create | force)
267 Create a new store at the URI even if a store already exists there."""
268
269 SESSION_READ_ONLY = gnucash_core_c.SESSION_READ_ONLY
270 """True, False, False (ignore_lock)
271 Open the session read-only, ignoring any existing lock and not creating one if the URI isn't locked."""
272
273 SESSION_BREAK_LOCK = gnucash_core_c.SESSION_BREAK_LOCK
274 """True, False, True (ignore_lock | force)
275 Open the session, taking over any existing lock."""
276
277
279 """A GnuCash book editing session
280
281 To commit changes to the session you may need to call save,
282 (this is always the case with the file backend).
283
284 When you're down with a session you may need to call end()
285
286 Every Session has a Book in the book attribute, which you'll definitely
287 be interested in, as every GnuCash entity (Transaction, Split, Vendor,
288 Invoice..) is associated with a particular book where it is stored.
289 """
290
291 @deprecated_args_session_init
292 def __init__(self, book_uri=None, mode=None, instance=None, book=None):
293 """!
294 A convenient constructor that allows you to specify a book URI,
295 begin the session, and load the book.
296
297 This can give you the power of calling
298 qof_session_new, qof_session_begin, and qof_session_load all in one!
299
300 qof_session_load is only called if url scheme is "xml" and
301 mode is SESSION_NEW_STORE or SESSION_NEW_OVERWRITE
302
303 @param book_uri must be a string in the form of a URI/URL. The access
304 method specified depends on the loaded backends. Paths may be relative
305 or absolute. If the path is relative, that is if the argument is
306 "file://somefile.xml", then the current working directory is
307 assumed. Customized backends can choose to search other
308 application-specific directories or URI schemes as well.
309 It be None to skip the calls to qof_session_begin and
310 qof_session_load.
311
312 @param instance argument can be passed if new Session is used as a
313 wrapper for an existing session instance
314
315 @param mode The SessionOpenMode.
316 @note SessionOpenMode replaces deprecated ignore_lock, is_new and force_new.
317
318 @par SessionOpenMode
319 `SESSION_NORMAL_OPEN`: Find an existing file or database at the provided uri and
320 open it if it is unlocked. If it is locked post a QOF_BACKEND_LOCKED error.
321 @par
322 `SESSION_NEW_STORE`: Check for an existing file or database at the provided
323 uri and if none is found, create it. If the file or database exists post a
324 QOF_BACKED_STORE_EXISTS and return.
325 @par
326 `SESSION_NEW_OVERWRITE`: Create a new file or database at the provided uri,
327 deleting any existing file or database.
328 @par
329 `SESSION_READ_ONLY`: Find an existing file or database and open it without
330 disturbing the lock if it exists or setting one if not. This will also set a
331 flag on the book that will prevent many elements from being edited and will
332 prevent the backend from saving any edits.
333 @par
334 `SESSION_BREAK_LOCK`: Find an existing file or database, lock it, and open
335 it. If there is already a lock replace it with a new one for this session.
336
337 @par Errors
338 qof_session_begin() signals failure by queuing errors. After it completes use
339 qof_session_get_error() and test that the value is `ERROR_BACKEND_NONE` to
340 determine that the session began successfully.
341
342 @exception as begin() and load() are wrapped with raise_backend_errors_after_call()
343 this function can raise a GnuCashBackendException. If it does,
344 you don't need to cleanup and call end() and destroy(), that is handled
345 for you, and the exception is raised.
346 """
347 if instance is not None:
348 GnuCashCoreClass.__init__(self, instance=instance)
349 else:
350 if book is None:
351 book = Book()
352 GnuCashCoreClass.__init__(self, book)
353
354 if book_uri is not None:
355 try:
356 if mode is None:
357 mode = SessionOpenMode.SESSION_NORMAL_OPEN
358 self.begin(book_uri, mode)
359 is_new = mode in (SessionOpenMode.SESSION_NEW_STORE, SessionOpenMode.SESSION_NEW_OVERWRITE)
360 if not is_new:
361 self.load()
362 except GnuCashBackendException as backend_exception:
363 self.end()
364 self.destroy()
365 raise
366
367 def __enter__(self):
368 return self
369
370 def __exit__(self, exc_type, exc_value, traceback):
371 # Roll back changes on exception by not calling save. Only works for XMl backend.
372 if not exc_type:
373 self.save()
374 self.end()
375 self.destroy()
376
377 def raise_backend_errors(self, called_function="qof_session function"):
378 """Raises a GnuCashBackendException if there are outstanding
379 QOF_BACKEND errors.
380
381 set called_function to name the function that was last called
382 """
383 errors = self.pop_all_errors()
384 if errors != ():
386 "call to %s resulted in the "
387 "following errors, %s" % (called_function, backend_error_dict[errors[0]]),
388 errors )
389
391 """A generator that yields any outstanding QofBackend errors
392 """
393 while self.get_error() is not ERR_BACKEND_NO_ERR:
394 error = self.pop_error()
395 yield error
396
397 def pop_all_errors(self):
398 """Returns any accumulated qof backend errors as a tuple
399 """
400 return tuple( self.generate_errors() )
401
402 # STATIC METHODS
403 @staticmethod
404 def raise_backend_errors_after_call(function, *args, **kwargs):
405 """A function decorator that results in a call to
406 raise_backend_errors after execution.
407 """
408 def new_function(self, *args, **kwargs):
409 return_value = function(self, *args, **kwargs)
410 self.raise_backend_errors(function.__name__)
411 return return_value
412 return new_function
413
415 """A Book encapsulates all of the GnuCash data, it is the place where
416 all GnuCash entities (Transaction, Split, Vendor, Invoice...), are
417 stored. You'll notice that all of the constructors for those entities
418 need a book to be associated with.
419
420 The most common way to get a book is through the book property in the
421 Session class, that is, create a session that connects to some storage,
422 such as through 'my_session = Session('file:my_books.xac')', and access
423 the book via the book property, 'my_session.book'
424
425 If you would like to create a Book without any backing storage, call the
426 Book constructor without any parameters, 'Book()'. You can later merge
427 such a book into a book with actual store by using merge_init.
428
429 Methods of interest
430 get_root_account -- Returns the root level Account
431 get_table -- Returns a commodity lookup table, of type GncCommodityTable
432 """
433 def InvoiceLookup(self, guid):
434 from gnucash.gnucash_business import Invoice
436 gncInvoiceLookup, Invoice, guid.get_instance() )
437
438 def EntryLookup(self, guid):
439 from gnucash.gnucash_business import Entry
441 gncEntryLookup, Entry, guid.get_instance() )
442
443 def CustomerLookup(self, guid):
444 from gnucash.gnucash_business import Customer
446 gncCustomerLookup, Customer, guid.get_instance())
447
448 def JobLookup(self, guid):
449 from gnucash.gnucash_business import Job
451 gncJobLookup, Job, guid.get_instance() )
452
453 def VendorLookup(self, guid):
454 from gnucash.gnucash_business import Vendor
456 gncVendorLookup, Vendor, guid.get_instance() )
457
458 def EmployeeLookup(self, guid):
459 from gnucash.gnucash_business import Employee
461 gncEmployeeLookup, Employee, guid.get_instance() )
462
463 def TaxTableLookup(self, guid):
464 from gnucash.gnucash_business import TaxTable
466 gncTaxTableLookup, TaxTable, guid.get_instance() )
467
468 def TaxTableLookupByName(self, name):
469 from gnucash.gnucash_business import TaxTable
471 gncTaxTableLookupByName, TaxTable, name)
472
473 def TaxTableGetTables(self):
474 from gnucash.gnucash_business import TaxTable
475 return [ TaxTable(instance=item) for item in gncTaxTableGetTables(self.instance) ]
476
477 def BillLookupByID(self, id):
478 from gnucash.gnucash_business import Bill
480 gnc_search_bill_on_id, Bill, id)
481
482 def InvoiceLookupByID(self, id):
483 from gnucash.gnucash_business import Invoice
485 gnc_search_invoice_on_id, Invoice, id)
486
487 def CustomerLookupByID(self, id):
488 from gnucash.gnucash_business import Customer
490 gnc_search_customer_on_id, Customer, id)
491
492 def VendorLookupByID(self, id):
493 from gnucash.gnucash_business import Vendor
495 gnc_search_vendor_on_id, Vendor, id)
496
497 def InvoiceNextID(self, customer):
498 ''' Return the next invoice ID.
499 '''
500 from gnucash.gnucash_core_c import gncInvoiceNextID
501 return gncInvoiceNextID(self.get_instance(),customer.GetEndOwner().get_instance()[1])
502
503 def BillNextID(self, vendor):
504 ''' Return the next Bill ID. '''
505 from gnucash.gnucash_core_c import gncInvoiceNextID
506 return gncInvoiceNextID(self.get_instance(),vendor.GetEndOwner().get_instance()[1])
507
508 def CustomerNextID(self):
509 ''' Return the next Customer ID. '''
510 from gnucash.gnucash_core_c import gncCustomerNextID
511 return gncCustomerNextID(self.get_instance())
512
513 def VendorNextID(self):
514 ''' Return the next Vendor ID. '''
515 from gnucash.gnucash_core_c import gncVendorNextID
516 return gncVendorNextID(self.get_instance())
517
519 """Object used by GnuCash to store all numbers. Always consists of a
520 numerator and denominator.
521
522 The constants GNC_DENOM_AUTO,
523 GNC_HOW_RND_FLOOR, GNC_HOW_RND_CEIL, GNC_HOW_RND_TRUNC,
524 GNC_HOW_RND_PROMOTE, GNC_HOW_RND_ROUND_HALF_DOWN,
525 GNC_HOW_RND_ROUND_HALF_UP, GNC_HOW_RND_ROUND, GNC_HOW_RND_NEVER,
526 GNC_HOW_DENOM_EXACT, GNC_HOW_DENOM_REDUCE, GNC_HOW_DENOM_LCD,
527 and GNC_HOW_DENOM_FIXED are available for arithmetic
528 functions like GncNumeric.add
529
530 Look at gnc-numeric.h to see how to use these
531 """
532
533 def __init__(self, *args, **kargs):
534 """Constructor that supports the following formats:
535 * No arguments defaulting to zero: eg. GncNumeric() == 0/1
536 * A integer: e.g. GncNumeric(1) == 1/1
537 * Numerator and denominator intager pair: eg. GncNumeric(1, 2) == 1/2
538 * A floating point number: e.g. GncNumeric(0.5) == 1/2
539 * A floating point number with defined conversion: e.g.
540 GncNumeric(0.5, GNC_DENOM_AUTO,
541 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER) == 1/2
542 * A string: e.g. GncNumeric("1/2") == 1/2
543 """
544 if 'instance' not in kargs:
545 kargs['instance'] = GncNumeric.__args_to_instance(args)
546 GnuCashCoreClass.__init__(self, [], **kargs)
547
548 @staticmethod
549 def __args_to_instance(args):
550 if len(args) == 0:
551 return gnc_numeric_zero()
552 elif len(args) == 1:
553 arg = args[0]
554 if isinstance(arg, int):
555 return gnc_numeric_create(arg, 1)
556 elif isinstance(arg, float):
557 return double_to_gnc_numeric(arg, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER)
558 elif isinstance(arg, str):
559 instance = gnc_numeric_from_string(arg)
560 if gnc_numeric_check(instance):
561 raise TypeError('Failed to convert to GncNumeric: ' + str(args))
562 return instance
563 elif isinstance(arg, GncNumeric):
564 return arg.instance
565 else:
566 raise TypeError('Only single int/float/str/GncNumeric allowed: ' + str(args))
567 elif len(args) == 2:
568 if isinstance(args[0], int) and isinstance(args[1], int):
569 return gnc_numeric_create(*args)
570 else:
571 raise TypeError('Only two ints allowed: ' + str(args))
572 elif len(args) == 3:
573 if isinstance(args[0], float) \
574 and isinstance(args[1], int) \
575 and type(args[2]) == type(GNC_HOW_DENOM_FIXED):
576 return double_to_gnc_numeric(*args)
577 else:
578 raise TypeError('Only (float, int, GNC_HOW_RND_*) allowed: ' + str(args))
579 else:
580 raise TypeError('Required single int/float/str or two ints: ' + str(args))
581
582 # from https://docs.python.org/3/library/numbers.html#numbers.Integral
583 # and https://github.com/python/cpython/blob/3.7/Lib/fractions.py
584
585 def _operator_fallbacks(monomorphic_operator, fallback_operator):
586 """fallbacks are not needed except for method name,
587 keep for possible later use"""
588 def forward(a, b):
589 if isinstance(b, GncNumeric):
590 return monomorphic_operator(a, b)
591 if isinstance(b, (int, float)):
592 return monomorphic_operator(a, GncNumeric(b))
593 else:
594 return NotImplemented
595 forward.__name__ = '__' + fallback_operator.__name__ + '__'
596 forward.__doc__ = monomorphic_operator.__doc__
597
598 def reverse(b, a):
599 if isinstance(a, (GncNumeric, int, float)):
600 return forward(b, a)
601 else:
602 return NotImplemented
603 reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
604 reverse.__doc__ = monomorphic_operator.__doc__
605
606 return forward, reverse
607
608 def _add(a, b):
609 return a.add(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
610
611 def _sub(a, b):
612 return a.sub(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
613
614 def _mul(a, b):
615 return a.mul(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
616
617 def _div(a, b):
618 return a.div(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
619
620 def _floordiv(a, b):
621 return a.div(b, 1, GNC_HOW_RND_TRUNC)
622
623 __add__, __radd__ = _operator_fallbacks(_add, operator.add)
624 __iadd__ = __add__
625 __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
626 __isub__ = __sub__
627 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
628 __imul__ = __mul__
629 __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
630 __itruediv__ = __truediv__
631 __floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
632 __ifloordiv__ = __floordiv__
633
634 # Comparisons derived from https://github.com/python/cpython/blob/3.7/Lib/fractions.py
635 def _lt(a, b):
636 return a.compare(b) == -1
637
638 def _gt(a, b):
639 return a.compare(b) == 1
640
641 def _le(a, b):
642 return a.compare(b) in (0,-1)
643
644 def _ge(a, b):
645 return a.compare(b) in (0,1)
646
647 def _eq(a, b):
648 return a.compare(b) == 0
649
650 def _richcmp(self, other, op):
651 """Helper for comparison operators, for internal use only.
652 Implement comparison between a GncNumeric instance `self`,
653 and either another GncNumeric instance, an int or a float
654 `other`. If `other` is not an instance of that kind, return
655 NotImplemented. `op` should be one of the six standard
656 comparison operators. The comparisons are based on
657 GncNumeric.compare().
658 """
659 import math
660 if isinstance(other, GncNumeric):
661 return op(other)
662 elif isinstance(other, (int, float)):
663 return op(GncNumeric(other))
664 else:
665 return NotImplemented
666
667 def __lt__(a, b):
668 """a < b"""
669 return a._richcmp(b, a._lt)
670
671 def __gt__(a, b):
672 """a > b"""
673 return a._richcmp(b, a._gt)
674
675 def __le__(a, b):
676 """a <= b"""
677 return a._richcmp(b, a._le)
678
679 def __ge__(a, b):
680 """a >= b"""
681 return a._richcmp(b, a._ge)
682
683 def __eq__(a, b):
684 """a == b"""
685 return a._richcmp(b, a._eq)
686
687 def __bool__(a):
688 """a != 0"""
689 return bool(a.num())
690
691 def __float__(self):
692 return self.to_double()
693
694 def __int__(self):
695 return int(self.to_double())
696
697 def __pos__(a):
698 """+a"""
699 return GncNumeric(a.num(), a.denom())
700
701 def __neg__(a):
702 """-a"""
703 return a.neg()
704
705 def __abs__(a):
706 """abs(a)"""
707 return a.abs()
708
709 def to_fraction(self):
710 from fractions import Fraction
711 return Fraction(self.num(), self.denom())
712
713 def __str__(self):
714 """Returns a human readable numeric value string as UTF8."""
715 return gnc_numeric_to_string(self.instance)
716
718 '''
719 Each priceEach price in the database represents an "instantaneous"
720 quote for a given commodity with respect to another commodity.
721 For example, a given price might represent the value of LNUX in USD on 2001-02-03.
722
723 Fields:
724 * commodity: the item being priced.
725 * currency: the denomination of the value of the item being priced.
726 * value: the value of the item being priced.
727 * time: the time the price was valid.
728 * source: a string describing the source of the quote. These strings will be something like this:
729 "Finance::Quote", "user:misc", "user:foo", etc. If the quote came from a user, as a matter of policy,
730 you *must* prefix the string you give with "user:". For now, the only other reserved values are
731 "Finance::Quote" and "old-file-import". Any string used must be added to the source_list array in
732 dialog-price-edit-db.c so that it can be properly translated. (There are unfortunately many strings
733 in users' databases, so this string must be translated on output instead of always being used in untranslated form).
734 * type: the type of quote - types possible right now are bid, ask, last, nav, and
735 unknown.Each price in the database represents an "instantaneous" quote for a given
736 commodity with respect to another commodity.
737 For example, a given price might represent the value of LNUX in USD on 2001-02-03.
738
739 See also https://code.gnucash.org/docs/head/group__Price.html
740 '''
741 _new_instance = 'gnc_price_create'
742GncPrice.add_methods_with_prefix('gnc_price_')
743
744
746 '''
747 a simple price database for gnucash.
748 The PriceDB is intended to be a database of price quotes, or more specifically,
749 a database of GNCPrices. For the time being, it is still a fairly simple
750 database supporting only fairly simple queries. It is expected that new
751 queries will be added as needed, and that there is some advantage to delaying
752 complex queries for now in the hope that we get a real DB implementation
753 before they're really needed.
754
755 Every QofBook contains a GNCPriceDB, accessible via gnc_pricedb_get_db.
756
757 Definition in file gnc-pricedb.h.
758 See also https://code.gnucash.org/docs/head/gnc-pricedb_8h.html
759 '''
760
761@deprecated("Use gnc_pricedb_latest_before_t64")
762def gnc_pricedb_lookup_latest_before_t64(self, commodity, currency, date):
763 return self.lookup_nearest_before_t64(commodity, currency, date)
764
765GncPriceDB.add_method('gnc_pricedb_lookup_latest_before_t64', 'lookup_latest_before_t64')
766
767GncPriceDB.lookup_latest_before_t64 = method_function_returns_instance(GncPriceDB.lookup_latest_before_t64, GncPrice)
768
769GncPriceDB.add_methods_with_prefix('gnc_pricedb_')
770PriceDB_dict = {
771 'lookup_latest' : GncPrice,
772 'lookup_nearest_in_time64' : GncPrice,
773 'lookup_nearest_before_t64' : GncPrice,
774 'nth_price' : GncPrice,
775 'lookup_day_t64' : GncPrice,
776 'convert_balance_latest_price' : GncNumeric,
777 'convert_balance_nearest_price_t64' : GncNumeric,
778 'convert_balance_nearest_before_price_t64' : GncNumeric,
779 'get_latest_price' : GncNumeric,
780 'get_nearest_price' : GncNumeric,
781 'get_nearest_before_price' : GncNumeric,
782 }
783methods_return_instance(GncPriceDB,PriceDB_dict)
784methods_return_instance_lists(
785 GncPriceDB, { 'get_prices': GncPrice,
786 'lookup_latest_any_currency': GncPrice,
787 'lookup_nearest_before_any_currency_t64': GncPrice,
788 'lookup_nearest_in_time_any_currency_t64': GncPrice,
789 })
790
792
794 """A CommodityTable provides a way to store and lookup commodities.
795 Commodities are primarily currencies, but other tradable things such as
796 stocks, mutual funds, and material substances are possible.
797
798 Users of this library should not create their own CommodityTable, instead
799 the get_table method from the Book class should be used.
800
801 This table is automatically populated with the GnuCash default commodity's
802 which includes most of the world's currencies.
803 """
804
805 def _get_namespaces_py(self):
806 return [ns.get_name() for ns in self.get_namespaces_list()]
807
811class GncLot(GnuCashCoreClass):
812 def GetInvoiceFromLot(self):
813 from gnucash.gnucash_business import Invoice
814 return self.do_lookup_create_oo_instance(
815 gncInvoiceGetInvoiceFromLot, Invoice )
816
818 """A GnuCash Transaction
819
820 Consists of at least one (generally two) splits to represent a transaction
821 between two accounts.
822
823
824 Has a GetImbalance() method that returns a list of all the imbalanced
825 currencies. Each list item is a two element tuple, the first element is
826 the imbalanced commodity, the second element is the value.
827
828 Warning, the commodity.get_instance() value can be None when there
829 is no currency set for the transaction.
830 """
831 _new_instance = 'xaccMallocTransaction'
832 def GetNthSplit(self, n):
833 return self.GetSplitList().pop(n)
834
835 def GetInvoiceFromTxn(self):
836 from gnucash.gnucash_business import Invoice
838 gncInvoiceGetInvoiceFromTxn, Invoice )
839
840 def __eq__(self, other):
841 return self.Equal(other, True, False, False, False)
842
843def decorate_monetary_list_returning_function(orig_function):
844 def new_function(self, *args):
845 """decorate function that returns list of gnc_monetary to return tuples of GncCommodity and GncNumeric
846
847 Args:
848 *args: Variable length argument list. Will get passed to orig_function
849
850 Returns:
851 array of tuples: (GncCommodity, GncNumeric)
852
853 ToDo:
854 Maybe this function should better reside in module function_class (?)"""
855 # warning, item.commodity has been shown to be None
856 # when the transaction doesn't have a currency
857 return [(GncCommodity(instance=item.commodity),
858 GncNumeric(instance=item.value))
859 for item in orig_function(self, *args) ]
860 return new_function
861
863 """A GnuCash Split
864
865 The most basic representation of a movement of currency from one account to
866 another.
867 """
868 _new_instance = 'xaccMallocSplit'
869
870 def __eq__(self, other):
871 return self.Equal(other, True, False, False)
872
874 """A GnuCash Account.
875
876 A fundamental entity in accounting, an Account provides representation
877 for a financial object, such as a ACCT_TYPE_BANK account, an
878 ACCT_TYPE_ASSET (like a building),
879 a ACCT_TYPE_LIABILITY (such as a bank loan), a summary of some type of
880 ACCT_TYPE_EXPENSE, or a summary of some source of ACCT_TYPE_INCOME .
881
882 The words in upper case are the constants that GnuCash and this library uses
883 to describe account type. Here is the full list:
884 ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
885 ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
886 ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
887 ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
888
889 These are not strings, they are attributes you can import from this
890 module
891 """
892 _new_instance = 'xaccMallocAccount'
893
895 _new_instance = 'guid_new_return'
896
897# Session
898Session.add_constructor_and_methods_with_prefix('qof_session_', 'new')
899
900def one_arg_default_none(function):
901 return default_arguments_decorator(function, None, None)
902Session.decorate_functions(one_arg_default_none, "load", "save")
903
904Session.decorate_functions( Session.raise_backend_errors_after_call,
905 "begin", "load", "save", "end")
906Session.decorate_method(default_arguments_decorator, "begin", None, mode=SessionOpenMode.SESSION_NORMAL_OPEN)
907Session.decorate_functions(deprecated_args_session_begin, "begin")
908
909Session.get_book = method_function_returns_instance(
910 Session.get_book, Book )
911
912Session.book = property( Session.get_book )
913
914# import all of the session backend error codes into this module
915this_module_dict = globals()
916for error_name, error_value, error_name_after_prefix in \
917 extract_attributes_with_prefix(gnucash_core_c, 'ERR_'):
918 this_module_dict[ error_name ] = error_value
919
920#backend error codes used for reverse lookup
921backend_error_dict = {}
922for error_name, error_value, error_name_after_prefix in \
923 extract_attributes_with_prefix(gnucash_core_c, 'ERR_'):
924 backend_error_dict[ error_value ] = error_name
925
926# GncNumeric denominator computation schemes
927# Used for the denom argument in arithmetic functions like GncNumeric.add
928from gnucash.gnucash_core_c import GNC_DENOM_AUTO
929
930# GncNumeric rounding instructions
931# used for the how argument in arithmetic functions like GncNumeric.add
932from gnucash.gnucash_core_c import \
933 GNC_HOW_RND_FLOOR, GNC_HOW_RND_CEIL, GNC_HOW_RND_TRUNC, \
934 GNC_HOW_RND_PROMOTE, GNC_HOW_RND_ROUND_HALF_DOWN, \
935 GNC_HOW_RND_ROUND_HALF_UP, GNC_HOW_RND_ROUND, GNC_HOW_RND_NEVER
936
937# GncNumeric denominator types
938# used for the how argument in arithmetic functions like GncNumeric.add
939from gnucash.gnucash_core_c import \
940 GNC_HOW_DENOM_EXACT, GNC_HOW_DENOM_REDUCE, GNC_HOW_DENOM_LCD, \
941 GNC_HOW_DENOM_FIXED, GNC_HOW_DENOM_SIGFIG
942
943# import account types
944from gnucash.gnucash_core_c import \
945 ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
946 ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
947 ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
948 ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
949
950#Book
951Book.add_constructor_and_methods_with_prefix('qof_book_', 'new')
952Book.add_method('gnc_book_get_root_account', 'get_root_account')
953Book.add_method('gnc_book_set_root_account', 'set_root_account')
954Book.add_method('gnc_commodity_table_get_table', 'get_table')
955Book.add_method('gnc_pricedb_get_db', 'get_price_db')
956Book.add_method('qof_book_increment_and_format_counter', 'increment_and_format_counter')
957
958#Functions that return Account
959Book.get_root_account = method_function_returns_instance(
960 Book.get_root_account, Account )
961#Functions that return GncCommodityTable
962Book.get_table = method_function_returns_instance(
963 Book.get_table, GncCommodityTable )
964#Functions that return GNCPriceDB
965Book.get_price_db = method_function_returns_instance(
966 Book.get_price_db, GncPriceDB)
967
968# GncNumeric
969GncNumeric.add_constructor_and_methods_with_prefix('gnc_numeric_', 'create')
970
971gncnumeric_dict = {
972 'same' : GncNumeric,
973 'add' : GncNumeric,
974 'sub' : GncNumeric,
975 'mul' : GncNumeric,
976 'div' : GncNumeric,
977 'neg' : GncNumeric,
978 'abs' : GncNumeric,
979 'add_fixed' : GncNumeric,
980 'sub_fixed' : GncNumeric,
981 'convert' : GncNumeric,
982 'reduce' : GncNumeric,
983 'invert' : GncNumeric
984 }
985methods_return_instance(GncNumeric, gncnumeric_dict)
986
987# GncCommodity
988GncCommodity.add_constructor_and_methods_with_prefix('gnc_commodity_', 'new')
989gnc_commodity_dict = {
990 'clone': GncCommodity,
991 'obtain_twin': GncCommodity,
992 'get_namespace_ds': GncCommodityNamespace,
993 }
994methods_return_instance(GncCommodity, gnc_commodity_dict)
995
996# GncPrice (deferred until after GncCommodity is defined)
997gnc_price_dict = {
998 'get_commodity': GncCommodity,
999 'get_currency': GncCommodity,
1000 'clone': GncPrice,
1001 'get_value': GncNumeric,
1002 }
1003methods_return_instance(GncPrice, gnc_price_dict)
1004
1005# GncCommodityTable
1006GncCommodityTable.add_methods_with_prefix('gnc_commodity_table_')
1007commoditytable_dict = {
1008 'lookup' : GncCommodity,
1009 'lookup_unique' : GncCommodity,
1010 'find_full' : GncCommodity,
1011 'insert' : GncCommodity,
1012 'add_namespace': GncCommodityNamespace,
1013 'find_namespace': GncCommodityNamespace,
1014 }
1015methods_return_instance(GncCommodityTable, commoditytable_dict)
1016
1017methods_return_instance_lists(
1018 GncCommodityTable, { 'get_namespaces_list': GncCommodityNamespace,
1019 'get_commodities': GncCommodity,
1020 'get_quotable_commodities': GncCommodity,
1021
1022 } )
1023setattr(GncCommodityTable, 'get_namespaces', getattr(GncCommodityTable, '_get_namespaces_py'))
1024
1025# GncCommodityNamespace
1026GncCommodityNamespace.add_methods_with_prefix('gnc_commodity_namespace_')
1027GncCommodityNamespace.get_commodity_list = \
1028 method_function_returns_instance_list(
1029 GncCommodityNamespace.get_commodity_list, GncCommodity )
1030
1031# GncLot
1032GncLot.add_constructor_and_methods_with_prefix('gnc_lot_', 'new')
1033
1034gnclot_dict = {
1035 'get_account' : Account,
1036 'get_book' : Book,
1037 'get_earliest_split' : Split,
1038 'get_latest_split' : Split,
1039 'get_balance' : GncNumeric,
1040 'lookup' : GncLot,
1041 'make_default' : GncLot
1042 }
1043methods_return_instance(GncLot, gnclot_dict)
1044methods_return_instance_lists(
1045 GncLot, { 'get_split_list': Split,
1046 })
1047
1048# Transaction
1049Transaction.add_methods_with_prefix('xaccTrans')
1050Transaction.add_method('gncTransGetGUID', 'GetGUID')
1051
1052Transaction.add_method('xaccTransGetDescription', 'GetDescription')
1053Transaction.add_method('xaccTransDestroy', 'Destroy')
1054
1055trans_dict = {
1056 'GetSplit': Split,
1057 'FindSplitByAccount': Split,
1058 'Clone': Transaction,
1059 'Reverse': Transaction,
1060 'GetReversedBy': Transaction,
1061 'GetImbalanceValue': GncNumeric,
1062 'GetAccountValue': GncNumeric,
1063 'GetAccountAmount': GncNumeric,
1064 'GetAccountConvRate': GncNumeric,
1065 'GetAccountBalance': GncNumeric,
1066 'GetCurrency': GncCommodity,
1067 'GetGUID': GUID
1068 }
1069
1070methods_return_instance(Transaction, trans_dict)
1071methods_return_instance_lists(
1072 Transaction, { 'GetSplitList': Split,
1073 })
1074Transaction.decorate_functions(
1075 decorate_monetary_list_returning_function, 'GetImbalance')
1076
1077# Split
1078Split.add_methods_with_prefix('xaccSplit')
1079Split.add_method('gncSplitGetGUID', 'GetGUID')
1080Split.add_method('xaccSplitDestroy', 'Destroy')
1081
1082split_dict = {
1083 'GetBook': Book,
1084 'GetAccount': Account,
1085 'GetParent': Transaction,
1086 'Lookup': Split,
1087 'GetOtherSplit': Split,
1088 'GetAmount': GncNumeric,
1089 'GetValue': GncNumeric,
1090 'GetSharePrice': GncNumeric,
1091 'ConvertAmount': GncNumeric,
1092 'GetBaseValue': GncNumeric,
1093 'GetBalance': GncNumeric,
1094 'GetClearedBalance': GncNumeric,
1095 'GetReconciledBalance': GncNumeric,
1096 'VoidFormerAmount': GncNumeric,
1097 'VoidFormerValue': GncNumeric,
1098 'GetNoclosingBalance': GncNumeric,
1099 'GetCapGains': GncNumeric,
1100 'GetGUID': GUID
1101 }
1102methods_return_instance(Split, split_dict)
1103
1104Split.account = property( Split.GetAccount, Split.SetAccount )
1105Split.parent = property( Split.GetParent, Split.SetParent )
1106
1107# Account
1108Account.add_methods_with_prefix('xaccAccount')
1109Account.add_methods_with_prefix('gnc_account_')
1110Account.add_method('gncAccountGetGUID', 'GetGUID')
1111Account.add_method('xaccAccountGetPlaceholder', 'GetPlaceholder')
1112
1113account_dict = {
1114 'get_book' : Book,
1115 'Lookup' : Account,
1116 'get_parent' : Account,
1117 'get_root' : Account,
1118 'nth_child' : Account,
1119 'lookup_by_code' : Account,
1120 'lookup_by_name' : Account,
1121 'lookup_by_full_name' : Account,
1122 'FindTransByDesc' : Transaction,
1123 'FindSplitByDesc' : Split,
1124 'GetBalance' : GncNumeric,
1125 'GetClearedBalance' : GncNumeric,
1126 'GetReconciledBalance' : GncNumeric,
1127 'GetPresentBalance' : GncNumeric,
1128 'GetProjectedMinimumBalance' : GncNumeric,
1129 'GetBalanceAsOfDate' : GncNumeric,
1130 'ConvertBalanceToCurrency' : GncNumeric,
1131 'ConvertBalanceToCurrencyAsOfDate' : GncNumeric,
1132 'GetBalanceInCurrency' : GncNumeric,
1133 'GetClearedBalanceInCurrency' : GncNumeric,
1134 'GetReconciledBalanceInCurrency' : GncNumeric,
1135 'GetPresentBalanceInCurrency' : GncNumeric,
1136 'GetProjectedMinimumBalanceInCurrency' : GncNumeric,
1137 'GetBalanceAsOfDateInCurrency' : GncNumeric,
1138 'GetBalanceChangeForPeriod' : GncNumeric,
1139 'GetCommodity' : GncCommodity,
1140 'get_currency_or_parent' : GncCommodity,
1141 'GetGUID': GUID
1142 }
1143methods_return_instance(Account, account_dict)
1144methods_return_instance_lists(
1145 Account, { 'GetSplitList': Split,
1146 'GetLotList': GncLot,
1147 'get_children': Account,
1148 'get_children_sorted': Account,
1149 'get_descendants': Account,
1150 'get_descendants_sorted': Account
1151 })
1152Account.name = property( Account.GetName, Account.SetName )
1153
1154#GUID
1155GUID.add_methods_with_prefix('guid_')
1156GUID.add_method('xaccAccountLookup', 'AccountLookup')
1157GUID.add_method('xaccTransLookup', 'TransLookup')
1158GUID.add_method('xaccSplitLookup', 'SplitLookup')
1159
1160
1161GUID.add_method('guid_to_string', 'to_string')
1162#GUID.add_method('string_to_guid', 'string_to_guid')
1163
1164guid_dict = {
1165 'copy' : GUID,
1166 'TransLookup': Transaction,
1167 'AccountLookup': Account,
1168 'SplitLookup': Split
1169 }
1170methods_return_instance(GUID, guid_dict)
1171
1172#GUIDString
1174 pass
1175
1176GUIDString.add_constructor_and_methods_with_prefix('string_', 'to_guid')
1177
1178#Query
1179from gnucash.gnucash_core_c import \
1180 QOF_QUERY_AND, \
1181 QOF_QUERY_OR, \
1182 QOF_QUERY_NAND, \
1183 QOF_QUERY_NOR, \
1184 QOF_QUERY_XOR
1185
1186from gnucash.gnucash_core_c import \
1187 QOF_STRING_MATCH_NORMAL, \
1188 QOF_STRING_MATCH_CASEINSENSITIVE
1189
1190from gnucash.gnucash_core_c import \
1191 QOF_COMPARE_LT, \
1192 QOF_COMPARE_LTE, \
1193 QOF_COMPARE_EQUAL, \
1194 QOF_COMPARE_GT, \
1195 QOF_COMPARE_GTE, \
1196 QOF_COMPARE_NEQ, \
1197 QOF_COMPARE_CONTAINS, \
1198 QOF_COMPARE_NCONTAINS
1199
1200from gnucash.gnucash_core_c import \
1201 QOF_DATE_MATCH_NORMAL, \
1202 QOF_DATE_MATCH_DAY
1203
1204from gnucash.gnucash_core_c import \
1205 QOF_NUMERIC_MATCH_DEBIT, \
1206 QOF_NUMERIC_MATCH_CREDIT, \
1207 QOF_NUMERIC_MATCH_ANY
1208
1209from gnucash.gnucash_core_c import \
1210 QOF_GUID_MATCH_ANY, \
1211 QOF_GUID_MATCH_NONE, \
1212 QOF_GUID_MATCH_NULL, \
1213 QOF_GUID_MATCH_ALL, \
1214 QOF_GUID_MATCH_LIST_ANY
1215
1216from gnucash.gnucash_core_c import \
1217 QOF_CHAR_MATCH_ANY, \
1218 QOF_CHAR_MATCH_NONE
1219
1220from gnucash.gnucash_core_c import \
1221 INVOICE_TYPE
1222
1223from gnucash.gnucash_core_c import \
1224 INVOICE_IS_PAID
1225
1227
1228 def search_for(self, obj_type):
1229 """Set search_for to obj_type
1230
1231 calls qof_query_search_for. Buffers search string for queries lifetime.
1232 @see https://bugs.gnucash.org/show_bug.cgi?id=796137"""
1233 self.__search_for_buf = obj_type
1234 self._search_for(self.__search_for_buf)
1235
1236Query.add_constructor_and_methods_with_prefix('qof_query_', 'create', exclude=["qof_query_search_for"])
1237
1238Query.add_method('qof_query_set_book', 'set_book')
1239Query.add_method('qof_query_search_for', '_search_for')
1240Query.add_method('qof_query_run', 'run')
1241Query.add_method('qof_query_add_term', 'add_term')
1242Query.add_method('qof_query_add_boolean_match', 'add_boolean_match')
1243Query.add_method('qof_query_add_guid_list_match', 'add_guid_list_match')
1244Query.add_method('qof_query_add_guid_match', 'add_guid_match')
1245Query.add_method('qof_query_destroy', 'destroy')
1246
1248 pass
1249
1250QueryStringPredicate.add_constructor_and_methods_with_prefix(
1251 'qof_query_','string_predicate')
1252
1254 pass
1255
1256QueryBooleanPredicate.add_constructor_and_methods_with_prefix(
1257 'qof_query_', 'boolean_predicate')
1258
1260 pass
1261
1262QueryInt32Predicate.add_constructor_and_methods_with_prefix(
1263 'qof_query_', 'int32_predicate')
1264
1266 pass
1267
1268QueryDatePredicate.add_constructor_and_methods_with_prefix(
1269 'qof_query_', 'date_predicate', exclude=["qof_query_date_predicate_get_date"])
1270QueryDatePredicate.add_method('qof_query_date_predicate_get_date', 'get_date')
1271
1273 pass
1274
1275QueryGuidPredicate.add_constructor_and_methods_with_prefix(
1276 'qof_query_', 'guid_predicate')
1277
1279 pass
1280
1281QueryNumericPredicate.add_constructor_and_methods_with_prefix(
1282 'qof_query_', 'numeric_predicate')
InvoiceNextID(self, customer)
_operator_fallbacks(monomorphic_operator, fallback_operator)
__init__(self, *args, **kargs)
do_lookup_create_oo_instance(self, lookup_function, cls, *args)
raise_backend_errors(self, called_function="qof_session function")
raise_backend_errors_after_call(function, *args, **kwargs)
__init__(self, book_uri=None, mode=None, instance=None, book=None)
A convenient constructor that allows you to specify a book URI, begin the session,...