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  # Take care of backend inconsistency
360  # New xml file can't be loaded, new sql store
361  # has to be loaded before it can be altered
362  # Any existing store obviously has to be loaded
363  # More background: https://bugs.gnucash.org/show_bug.cgi?id=726891
364  is_new = mode in (SessionOpenMode.SESSION_NEW_STORE, SessionOpenMode.SESSION_NEW_OVERWRITE)
365  scheme = urlparse(book_uri).scheme
366  if not (is_new and scheme == 'xml'):
367  self.load()
368  except GnuCashBackendException as backend_exception:
369  self.end()
370  self.destroy()
371  raise
372 
373  def __enter__(self):
374  return self
375 
376  def __exit__(self, exc_type, exc_value, traceback):
377  # Roll back changes on exception by not calling save. Only works for XMl backend.
378  if not exc_type:
379  self.save()
380  self.end()
381 
382  def raise_backend_errors(self, called_function="qof_session function"):
383  """Raises a GnuCashBackendException if there are outstanding
384  QOF_BACKEND errors.
385 
386  set called_function to name the function that was last called
387  """
388  errors = self.pop_all_errors()
389  if errors != ():
391  "call to %s resulted in the "
392  "following errors, %s" % (called_function, backend_error_dict[errors[0]]),
393  errors )
394 
395  def generate_errors(self):
396  """A generator that yields any outstanding QofBackend errors
397  """
398  while self.get_error() is not ERR_BACKEND_NO_ERR:
399  error = self.pop_error()
400  yield error
401 
402  def pop_all_errors(self):
403  """Returns any accumulated qof backend errors as a tuple
404  """
405  return tuple( self.generate_errors() )
406 
407  # STATIC METHODS
408  @staticmethod
409  def raise_backend_errors_after_call(function, *args, **kwargs):
410  """A function decorator that results in a call to
411  raise_backend_errors after execution.
412  """
413  def new_function(self, *args, **kwargs):
414  return_value = function(self, *args, **kwargs)
415  self.raise_backend_errors(function.__name__)
416  return return_value
417  return new_function
418 
420  """A Book encapsulates all of the GnuCash data, it is the place where
421  all GnuCash entities (Transaction, Split, Vendor, Invoice...), are
422  stored. You'll notice that all of the constructors for those entities
423  need a book to be associated with.
424 
425  The most common way to get a book is through the book property in the
426  Session class, that is, create a session that connects to some storage,
427  such as through 'my_session = Session('file:my_books.xac')', and access
428  the book via the book property, 'my_session.book'
429 
430  If you would like to create a Book without any backing storage, call the
431  Book constructor without any parameters, 'Book()'. You can later merge
432  such a book into a book with actual store by using merge_init.
433 
434  Methods of interest
435  get_root_account -- Returns the root level Account
436  get_table -- Returns a commodity lookup table, of type GncCommodityTable
437  """
438  def InvoiceLookup(self, guid):
439  from gnucash.gnucash_business import Invoice
440  return self.do_lookup_create_oo_instance(
441  gncInvoiceLookup, Invoice, guid.get_instance() )
442 
443  def EntryLookup(self, guid):
444  from gnucash.gnucash_business import Entry
445  return self.do_lookup_create_oo_instance(
446  gncEntryLookup, Entry, guid.get_instance() )
447 
448  def CustomerLookup(self, guid):
449  from gnucash.gnucash_business import Customer
450  return self.do_lookup_create_oo_instance(
451  gncCustomerLookup, Customer, guid.get_instance())
452 
453  def JobLookup(self, guid):
454  from gnucash.gnucash_business import Job
455  return self.do_lookup_create_oo_instance(
456  gncJobLookup, Job, guid.get_instance() )
457 
458  def VendorLookup(self, guid):
459  from gnucash.gnucash_business import Vendor
460  return self.do_lookup_create_oo_instance(
461  gncVendorLookup, Vendor, guid.get_instance() )
462 
463  def EmployeeLookup(self, guid):
464  from gnucash.gnucash_business import Employee
465  return self.do_lookup_create_oo_instance(
466  gncEmployeeLookup, Employee, guid.get_instance() )
467 
468  def TaxTableLookup(self, guid):
469  from gnucash.gnucash_business import TaxTable
470  return self.do_lookup_create_oo_instance(
471  gncTaxTableLookup, TaxTable, guid.get_instance() )
472 
473  def TaxTableLookupByName(self, name):
474  from gnucash.gnucash_business import TaxTable
475  return self.do_lookup_create_oo_instance(
476  gncTaxTableLookupByName, TaxTable, name)
477 
478  def TaxTableGetTables(self):
479  from gnucash.gnucash_business import TaxTable
480  return [ TaxTable(instance=item) for item in gncTaxTableGetTables(self.instance) ]
481 
482  def BillLookupByID(self, id):
483  from gnucash.gnucash_business import Bill
484  return self.do_lookup_create_oo_instance(
485  gnc_search_bill_on_id, Bill, id)
486 
487  def InvoiceLookupByID(self, id):
488  from gnucash.gnucash_business import Invoice
489  return self.do_lookup_create_oo_instance(
490  gnc_search_invoice_on_id, Invoice, id)
491 
492  def CustomerLookupByID(self, id):
493  from gnucash.gnucash_business import Customer
494  return self.do_lookup_create_oo_instance(
495  gnc_search_customer_on_id, Customer, id)
496 
497  def VendorLookupByID(self, id):
498  from gnucash.gnucash_business import Vendor
499  return self.do_lookup_create_oo_instance(
500  gnc_search_vendor_on_id, Vendor, id)
501 
502  def InvoiceNextID(self, customer):
503  ''' Return the next invoice ID.
504  '''
505  from gnucash.gnucash_core_c import gncInvoiceNextID
506  return gncInvoiceNextID(self.get_instance(),customer.GetEndOwner().get_instance()[1])
507 
508  def BillNextID(self, vendor):
509  ''' Return the next Bill ID. '''
510  from gnucash.gnucash_core_c import gncInvoiceNextID
511  return gncInvoiceNextID(self.get_instance(),vendor.GetEndOwner().get_instance()[1])
512 
513  def CustomerNextID(self):
514  ''' Return the next Customer ID. '''
515  from gnucash.gnucash_core_c import gncCustomerNextID
516  return gncCustomerNextID(self.get_instance())
517 
518  def VendorNextID(self):
519  ''' Return the next Vendor ID. '''
520  from gnucash.gnucash_core_c import gncVendorNextID
521  return gncVendorNextID(self.get_instance())
522 
524  """Object used by GnuCash to store all numbers. Always consists of a
525  numerator and denominator.
526 
527  The constants GNC_DENOM_AUTO,
528  GNC_HOW_RND_FLOOR, GNC_HOW_RND_CEIL, GNC_HOW_RND_TRUNC,
529  GNC_HOW_RND_PROMOTE, GNC_HOW_RND_ROUND_HALF_DOWN,
530  GNC_HOW_RND_ROUND_HALF_UP, GNC_HOW_RND_ROUND, GNC_HOW_RND_NEVER,
531  GNC_HOW_DENOM_EXACT, GNC_HOW_DENOM_REDUCE, GNC_HOW_DENOM_LCD,
532  and GNC_HOW_DENOM_FIXED are available for arithmetic
533  functions like GncNumeric.add
534 
535  Look at gnc-numeric.h to see how to use these
536  """
537 
538  def __init__(self, *args, **kargs):
539  """Constructor that supports the following formats:
540  * No arguments defaulting to zero: eg. GncNumeric() == 0/1
541  * A integer: e.g. GncNumeric(1) == 1/1
542  * Numerator and denominator intager pair: eg. GncNumeric(1, 2) == 1/2
543  * A floating point number: e.g. GncNumeric(0.5) == 1/2
544  * A floating point number with defined conversion: e.g.
545  GncNumeric(0.5, GNC_DENOM_AUTO,
546  GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER) == 1/2
547  * A string: e.g. GncNumeric("1/2") == 1/2
548  """
549  if 'instance' not in kargs:
550  kargs['instance'] = GncNumeric.__args_to_instance(args)
551  GnuCashCoreClass.__init__(self, [], **kargs)
552 
553  @staticmethod
554  def __args_to_instance(args):
555  if len(args) == 0:
556  return gnc_numeric_zero()
557  elif len(args) == 1:
558  arg = args[0]
559  if isinstance(arg, int):
560  return gnc_numeric_create(arg, 1)
561  elif isinstance(arg, float):
562  return double_to_gnc_numeric(arg, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER)
563  elif isinstance(arg, str):
564  instance = gnc_numeric_from_string(arg)
565  if gnc_numeric_check(instance):
566  raise TypeError('Failed to convert to GncNumeric: ' + str(args))
567  return instance
568  elif isinstance(arg, GncNumeric):
569  return arg.instance
570  else:
571  raise TypeError('Only single int/float/str/GncNumeric allowed: ' + str(args))
572  elif len(args) == 2:
573  if isinstance(args[0], int) and isinstance(args[1], int):
574  return gnc_numeric_create(*args)
575  else:
576  raise TypeError('Only two ints allowed: ' + str(args))
577  elif len(args) == 3:
578  if isinstance(args[0], float) \
579  and isinstance(args[1], int) \
580  and type(args[2]) == type(GNC_HOW_DENOM_FIXED):
581  return double_to_gnc_numeric(*args)
582  else:
583  raise TypeError('Only (float, int, GNC_HOW_RND_*) allowed: ' + str(args))
584  else:
585  raise TypeError('Required single int/float/str or two ints: ' + str(args))
586 
587  # from https://docs.python.org/3/library/numbers.html#numbers.Integral
588  # and https://github.com/python/cpython/blob/3.7/Lib/fractions.py
589 
590  def _operator_fallbacks(monomorphic_operator, fallback_operator):
591  """fallbacks are not needed except for method name,
592  keep for possible later use"""
593  def forward(a, b):
594  if isinstance(b, GncNumeric):
595  return monomorphic_operator(a, b)
596  if isinstance(b, (int, float)):
597  return monomorphic_operator(a, GncNumeric(b))
598  else:
599  return NotImplemented
600  forward.__name__ = '__' + fallback_operator.__name__ + '__'
601  forward.__doc__ = monomorphic_operator.__doc__
602 
603  def reverse(b, a):
604  if isinstance(a, (GncNumeric, int, float)):
605  return forward(b, a)
606  else:
607  return NotImplemented
608  reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
609  reverse.__doc__ = monomorphic_operator.__doc__
610 
611  return forward, reverse
612 
613  def _add(a, b):
614  return a.add(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
615 
616  def _sub(a, b):
617  return a.sub(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
618 
619  def _mul(a, b):
620  return a.mul(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
621 
622  def _div(a, b):
623  return a.div(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
624 
625  def _floordiv(a, b):
626  return a.div(b, 1, GNC_HOW_RND_TRUNC)
627 
628  __add__, __radd__ = _operator_fallbacks(_add, operator.add)
629  __iadd__ = __add__
630  __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
631  __isub__ = __sub__
632  __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
633  __imul__ = __mul__
634  __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
635  __itruediv__ = __truediv__
636  __floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
637  __ifloordiv__ = __floordiv__
638 
639  # Comparisons derived from https://github.com/python/cpython/blob/3.7/Lib/fractions.py
640  def _lt(a, b):
641  return a.compare(b) == -1
642 
643  def _gt(a, b):
644  return a.compare(b) == 1
645 
646  def _le(a, b):
647  return a.compare(b) in (0,-1)
648 
649  def _ge(a, b):
650  return a.compare(b) in (0,1)
651 
652  def _eq(a, b):
653  return a.compare(b) == 0
654 
655  def _richcmp(self, other, op):
656  """Helper for comparison operators, for internal use only.
657  Implement comparison between a GncNumeric instance `self`,
658  and either another GncNumeric instance, an int or a float
659  `other`. If `other` is not an instance of that kind, return
660  NotImplemented. `op` should be one of the six standard
661  comparison operators. The comparisons are based on
662  GncNumeric.compare().
663  """
664  import math
665  if isinstance(other, GncNumeric):
666  return op(other)
667  elif isinstance(other, (int, float)):
668  return op(GncNumeric(other))
669  else:
670  return NotImplemented
671 
672  def __lt__(a, b):
673  """a < b"""
674  return a._richcmp(b, a._lt)
675 
676  def __gt__(a, b):
677  """a > b"""
678  return a._richcmp(b, a._gt)
679 
680  def __le__(a, b):
681  """a <= b"""
682  return a._richcmp(b, a._le)
683 
684  def __ge__(a, b):
685  """a >= b"""
686  return a._richcmp(b, a._ge)
687 
688  def __eq__(a, b):
689  """a == b"""
690  return a._richcmp(b, a._eq)
691 
692  def __bool__(a):
693  """a != 0"""
694  return bool(a.num())
695 
696  def __float__(self):
697  return self.to_double()
698 
699  def __int__(self):
700  return int(self.to_double())
701 
702  def __pos__(a):
703  """+a"""
704  return GncNumeric(a.num(), a.denom())
705 
706  def __neg__(a):
707  """-a"""
708  return a.neg()
709 
710  def __abs__(a):
711  """abs(a)"""
712  return a.abs()
713 
714  def to_fraction(self):
715  from fractions import Fraction
716  return Fraction(self.num(), self.denom())
717 
718  def __str__(self):
719  """Returns a human readable numeric value string as UTF8."""
720  return gnc_numeric_to_string(self.instance)
721 
723  '''
724  Each priceEach price in the database represents an "instantaneous"
725  quote for a given commodity with respect to another commodity.
726  For example, a given price might represent the value of LNUX in USD on 2001-02-03.
727 
728  Fields:
729  * commodity: the item being priced.
730  * currency: the denomination of the value of the item being priced.
731  * value: the value of the item being priced.
732  * time: the time the price was valid.
733  * source: a string describing the source of the quote. These strings will be something like this:
734  "Finance::Quote", "user:misc", "user:foo", etc. If the quote came from a user, as a matter of policy,
735  you *must* prefix the string you give with "user:". For now, the only other reserved values are
736  "Finance::Quote" and "old-file-import". Any string used must be added to the source_list array in
737  dialog-price-edit-db.c so that it can be properly translated. (There are unfortunately many strings
738  in users' databases, so this string must be translated on output instead of always being used in untranslated form).
739  * type: the type of quote - types possible right now are bid, ask, last, nav, and
740  unknown.Each price in the database represents an "instantaneous" quote for a given
741  commodity with respect to another commodity.
742  For example, a given price might represent the value of LNUX in USD on 2001-02-03.
743 
744  See also https://code.gnucash.org/docs/head/group__Price.html
745  '''
746  _new_instance = 'gnc_price_create'
747 GncPrice.add_methods_with_prefix('gnc_price_')
748 
749 
751  '''
752  a simple price database for gnucash.
753  The PriceDB is intended to be a database of price quotes, or more specifically,
754  a database of GNCPrices. For the time being, it is still a fairly simple
755  database supporting only fairly simple queries. It is expected that new
756  queries will be added as needed, and that there is some advantage to delaying
757  complex queries for now in the hope that we get a real DB implementation
758  before they're really needed.
759 
760  Every QofBook contains a GNCPriceDB, accessible via gnc_pricedb_get_db.
761 
762  Definition in file gnc-pricedb.h.
763  See also https://code.gnucash.org/docs/head/gnc-pricedb_8h.html
764  '''
765 
766 @deprecated("Use gnc_pricedb_latest_before_t64")
767 def gnc_pricedb_lookup_latest_before_t64(self, commodity, currency, date):
768  return self.lookup_nearest_before_t64(commodity, currency, date)
769 
770 GncPriceDB.add_method('gnc_pricedb_lookup_latest_before_t64', 'lookup_latest_before_t64')
771 
772 GncPriceDB.lookup_latest_before_t64 = method_function_returns_instance(GncPriceDB.lookup_latest_before_t64, GncPrice)
773 
774 GncPriceDB.add_methods_with_prefix('gnc_pricedb_')
775 PriceDB_dict = {
776  'lookup_latest' : GncPrice,
777  'lookup_nearest_in_time64' : GncPrice,
778  'lookup_nearest_before_t64' : GncPrice,
779  'convert_balance_latest_price' : GncNumeric,
780  'convert_balance_nearest_price_t64' : GncNumeric,
781  }
782 methods_return_instance(GncPriceDB,PriceDB_dict)
783 GncPriceDB.get_prices = method_function_returns_instance_list(
784  GncPriceDB.get_prices, GncPrice )
785 
787 
789  """A CommodityTable provides a way to store and lookup commodities.
790  Commodities are primarily currencies, but other tradable things such as
791  stocks, mutual funds, and material substances are possible.
792 
793  Users of this library should not create their own CommodityTable, instead
794  the get_table method from the Book class should be used.
795 
796  This table is automatically populated with the GnuCash default commodity's
797  which includes most of the world's currencies.
798  """
799 
800  def _get_namespaces_py(self):
801  return [ns.get_name() for ns in self.get_namespaces_list()]
802 
804  pass
805 
806 class GncLot(GnuCashCoreClass):
807  def GetInvoiceFromLot(self):
808  from gnucash.gnucash_business import Invoice
809  return self.do_lookup_create_oo_instance(
810  gncInvoiceGetInvoiceFromLot, Invoice )
811 
813  """A GnuCash Transaction
814 
815  Consists of at least one (generally two) splits to represent a transaction
816  between two accounts.
817 
818 
819  Has a GetImbalance() method that returns a list of all the imbalanced
820  currencies. Each list item is a two element tuple, the first element is
821  the imbalanced commodity, the second element is the value.
822 
823  Warning, the commodity.get_instance() value can be None when there
824  is no currency set for the transaction.
825  """
826  _new_instance = 'xaccMallocTransaction'
827  def GetNthSplit(self, n):
828  return self.GetSplitList().pop(n)
829 
830  def GetInvoiceFromTxn(self):
831  from gnucash.gnucash_business import Transaction
832  return self.do_lookup_create_oo_instance(
833  gncInvoiceGetInvoiceFromTxn, Transaction )
834 
835  def __eq__(self, other):
836  return self.Equal(other, True, False, False, False)
837 
838 def decorate_monetary_list_returning_function(orig_function):
839  def new_function(self, *args):
840  """decorate function that returns list of gnc_monetary to return tuples of GncCommodity and GncNumeric
841 
842  Args:
843  *args: Variable length argument list. Will get passed to orig_function
844 
845  Returns:
846  array of tuples: (GncCommodity, GncNumeric)
847 
848  ToDo:
849  Maybe this function should better reside in module function_class (?)"""
850  # warning, item.commodity has been shown to be None
851  # when the transaction doesn't have a currency
852  return [(GncCommodity(instance=item.commodity),
853  GncNumeric(instance=item.value))
854  for item in orig_function(self, *args) ]
855  return new_function
856 
858  """A GnuCash Split
859 
860  The most basic representation of a movement of currency from one account to
861  another.
862  """
863  _new_instance = 'xaccMallocSplit'
864 
865  def __eq__(self, other):
866  return self.Equal(other, True, False, False)
867 
869  """A GnuCash Account.
870 
871  A fundamental entity in accounting, an Account provides representation
872  for a financial object, such as a ACCT_TYPE_BANK account, an
873  ACCT_TYPE_ASSET (like a building),
874  a ACCT_TYPE_LIABILITY (such as a bank loan), a summary of some type of
875  ACCT_TYPE_EXPENSE, or a summary of some source of ACCT_TYPE_INCOME .
876 
877  The words in upper case are the constants that GnuCash and this library uses
878  to describe account type. Here is the full list:
879  ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
880  ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
881  ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
882  ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
883 
884  These are not strings, they are attributes you can import from this
885  module
886  """
887  _new_instance = 'xaccMallocAccount'
888 
890  _new_instance = 'guid_new_return'
891 
892 # Session
893 Session.add_constructor_and_methods_with_prefix('qof_session_', 'new')
894 
895 def one_arg_default_none(function):
896  return default_arguments_decorator(function, None, None)
897 Session.decorate_functions(one_arg_default_none, "load", "save")
898 
899 Session.decorate_functions( Session.raise_backend_errors_after_call,
900  "begin", "load", "save", "end")
901 Session.decorate_method(default_arguments_decorator, "begin", None, mode=SessionOpenMode.SESSION_NORMAL_OPEN)
902 Session.decorate_functions(deprecated_args_session_begin, "begin")
903 
904 Session.get_book = method_function_returns_instance(
905  Session.get_book, Book )
906 
907 Session.book = property( Session.get_book )
908 
909 # import all of the session backend error codes into this module
910 this_module_dict = globals()
911 for error_name, error_value, error_name_after_prefix in \
912  extract_attributes_with_prefix(gnucash_core_c, 'ERR_'):
913  this_module_dict[ error_name ] = error_value
914 
915 #backend error codes used for reverse lookup
916 backend_error_dict = {}
917 for error_name, error_value, error_name_after_prefix in \
918  extract_attributes_with_prefix(gnucash_core_c, 'ERR_'):
919  backend_error_dict[ error_value ] = error_name
920 
921 # GncNumeric denominator computation schemes
922 # Used for the denom argument in arithmetic functions like GncNumeric.add
923 from gnucash.gnucash_core_c import GNC_DENOM_AUTO
924 
925 # GncNumeric rounding instructions
926 # used for the how argument in arithmetic functions like GncNumeric.add
927 from gnucash.gnucash_core_c import \
928  GNC_HOW_RND_FLOOR, GNC_HOW_RND_CEIL, GNC_HOW_RND_TRUNC, \
929  GNC_HOW_RND_PROMOTE, GNC_HOW_RND_ROUND_HALF_DOWN, \
930  GNC_HOW_RND_ROUND_HALF_UP, GNC_HOW_RND_ROUND, GNC_HOW_RND_NEVER
931 
932 # GncNumeric denominator types
933 # used for the how argument in arithmetic functions like GncNumeric.add
934 from gnucash.gnucash_core_c import \
935  GNC_HOW_DENOM_EXACT, GNC_HOW_DENOM_REDUCE, GNC_HOW_DENOM_LCD, \
936  GNC_HOW_DENOM_FIXED, GNC_HOW_DENOM_SIGFIG
937 
938 # import account types
939 from gnucash.gnucash_core_c import \
940  ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
941  ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
942  ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
943  ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
944 
945 #Book
946 Book.add_constructor_and_methods_with_prefix('qof_book_', 'new')
947 Book.add_method('gnc_book_get_root_account', 'get_root_account')
948 Book.add_method('gnc_book_set_root_account', 'set_root_account')
949 Book.add_method('gnc_commodity_table_get_table', 'get_table')
950 Book.add_method('gnc_pricedb_get_db', 'get_price_db')
951 Book.add_method('qof_book_increment_and_format_counter', 'increment_and_format_counter')
952 
953 #Functions that return Account
954 Book.get_root_account = method_function_returns_instance(
955  Book.get_root_account, Account )
956 #Functions that return GncCommodityTable
957 Book.get_table = method_function_returns_instance(
958  Book.get_table, GncCommodityTable )
959 #Functions that return GNCPriceDB
960 Book.get_price_db = method_function_returns_instance(
961  Book.get_price_db, GncPriceDB)
962 
963 # GncNumeric
964 GncNumeric.add_constructor_and_methods_with_prefix('gnc_numeric_', 'create')
965 
966 gncnumeric_dict = {
967  'same' : GncNumeric,
968  'add' : GncNumeric,
969  'sub' : GncNumeric,
970  'mul' : GncNumeric,
971  'div' : GncNumeric,
972  'neg' : GncNumeric,
973  'abs' : GncNumeric,
974  'add_fixed' : GncNumeric,
975  'sub_fixed' : GncNumeric,
976  'convert' : GncNumeric,
977  'reduce' : GncNumeric,
978  'invert' : GncNumeric
979  }
980 methods_return_instance(GncNumeric, gncnumeric_dict)
981 
982 # GncCommodity
983 GncCommodity.add_constructor_and_methods_with_prefix('gnc_commodity_', 'new')
984 #Functions that return GncCommodity
985 GncCommodity.clone = method_function_returns_instance(
986  GncCommodity.clone, GncCommodity )
987 
988 # GncCommodityTable
989 GncCommodityTable.add_methods_with_prefix('gnc_commodity_table_')
990 commoditytable_dict = {
991  'lookup' : GncCommodity,
992  'lookup_unique' : GncCommodity,
993  'find_full' : GncCommodity,
994  'insert' : GncCommodity,
995  'add_namespace': GncCommodityNamespace,
996  'find_namespace': GncCommodityNamespace,
997  }
998 methods_return_instance(GncCommodityTable, commoditytable_dict)
999 
1000 methods_return_instance_lists(
1001  GncCommodityTable, { 'get_namespaces_list': GncCommodityNamespace,
1002  'get_commodities': GncCommodity,
1003  'get_quotable_commodities': GncCommodity,
1004 
1005  } )
1006 setattr(GncCommodityTable, 'get_namespaces', getattr(GncCommodityTable, '_get_namespaces_py'))
1007 
1008 # GncCommodityNamespace
1009 GncCommodityNamespace.add_methods_with_prefix('gnc_commodity_namespace_')
1010 GncCommodityNamespace.get_commodity_list = \
1011  method_function_returns_instance_list(
1012  GncCommodityNamespace.get_commodity_list, GncCommodity )
1013 
1014 # GncLot
1015 GncLot.add_constructor_and_methods_with_prefix('gnc_lot_', 'new')
1016 
1017 gnclot_dict = {
1018  'get_account' : Account,
1019  'get_book' : Book,
1020  'get_earliest_split' : Split,
1021  'get_latest_split' : Split,
1022  'get_balance' : GncNumeric,
1023  'lookup' : GncLot,
1024  'make_default' : GncLot
1025  }
1026 methods_return_instance(GncLot, gnclot_dict)
1027 
1028 # Transaction
1029 Transaction.add_methods_with_prefix('xaccTrans')
1030 Transaction.add_method('gncTransGetGUID', 'GetGUID')
1031 
1032 Transaction.add_method('xaccTransGetDescription', 'GetDescription')
1033 Transaction.add_method('xaccTransDestroy', 'Destroy')
1034 
1035 trans_dict = {
1036  'GetSplit': Split,
1037  'FindSplitByAccount': Split,
1038  'Clone': Transaction,
1039  'Reverse': Transaction,
1040  'GetReversedBy': Transaction,
1041  'GetImbalanceValue': GncNumeric,
1042  'GetAccountValue': GncNumeric,
1043  'GetAccountAmount': GncNumeric,
1044  'GetAccountConvRate': GncNumeric,
1045  'GetAccountBalance': GncNumeric,
1046  'GetCurrency': GncCommodity,
1047  'GetGUID': GUID
1048  }
1049 
1050 methods_return_instance(Transaction, trans_dict)
1051 methods_return_instance_lists(
1052  Transaction, { 'GetSplitList': Split,
1053  })
1054 Transaction.decorate_functions(
1055  decorate_monetary_list_returning_function, 'GetImbalance')
1056 
1057 # Split
1058 Split.add_methods_with_prefix('xaccSplit')
1059 Split.add_method('gncSplitGetGUID', 'GetGUID')
1060 Split.add_method('xaccSplitDestroy', 'Destroy')
1061 
1062 split_dict = {
1063  'GetBook': Book,
1064  'GetAccount': Account,
1065  'GetParent': Transaction,
1066  'Lookup': Split,
1067  'GetOtherSplit': Split,
1068  'GetAmount': GncNumeric,
1069  'GetValue': GncNumeric,
1070  'GetSharePrice': GncNumeric,
1071  'ConvertAmount': GncNumeric,
1072  'GetBaseValue': GncNumeric,
1073  'GetBalance': GncNumeric,
1074  'GetClearedBalance': GncNumeric,
1075  'GetReconciledBalance': GncNumeric,
1076  'VoidFormerAmount': GncNumeric,
1077  'VoidFormerValue': GncNumeric,
1078  'GetGUID': GUID
1079  }
1080 methods_return_instance(Split, split_dict)
1081 
1082 Split.account = property( Split.GetAccount, Split.SetAccount )
1083 Split.parent = property( Split.GetParent, Split.SetParent )
1084 
1085 # Account
1086 Account.add_methods_with_prefix('xaccAccount')
1087 Account.add_methods_with_prefix('gnc_account_')
1088 Account.add_method('gncAccountGetGUID', 'GetGUID')
1089 Account.add_method('xaccAccountGetPlaceholder', 'GetPlaceholder')
1090 
1091 account_dict = {
1092  'get_book' : Book,
1093  'Lookup' : Account,
1094  'get_parent' : Account,
1095  'get_root' : Account,
1096  'nth_child' : Account,
1097  'lookup_by_code' : Account,
1098  'lookup_by_name' : Account,
1099  'lookup_by_full_name' : Account,
1100  'FindTransByDesc' : Transaction,
1101  'FindSplitByDesc' : Split,
1102  'GetBalance' : GncNumeric,
1103  'GetClearedBalance' : GncNumeric,
1104  'GetReconciledBalance' : GncNumeric,
1105  'GetPresentBalance' : GncNumeric,
1106  'GetProjectedMinimumBalance' : GncNumeric,
1107  'GetBalanceAsOfDate' : GncNumeric,
1108  'ConvertBalanceToCurrency' : GncNumeric,
1109  'ConvertBalanceToCurrencyAsOfDate' : GncNumeric,
1110  'GetBalanceInCurrency' : GncNumeric,
1111  'GetClearedBalanceInCurrency' : GncNumeric,
1112  'GetReconciledBalanceInCurrency' : GncNumeric,
1113  'GetPresentBalanceInCurrency' : GncNumeric,
1114  'GetProjectedMinimumBalanceInCurrency' : GncNumeric,
1115  'GetBalanceAsOfDateInCurrency' : GncNumeric,
1116  'GetBalanceChangeForPeriod' : GncNumeric,
1117  'GetCommodity' : GncCommodity,
1118  'GetGUID': GUID
1119  }
1120 methods_return_instance(Account, account_dict)
1121 methods_return_instance_lists(
1122  Account, { 'GetSplitList': Split,
1123  'get_children': Account,
1124  'get_children_sorted': Account,
1125  'get_descendants': Account,
1126  'get_descendants_sorted': Account
1127  })
1128 Account.name = property( Account.GetName, Account.SetName )
1129 
1130 #GUID
1131 GUID.add_methods_with_prefix('guid_')
1132 GUID.add_method('xaccAccountLookup', 'AccountLookup')
1133 GUID.add_method('xaccTransLookup', 'TransLookup')
1134 GUID.add_method('xaccSplitLookup', 'SplitLookup')
1135 
1136 
1137 GUID.add_method('guid_to_string', 'to_string')
1138 #GUID.add_method('string_to_guid', 'string_to_guid')
1139 
1140 guid_dict = {
1141  'copy' : GUID,
1142  'TransLookup': Transaction,
1143  'AccountLookup': Account,
1144  'SplitLookup': Split
1145  }
1146 methods_return_instance(GUID, guid_dict)
1147 
1148 #GUIDString
1150  pass
1151 
1152 GUIDString.add_constructor_and_methods_with_prefix('string_', 'to_guid')
1153 
1154 #Query
1155 from gnucash.gnucash_core_c import \
1156  QOF_QUERY_AND, \
1157  QOF_QUERY_OR, \
1158  QOF_QUERY_NAND, \
1159  QOF_QUERY_NOR, \
1160  QOF_QUERY_XOR
1161 
1162 from gnucash.gnucash_core_c import \
1163  QOF_STRING_MATCH_NORMAL, \
1164  QOF_STRING_MATCH_CASEINSENSITIVE
1165 
1166 from gnucash.gnucash_core_c import \
1167  QOF_COMPARE_LT, \
1168  QOF_COMPARE_LTE, \
1169  QOF_COMPARE_EQUAL, \
1170  QOF_COMPARE_GT, \
1171  QOF_COMPARE_GTE, \
1172  QOF_COMPARE_NEQ, \
1173  QOF_COMPARE_CONTAINS, \
1174  QOF_COMPARE_NCONTAINS
1175 
1176 from gnucash.gnucash_core_c import \
1177  QOF_DATE_MATCH_NORMAL, \
1178  QOF_DATE_MATCH_DAY
1179 
1180 from gnucash.gnucash_core_c import \
1181  QOF_NUMERIC_MATCH_DEBIT, \
1182  QOF_NUMERIC_MATCH_CREDIT, \
1183  QOF_NUMERIC_MATCH_ANY
1184 
1185 from gnucash.gnucash_core_c import \
1186  QOF_GUID_MATCH_ANY, \
1187  QOF_GUID_MATCH_NONE, \
1188  QOF_GUID_MATCH_NULL, \
1189  QOF_GUID_MATCH_ALL, \
1190  QOF_GUID_MATCH_LIST_ANY
1191 
1192 from gnucash.gnucash_core_c import \
1193  QOF_CHAR_MATCH_ANY, \
1194  QOF_CHAR_MATCH_NONE
1195 
1196 from gnucash.gnucash_core_c import \
1197  INVOICE_TYPE
1198 
1199 from gnucash.gnucash_core_c import \
1200  INVOICE_IS_PAID
1201 
1203 
1204  def search_for(self, obj_type):
1205  """Set search_for to obj_type
1206 
1207  calls qof_query_search_for. Buffers search string for queries lifetime.
1208  @see https://bugs.gnucash.org/show_bug.cgi?id=796137"""
1209  self.__search_for_buf = obj_type
1210  self._search_for(self.__search_for_buf)
1211 
1212 Query.add_constructor_and_methods_with_prefix('qof_query_', 'create', exclude=["qof_query_search_for"])
1213 
1214 Query.add_method('qof_query_set_book', 'set_book')
1215 Query.add_method('qof_query_search_for', '_search_for')
1216 Query.add_method('qof_query_run', 'run')
1217 Query.add_method('qof_query_add_term', 'add_term')
1218 Query.add_method('qof_query_add_boolean_match', 'add_boolean_match')
1219 Query.add_method('qof_query_add_guid_list_match', 'add_guid_list_match')
1220 Query.add_method('qof_query_add_guid_match', 'add_guid_match')
1221 Query.add_method('qof_query_destroy', 'destroy')
1222 
1224  pass
1225 
1226 QueryStringPredicate.add_constructor_and_methods_with_prefix(
1227  'qof_query_','string_predicate')
1228 
1230  pass
1231 
1232 QueryBooleanPredicate.add_constructor_and_methods_with_prefix(
1233  'qof_query_', 'boolean_predicate')
1234 
1236  pass
1237 
1238 QueryInt32Predicate.add_constructor_and_methods_with_prefix(
1239  'qof_query_', 'int32_predicate')
1240 
1242  pass
1243 
1244 QueryDatePredicate.add_constructor_and_methods_with_prefix(
1245  'qof_query_', 'date_predicate', exclude=["qof_query_date_predicate_get_date"])
1246 QueryDatePredicate.add_method('qof_query_date_predicate_get_date', 'get_date')
1247 
1249  pass
1250 
1251 QueryGuidPredicate.add_constructor_and_methods_with_prefix(
1252  'qof_query_', 'guid_predicate')
1253 
1255  pass
1256 
1257 QueryNumericPredicate.add_constructor_and_methods_with_prefix(
1258  'qof_query_', 'numeric_predicate')
gnc_numeric double_to_gnc_numeric(double in, 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 in)
Check for error signal in value.