31 from gnucash
import Session, Account, Transaction, Split, GncNumeric
32 from gnucash.gnucash_core_c
import \
33 GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT, \
34 ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
35 ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
36 ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
37 ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
40 from os.path
import abspath
41 from datetime
import date
86 OPENING_DATE = (1, 1, 2011)
89 ACCOUNT_TYPES_TO_OPEN = set( (
100 ACCT_TYPE_RECEIVABLE,
108 ACCOUNT_TYPES_TO_OPEN = ACCOUNT_TYPES_TO_OPEN.difference( set((
117 ACCOUNT_TYPES_TO_OPEN = ACCOUNT_TYPES_TO_OPEN.difference( set((
120 ACCT_TYPE_RECEIVABLE,
127 ACCOUNT_TYPES_TO_OPEN.remove(ACCT_TYPE_TRADING)
129 OPENING_BALANCE_ACCOUNT = (
'Equity',
'Opening Balances')
134 PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE = (
"CURRENCY",
"CAD")
136 def initialize_split(book, value, account, trans):
138 split.SetValue(value)
139 split.SetAccount(account)
140 split.SetParent(trans)
144 def record_opening_balance(original_account, new_account, new_book,
145 opening_balance_per_currency, commodity_tuple
148 if new_account.GetType()
in ACCOUNT_TYPES_TO_OPEN:
149 final_balance = original_account.GetBalance()
150 if final_balance.num() != 0:
155 if commodity_tuple
not in opening_balance_per_currency:
158 opening_balance_per_currency[commodity_tuple] = (
159 trans, GncNumeric(0, 1) )
160 trans, total = opening_balance_per_currency[commodity_tuple]
162 new_total = total.sub(
164 GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT )
170 opening_balance_per_currency[commodity_tuple] = \
173 def recursivly_build_account_tree(original_parent_account,
177 opening_balance_per_currency,
178 account_types_to_open ):
180 for child
in original_parent_account.get_children():
181 original_account = child
182 new_account =
Account(new_book)
184 new_parent_account.append_child(new_account)
187 for attribute
in (
'Name',
'Type',
'Description',
'Notes',
188 'Code',
'TaxRelated',
'Placeholder'):
190 getattr(new_account,
'Set' + attribute)(
191 getattr(original_account,
'Get' + attribute)() )
194 orig_commodity = original_account.GetCommodity()
195 namespace = orig_commodity.get_namespace()
196 mnemonic = orig_commodity.get_mnemonic()
197 new_commodity = new_commodity_table.lookup(namespace, mnemonic)
198 if new_commodity ==
None:
199 new_commodity = orig_commodity.clone(new_book)
200 new_commodity_table.insert(new_commodity)
201 new_account.SetCommodity(new_commodity)
203 record_opening_balance( original_account, new_account,
204 new_book, opening_balance_per_currency,
205 (namespace, mnemonic),
208 recursivly_build_account_tree(original_account,
212 opening_balance_per_currency,
213 account_types_to_open)
215 def reconstruct_account_name_with_mnemonic(account_tuple, mnemonic):
216 opening_balance_account_pieces = list(account_tuple)
217 opening_balance_account_pieces[
218 len(opening_balance_account_pieces) - 1 ] +=
" - " + mnemonic
219 return opening_balance_account_pieces
221 def find_or_make_account(account_tuple, root_account, book,
223 current_account_name, account_path = account_tuple[0], account_tuple[1:]
224 current_account = root_account.lookup_by_name(current_account_name)
225 if current_account ==
None:
226 current_account =
Account(book)
227 current_account.SetName(current_account_name)
228 current_account.SetCommodity(currency)
229 root_account.append_child(current_account)
231 if len(account_path) > 0:
232 return find_or_make_account(account_path, current_account, book,
235 account_commod = current_account.GetCommodity()
236 if (account_commod.get_mnemonic(),
237 account_commod.get_namespace() ) == \
238 (currency.get_mnemonic(),
239 currency.get_namespace()) :
240 return current_account
244 def choke_on_none_for_no_account(opening_account, extra_string ):
245 if opening_account ==
None:
246 raise Exception(
"account currency and name mismatch, " + extra_string)
248 def create_opening_balance_transaction(commodtable, namespace, mnemonic,
249 new_book_root, new_book,
250 opening_trans, opening_amount,
251 simple_opening_name_used):
252 currency = commodtable.lookup(namespace, mnemonic)
253 assert( currency.get_instance() !=
None )
255 if simple_opening_name_used:
256 account_pieces = reconstruct_account_name_with_mnemonic(
257 OPENING_BALANCE_ACCOUNT,
259 opening_account = find_or_make_account(
260 account_pieces, new_book_root, new_book, currency )
261 choke_on_none_for_no_account(opening_account,
262 ', '.join(account_pieces) )
264 opening_account = find_or_make_account(OPENING_BALANCE_ACCOUNT,
265 new_book_root, new_book,
267 simple_opening_name_used =
True
268 if opening_account ==
None:
269 account_pieces = reconstruct_account_name_with_mnemonic(
270 OPENING_BALANCE_ACCOUNT,
272 opening_account = find_or_make_account(
273 account_pieces, new_book_root, new_book, currency )
274 choke_on_none_for_no_account(opening_account,
275 ', '.join(account_pieces) )
279 if opening_amount.num() != 0:
280 initialize_split(new_book, opening_amount, opening_account,
283 opening_trans.SetDate( *OPENING_DATE )
284 opening_trans.SetCurrency(currency)
285 opening_trans.SetDescription(
"Opening Balance")
286 opening_trans.CommitEdit()
288 return simple_opening_name_used
293 print 'not enough parameters'
294 print 'usage: new_book_with_opening_balances.py {source_book_url} {destination_book_url}'
296 print "gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'sqlite3:///home/username/new_test.gnucash'"
297 print "gnucash-env python new_book_with_opening_balances.py '/home/username/test.gnucash' 'xml:///crypthome/username/finances/new_test.gnucash'"
302 original_book_session = Session(argv[1], is_new=
False)
303 new_book_session = Session(argv[2], is_new=
True)
304 new_book = new_book_session.get_book()
305 new_book_root = new_book.get_root_account()
307 commodtable = new_book.get_table()
310 new_book_session.save()
312 opening_balance_per_currency = {}
313 recursivly_build_account_tree(
314 original_book_session.get_book().get_root_account(),
318 opening_balance_per_currency,
319 ACCOUNT_TYPES_TO_OPEN
322 (namespace, mnemonic) = PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE
323 if (namespace, mnemonic)
in opening_balance_per_currency:
324 opening_trans, opening_amount = opening_balance_per_currency[
325 (namespace, mnemonic)]
326 simple_opening_name_used = create_opening_balance_transaction(
327 commodtable, namespace, mnemonic,
328 new_book_root, new_book,
329 opening_trans, opening_amount,
331 del opening_balance_per_currency[
332 PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE]
334 simple_opening_name_used =
False
336 for (namespace, mnemonic), (opening_trans, opening_amount)
in \
337 opening_balance_per_currency.iteritems() :
338 simple_opening_name_used = create_opening_balance_transaction(
339 commodtable, namespace, mnemonic,
340 new_book_root, new_book,
341 opening_trans, opening_amount,
342 simple_opening_name_used )
344 new_book_session.save()
345 new_book_session.end()
346 original_book_session.end()
348 if "original_book_session" in locals():
349 original_book_session.end()
351 if "new_book_session" in locals():
352 new_book_session.end()
357 if __name__ ==
"__main__":