32 Session, Account, Transaction, Split, GncNumeric, SessionOpenMode)
33 from gnucash.gnucash_core_c
import \
34 GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT, \
35 ACCT_TYPE_ASSET, ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CHECKING, \
36 ACCT_TYPE_CREDIT, ACCT_TYPE_EQUITY, ACCT_TYPE_EXPENSE, ACCT_TYPE_INCOME, \
37 ACCT_TYPE_LIABILITY, ACCT_TYPE_MUTUAL, ACCT_TYPE_PAYABLE, \
38 ACCT_TYPE_RECEIVABLE, ACCT_TYPE_STOCK, ACCT_TYPE_ROOT, ACCT_TYPE_TRADING
41 from os.path
import abspath
42 from datetime
import date
87 OPENING_DATE = (1, 1, 2011)
90 ACCOUNT_TYPES_TO_OPEN = set( (
101 ACCT_TYPE_RECEIVABLE,
109 ACCOUNT_TYPES_TO_OPEN = ACCOUNT_TYPES_TO_OPEN.difference( set((
118 ACCOUNT_TYPES_TO_OPEN = ACCOUNT_TYPES_TO_OPEN.difference( set((
121 ACCT_TYPE_RECEIVABLE,
128 ACCOUNT_TYPES_TO_OPEN.remove(ACCT_TYPE_TRADING)
130 OPENING_BALANCE_ACCOUNT = (
'Equity',
'Opening Balances')
135 PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE = (
"CURRENCY",
"CAD")
137 def initialize_split(book, value, account, trans):
139 split.SetValue(value)
140 split.SetAccount(account)
141 split.SetParent(trans)
145 def record_opening_balance(original_account, new_account, new_book,
146 opening_balance_per_currency, commodity_tuple
149 if new_account.GetType()
in ACCOUNT_TYPES_TO_OPEN:
150 final_balance = original_account.GetBalance()
151 if final_balance.num() != 0:
156 if commodity_tuple
not in opening_balance_per_currency:
157 trans = Transaction(new_book)
159 opening_balance_per_currency[commodity_tuple] = (
161 trans, total = opening_balance_per_currency[commodity_tuple]
163 new_total = total.sub(
165 GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT )
171 opening_balance_per_currency[commodity_tuple] = \
174 def recursivly_build_account_tree(original_parent_account,
178 opening_balance_per_currency,
179 account_types_to_open ):
181 for child
in original_parent_account.get_children():
182 original_account = child
183 new_account =
Account(new_book)
185 new_parent_account.append_child(new_account)
188 for attribute
in (
'Name',
'Type',
'Description',
'Notes',
189 'Code',
'TaxRelated',
'Placeholder'):
191 getattr(new_account,
'Set' + attribute)(
192 getattr(original_account,
'Get' + attribute)() )
195 orig_commodity = original_account.GetCommodity()
196 namespace = orig_commodity.get_namespace()
197 mnemonic = orig_commodity.get_mnemonic()
198 new_commodity = new_commodity_table.lookup(namespace, mnemonic)
199 if new_commodity ==
None:
200 new_commodity = orig_commodity.clone(new_book)
201 new_commodity_table.insert(new_commodity)
202 new_account.SetCommodity(new_commodity)
204 record_opening_balance( original_account, new_account,
205 new_book, opening_balance_per_currency,
206 (namespace, mnemonic),
209 recursivly_build_account_tree(original_account,
213 opening_balance_per_currency,
214 account_types_to_open)
216 def reconstruct_account_name_with_mnemonic(account_tuple, mnemonic):
217 opening_balance_account_pieces = list(account_tuple)
218 opening_balance_account_pieces[
219 len(opening_balance_account_pieces) - 1 ] +=
" - " + mnemonic
220 return opening_balance_account_pieces
222 def find_or_make_account(account_tuple, root_account, book,
224 current_account_name, account_path = account_tuple[0], account_tuple[1:]
225 current_account = root_account.lookup_by_name(current_account_name)
226 if current_account ==
None:
227 current_account =
Account(book)
228 current_account.SetName(current_account_name)
229 current_account.SetCommodity(currency)
230 root_account.append_child(current_account)
232 if len(account_path) > 0:
233 return find_or_make_account(account_path, current_account, book,
236 account_commod = current_account.GetCommodity()
237 if (account_commod.get_mnemonic(),
238 account_commod.get_namespace() ) == \
239 (currency.get_mnemonic(),
240 currency.get_namespace()) :
241 return current_account
245 def choke_on_none_for_no_account(opening_account, extra_string ):
246 if opening_account ==
None:
247 raise Exception(
"account currency and name mismatch, " + extra_string)
249 def create_opening_balance_transaction(commodtable, namespace, mnemonic,
250 new_book_root, new_book,
251 opening_trans, opening_amount,
252 simple_opening_name_used):
253 currency = commodtable.lookup(namespace, mnemonic)
254 assert( currency.get_instance() !=
None )
256 if simple_opening_name_used:
257 account_pieces = reconstruct_account_name_with_mnemonic(
258 OPENING_BALANCE_ACCOUNT,
260 opening_account = find_or_make_account(
261 account_pieces, new_book_root, new_book, currency )
262 choke_on_none_for_no_account(opening_account,
263 ', '.join(account_pieces) )
265 opening_account = find_or_make_account(OPENING_BALANCE_ACCOUNT,
266 new_book_root, new_book,
268 simple_opening_name_used =
True 269 if opening_account ==
None:
270 account_pieces = reconstruct_account_name_with_mnemonic(
271 OPENING_BALANCE_ACCOUNT,
273 opening_account = find_or_make_account(
274 account_pieces, new_book_root, new_book, currency )
275 choke_on_none_for_no_account(opening_account,
276 ', '.join(account_pieces) )
280 if opening_amount.num() != 0:
281 initialize_split(new_book, opening_amount, opening_account,
284 opening_trans.SetDate( *OPENING_DATE )
285 opening_trans.SetCurrency(currency)
286 opening_trans.SetDescription(
"Opening Balance")
287 opening_trans.CommitEdit()
289 return simple_opening_name_used
294 print(
'not enough parameters')
295 print(
'usage: new_book_with_opening_balances.py {source_book_url} {destination_book_url}')
297 print(
"python3 new_book_with_opening_balances.py '/home/username/test.gnucash' 'sqlite3:///home/username/new_test.gnucash'")
298 print(
"python3 new_book_with_opening_balances.py '/home/username/test.gnucash' 'xml:///crypthome/username/finances/new_test.gnucash'")
303 original_book_session = Session(argv[1], SessionOpenMode.SESSION_NORMAL_OPEN)
304 new_book_session = Session(argv[2], SessionOpenMode.SESSION_NEW_STORE)
305 new_book = new_book_session.get_book()
306 new_book_root = new_book.get_root_account()
308 commodtable = new_book.get_table()
311 new_book_session.save()
313 opening_balance_per_currency = {}
314 recursivly_build_account_tree(
315 original_book_session.get_book().get_root_account(),
319 opening_balance_per_currency,
320 ACCOUNT_TYPES_TO_OPEN
323 (namespace, mnemonic) = PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE
324 if (namespace, mnemonic)
in opening_balance_per_currency:
325 opening_trans, opening_amount = opening_balance_per_currency[
326 (namespace, mnemonic)]
327 simple_opening_name_used = create_opening_balance_transaction(
328 commodtable, namespace, mnemonic,
329 new_book_root, new_book,
330 opening_trans, opening_amount,
332 del opening_balance_per_currency[
333 PREFERED_CURRENCY_FOR_SIMPLE_OPENING_BALANCE]
335 simple_opening_name_used =
False 337 for (namespace, mnemonic), (opening_trans, opening_amount)
in \
338 opening_balance_per_currency.items() :
339 simple_opening_name_used = create_opening_balance_transaction(
340 commodtable, namespace, mnemonic,
341 new_book_root, new_book,
342 opening_trans, opening_amount,
343 simple_opening_name_used )
345 new_book_session.save()
346 new_book_session.end()
347 original_book_session.end()
349 if "original_book_session" in locals():
350 original_book_session.end()
352 if "new_book_session" in locals():
353 new_book_session.end()
358 if __name__ ==
"__main__":
The primary numeric class for representing amounts and values.