GnuCash  5.6-150-g038405b370+
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 
160 import operator
161 
162 from enum import IntEnum
163 from urllib.parse import urlparse
164 
165 from gnucash import gnucash_core_c
166 from gnucash import _sw_core_utils
167 
168 from 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 
174 from 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 
184 from gnucash.deprecation import (
185  deprecated_args_session,
186  deprecated_args_session_init,
187  deprecated_args_session_begin,
188  deprecated
189 )
190 
191 try:
192  import gettext
193 
194  _localedir = _sw_core_utils.gnc_path_get_localedir()
195  gettext.install(_sw_core_utils.GETTEXT_PACKAGE, _localedir)
196 except:
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 
212 class 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 
222 class GnuCashBackendException(Exception):
223  def __init__(self, msg, errors):
224  Exception.__init__(self, msg)
225  self.errors = errors
226 
227 
228 class 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 
390  def generate_errors(self):
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
435  return self.do_lookup_create_oo_instance(
436  gncInvoiceLookup, Invoice, guid.get_instance() )
437 
438  def EntryLookup(self, guid):
439  from gnucash.gnucash_business import Entry
440  return self.do_lookup_create_oo_instance(
441  gncEntryLookup, Entry, guid.get_instance() )
442 
443  def CustomerLookup(self, guid):
444  from gnucash.gnucash_business import Customer
445  return self.do_lookup_create_oo_instance(
446  gncCustomerLookup, Customer, guid.get_instance())
447 
448  def JobLookup(self, guid):
449  from gnucash.gnucash_business import Job
450  return self.do_lookup_create_oo_instance(
451  gncJobLookup, Job, guid.get_instance() )
452 
453  def VendorLookup(self, guid):
454  from gnucash.gnucash_business import Vendor
455  return self.do_lookup_create_oo_instance(
456  gncVendorLookup, Vendor, guid.get_instance() )
457 
458  def EmployeeLookup(self, guid):
459  from gnucash.gnucash_business import Employee
460  return self.do_lookup_create_oo_instance(
461  gncEmployeeLookup, Employee, guid.get_instance() )
462 
463  def TaxTableLookup(self, guid):
464  from gnucash.gnucash_business import TaxTable
465  return self.do_lookup_create_oo_instance(
466  gncTaxTableLookup, TaxTable, guid.get_instance() )
467 
468  def TaxTableLookupByName(self, name):
469  from gnucash.gnucash_business import TaxTable
470  return self.do_lookup_create_oo_instance(
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
479  return self.do_lookup_create_oo_instance(
480  gnc_search_bill_on_id, Bill, id)
481 
482  def InvoiceLookupByID(self, id):
483  from gnucash.gnucash_business import Invoice
484  return self.do_lookup_create_oo_instance(
485  gnc_search_invoice_on_id, Invoice, id)
486 
487  def CustomerLookupByID(self, id):
488  from gnucash.gnucash_business import Customer
489  return self.do_lookup_create_oo_instance(
490  gnc_search_customer_on_id, Customer, id)
491 
492  def VendorLookupByID(self, id):
493  from gnucash.gnucash_business import Vendor
494  return self.do_lookup_create_oo_instance(
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'
742 GncPrice.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")
762 def gnc_pricedb_lookup_latest_before_t64(self, commodity, currency, date):
763  return self.lookup_nearest_before_t64(commodity, currency, date)
764 
765 GncPriceDB.add_method('gnc_pricedb_lookup_latest_before_t64', 'lookup_latest_before_t64')
766 
767 GncPriceDB.lookup_latest_before_t64 = method_function_returns_instance(GncPriceDB.lookup_latest_before_t64, GncPrice)
768 
769 GncPriceDB.add_methods_with_prefix('gnc_pricedb_')
770 PriceDB_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  }
783 methods_return_instance(GncPriceDB,PriceDB_dict)
784 methods_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 
809  pass
810 
811 class 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
837  return self.do_lookup_create_oo_instance(
838  gncInvoiceGetInvoiceFromTxn, Invoice )
839 
840  def __eq__(self, other):
841  return self.Equal(other, True, False, False, False)
842 
843 def 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
898 Session.add_constructor_and_methods_with_prefix('qof_session_', 'new')
899 
900 def one_arg_default_none(function):
901  return default_arguments_decorator(function, None, None)
902 Session.decorate_functions(one_arg_default_none, "load", "save")
903 
904 Session.decorate_functions( Session.raise_backend_errors_after_call,
905  "begin", "load", "save", "end")
906 Session.decorate_method(default_arguments_decorator, "begin", None, mode=SessionOpenMode.SESSION_NORMAL_OPEN)
907 Session.decorate_functions(deprecated_args_session_begin, "begin")
908 
909 Session.get_book = method_function_returns_instance(
910  Session.get_book, Book )
911 
912 Session.book = property( Session.get_book )
913 
914 # import all of the session backend error codes into this module
915 this_module_dict = globals()
916 for 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
921 backend_error_dict = {}
922 for 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
928 from 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
932 from 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
939 from 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
944 from 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
951 Book.add_constructor_and_methods_with_prefix('qof_book_', 'new')
952 Book.add_method('gnc_book_get_root_account', 'get_root_account')
953 Book.add_method('gnc_book_set_root_account', 'set_root_account')
954 Book.add_method('gnc_commodity_table_get_table', 'get_table')
955 Book.add_method('gnc_pricedb_get_db', 'get_price_db')
956 Book.add_method('qof_book_increment_and_format_counter', 'increment_and_format_counter')
957 
958 #Functions that return Account
959 Book.get_root_account = method_function_returns_instance(
960  Book.get_root_account, Account )
961 #Functions that return GncCommodityTable
962 Book.get_table = method_function_returns_instance(
963  Book.get_table, GncCommodityTable )
964 #Functions that return GNCPriceDB
965 Book.get_price_db = method_function_returns_instance(
966  Book.get_price_db, GncPriceDB)
967 
968 # GncNumeric
969 GncNumeric.add_constructor_and_methods_with_prefix('gnc_numeric_', 'create')
970 
971 gncnumeric_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  }
985 methods_return_instance(GncNumeric, gncnumeric_dict)
986 
987 # GncCommodity
988 GncCommodity.add_constructor_and_methods_with_prefix('gnc_commodity_', 'new')
989 gnc_commodity_dict = {
990  'clone': GncCommodity,
991  'obtain_twin': GncCommodity,
992  'get_namespace_ds': GncCommodityNamespace,
993  }
994 methods_return_instance(GncCommodity, gnc_commodity_dict)
995 
996 # GncPrice (deferred until after GncCommodity is defined)
997 gnc_price_dict = {
998  'get_commodity': GncCommodity,
999  'get_currency': GncCommodity,
1000  'clone': GncPrice,
1001  'get_value': GncNumeric,
1002  }
1003 methods_return_instance(GncPrice, gnc_price_dict)
1004 
1005 # GncCommodityTable
1006 GncCommodityTable.add_methods_with_prefix('gnc_commodity_table_')
1007 commoditytable_dict = {
1008  'lookup' : GncCommodity,
1009  'lookup_unique' : GncCommodity,
1010  'find_full' : GncCommodity,
1011  'insert' : GncCommodity,
1012  'add_namespace': GncCommodityNamespace,
1013  'find_namespace': GncCommodityNamespace,
1014  }
1015 methods_return_instance(GncCommodityTable, commoditytable_dict)
1016 
1017 methods_return_instance_lists(
1018  GncCommodityTable, { 'get_namespaces_list': GncCommodityNamespace,
1019  'get_commodities': GncCommodity,
1020  'get_quotable_commodities': GncCommodity,
1021 
1022  } )
1023 setattr(GncCommodityTable, 'get_namespaces', getattr(GncCommodityTable, '_get_namespaces_py'))
1024 
1025 # GncCommodityNamespace
1026 GncCommodityNamespace.add_methods_with_prefix('gnc_commodity_namespace_')
1027 GncCommodityNamespace.get_commodity_list = \
1028  method_function_returns_instance_list(
1029  GncCommodityNamespace.get_commodity_list, GncCommodity )
1030 
1031 # GncLot
1032 GncLot.add_constructor_and_methods_with_prefix('gnc_lot_', 'new')
1033 
1034 gnclot_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  }
1043 methods_return_instance(GncLot, gnclot_dict)
1044 methods_return_instance_lists(
1045  GncLot, { 'get_split_list': Split,
1046  })
1047 
1048 # Transaction
1049 Transaction.add_methods_with_prefix('xaccTrans')
1050 Transaction.add_method('gncTransGetGUID', 'GetGUID')
1051 
1052 Transaction.add_method('xaccTransGetDescription', 'GetDescription')
1053 Transaction.add_method('xaccTransDestroy', 'Destroy')
1054 
1055 trans_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 
1070 methods_return_instance(Transaction, trans_dict)
1071 methods_return_instance_lists(
1072  Transaction, { 'GetSplitList': Split,
1073  })
1074 Transaction.decorate_functions(
1075  decorate_monetary_list_returning_function, 'GetImbalance')
1076 
1077 # Split
1078 Split.add_methods_with_prefix('xaccSplit')
1079 Split.add_method('gncSplitGetGUID', 'GetGUID')
1080 Split.add_method('xaccSplitDestroy', 'Destroy')
1081 
1082 split_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  }
1102 methods_return_instance(Split, split_dict)
1103 
1104 Split.account = property( Split.GetAccount, Split.SetAccount )
1105 Split.parent = property( Split.GetParent, Split.SetParent )
1106 
1107 # Account
1108 Account.add_methods_with_prefix('xaccAccount')
1109 Account.add_methods_with_prefix('gnc_account_')
1110 Account.add_method('gncAccountGetGUID', 'GetGUID')
1111 Account.add_method('xaccAccountGetPlaceholder', 'GetPlaceholder')
1112 
1113 account_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  }
1143 methods_return_instance(Account, account_dict)
1144 methods_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  })
1152 Account.name = property( Account.GetName, Account.SetName )
1153 
1154 #GUID
1155 GUID.add_methods_with_prefix('guid_')
1156 GUID.add_method('xaccAccountLookup', 'AccountLookup')
1157 GUID.add_method('xaccTransLookup', 'TransLookup')
1158 GUID.add_method('xaccSplitLookup', 'SplitLookup')
1159 
1160 
1161 GUID.add_method('guid_to_string', 'to_string')
1162 #GUID.add_method('string_to_guid', 'string_to_guid')
1163 
1164 guid_dict = {
1165  'copy' : GUID,
1166  'TransLookup': Transaction,
1167  'AccountLookup': Account,
1168  'SplitLookup': Split
1169  }
1170 methods_return_instance(GUID, guid_dict)
1171 
1172 #GUIDString
1174  pass
1175 
1176 GUIDString.add_constructor_and_methods_with_prefix('string_', 'to_guid')
1177 
1178 #Query
1179 from 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 
1186 from gnucash.gnucash_core_c import \
1187  QOF_STRING_MATCH_NORMAL, \
1188  QOF_STRING_MATCH_CASEINSENSITIVE
1189 
1190 from 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 
1200 from gnucash.gnucash_core_c import \
1201  QOF_DATE_MATCH_NORMAL, \
1202  QOF_DATE_MATCH_DAY
1203 
1204 from gnucash.gnucash_core_c import \
1205  QOF_NUMERIC_MATCH_DEBIT, \
1206  QOF_NUMERIC_MATCH_CREDIT, \
1207  QOF_NUMERIC_MATCH_ANY
1208 
1209 from 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 
1216 from gnucash.gnucash_core_c import \
1217  QOF_CHAR_MATCH_ANY, \
1218  QOF_CHAR_MATCH_NONE
1219 
1220 from gnucash.gnucash_core_c import \
1221  INVOICE_TYPE
1222 
1223 from 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 
1236 Query.add_constructor_and_methods_with_prefix('qof_query_', 'create', exclude=["qof_query_search_for"])
1237 
1238 Query.add_method('qof_query_set_book', 'set_book')
1239 Query.add_method('qof_query_search_for', '_search_for')
1240 Query.add_method('qof_query_run', 'run')
1241 Query.add_method('qof_query_add_term', 'add_term')
1242 Query.add_method('qof_query_add_boolean_match', 'add_boolean_match')
1243 Query.add_method('qof_query_add_guid_list_match', 'add_guid_list_match')
1244 Query.add_method('qof_query_add_guid_match', 'add_guid_match')
1245 Query.add_method('qof_query_destroy', 'destroy')
1246 
1248  pass
1249 
1250 QueryStringPredicate.add_constructor_and_methods_with_prefix(
1251  'qof_query_','string_predicate')
1252 
1254  pass
1255 
1256 QueryBooleanPredicate.add_constructor_and_methods_with_prefix(
1257  'qof_query_', 'boolean_predicate')
1258 
1260  pass
1261 
1262 QueryInt32Predicate.add_constructor_and_methods_with_prefix(
1263  'qof_query_', 'int32_predicate')
1264 
1266  pass
1267 
1268 QueryDatePredicate.add_constructor_and_methods_with_prefix(
1269  'qof_query_', 'date_predicate', exclude=["qof_query_date_predicate_get_date"])
1270 QueryDatePredicate.add_method('qof_query_date_predicate_get_date', 'get_date')
1271 
1273  pass
1274 
1275 QueryGuidPredicate.add_constructor_and_methods_with_prefix(
1276  'qof_query_', 'guid_predicate')
1277 
1279  pass
1280 
1281 QueryNumericPredicate.add_constructor_and_methods_with_prefix(
1282  'qof_query_', 'numeric_predicate')
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
def search_for(self, obj_type)
def raise_backend_errors_after_call(function, args, kwargs)
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
def BillNextID(self, vendor)
def raise_backend_errors(self, called_function="qof_session function")
def do_lookup_create_oo_instance(self, lookup_function, cls, args)
def InvoiceNextID(self, customer)
def __init__(self, args, kargs)
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
def __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, and load the book.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.