From 129d7deaf188c85546dcbe472792435c4fa615d8 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier <vincent@nexedi.com> Date: Wed, 20 Apr 2016 07:09:12 +0200 Subject: [PATCH] AccountModule_getAccountListForTrialBalance: Improve performance. - Correctly ignore parent_portal_type condition when all possible portal types are listed. This typically saves one stock-catalog join. - Expand node_category_uid into lists of node_uids. This saves one very costly stock-catalog join, as nodes member of given category should typically be the minority, inciting MySQL query optimiser to use the index materialising this join, preventing use of actual stock indexes. As there should be few nodes involved in accounting reports, listing them all and passing them to queries should not matter much. Also, add support for src__ parameter. Also, assorted coding style improvements, changes and code factorisation. --- ...untModule_getAccountListForTrialBalance.py | 1085 ++++++++--------- ...ntModule_getAccountListForTrialBalance.xml | 2 +- 2 files changed, 523 insertions(+), 564 deletions(-) diff --git a/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.py b/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.py index f2340c9561..9d9c0ac8df 100644 --- a/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.py +++ b/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.py @@ -2,35 +2,68 @@ from Products.ZSQLCatalog.SQLCatalog import Query from Products.PythonScripts.standard import Object from ZTUtils import LazyFilter -request = container.REQUEST portal = context.getPortalObject() -getInventoryList = portal.portal_simulation.getInventoryList -traverse = context.getPortalObject().restrictedTraverse -getObject = context.getPortalObject().portal_catalog.getObject +request = portal.REQUEST +getInventoryList_ = portal.portal_simulation.getInventoryList +traverse = portal.restrictedTraverse +portal_catalog = portal.portal_catalog +getObject = portal_catalog.getObject Base_translateString = portal.Base_translateString selected_gap = gap_root +traverseCategory = portal.portal_categories.restrictedTraverse +def getAccountUidListByCategory(category, strict_membership): + """ + Transform node_category* into node_uid list. + """ + if not category: + return [] + kw = { + ('strict_' if strict_membership else '') + 'account_type_uid': [ + traverseCategory(x).getUid() for x in category + ], + } + if node_uid: + kw['uid'] = node_uid + return [x.uid for x in portal_catalog(portal_type='Account', **kw)] inventory_movement_type_list = portal.getPortalInventoryMovementTypeList() # Balance Movement Type list is all movements that are both inventory movement # and accounting movement -balance_movement_type_list = [ t for t in - portal.getPortalAccountingMovementTypeList() - if t in inventory_movement_type_list ] - -accounting_movement_type_list = [ t for t in - portal.getPortalAccountingMovementTypeList() - if t not in balance_movement_type_list ] - -inventory_params = dict(section_uid=section_uid, - simulation_state=simulation_state, - precision=precision, - group_by_resource=0) - +balance_movement_type_list = [ + t for t in portal.getPortalAccountingMovementTypeList() + if t in inventory_movement_type_list +] +accounting_movement_type_list = [ + t for t in portal.getPortalAccountingMovementTypeList() + if t not in balance_movement_type_list +] + +src_list = [] +def getInventoryList(node_uid=None, **kw): + if not node_uid and node_uid is not None: + return [] + for key, value in inventory_params.iteritems(): + assert key not in kw, key + kw[key] = value + result = getInventoryList_( + section_uid=section_uid, + simulation_state=simulation_state, + precision=precision, + group_by_resource=0, + group_by_node=1, + node_uid=node_uid, + src__=src__, + **kw + ) + if src__: + src_list.append(result) + return [] + return result +inventory_params = {} if group_analytic: inventory_params['group_by'] = group_analytic group_analytic = tuple(group_analytic) - -if portal_type and portal_type != portal.getPortalAccountingTransactionTypeList(): +if portal_type and set(portal_type) != set(portal.getPortalAccountingTransactionTypeList()): inventory_params['parent_portal_type'] = portal_type if function: if function == 'None': @@ -58,33 +91,42 @@ if project: if mirror_section_category: inventory_params['mirror_section_category'] = mirror_section_category -if node_uid: - inventory_params['node_uid'] = node_uid - -MARKER = Object() - # a dictionary (node_relative_url, mirror_section_uid, payment_uid + analytic) -# -> dict(debit=, credit=) +# -> {'debit'=, 'credit'=} line_per_account = {} -# a dictionnary node_relative_url -> boolean "do we have transactions for this -# account ?" -account_used = {} +account_used = set() +def markNodeUsed(node): + account_used.add(node['node_relative_url']) +def getTotalPrice(node): + return node['total_price'] or 0 account_type = portal.portal_categories.account_type -balance_sheet_account_type_list = [c[0] for c in - account_type.asset.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False ) + \ - account_type.equity.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) + \ - account_type.liability.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) ] - -profit_and_loss_account_type = [ - 'account_type/expense', - 'account_type/income',] - -account_type_to_group_by_payment = [ 'account_type/asset/cash/bank' ] +balance_sheet_account_type_list = [c[0] for c in + account_type.asset.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) + + account_type.equity.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) + + account_type.liability.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) +] + +profit_and_loss_account_uid_list = getAccountUidListByCategory( + [ + 'account_type/expense', + 'account_type/income', + ], + strict_membership=0, +) + +account_type_to_group_by_payment = [ + 'account_type/asset/cash/bank' +] +node_uid_of_strict_account_type_to_group_by_payment = getAccountUidListByCategory( + account_type_to_group_by_payment, + strict_membership=1, +) account_type_payable_receivable = [ - 'account_type/asset/receivable', - 'account_type/liability/payable', ] + 'account_type/asset/receivable', + 'account_type/liability/payable', +] # For initial balance of third party accounts, we want the same bottom line figure for initial @@ -118,18 +160,23 @@ if expand_accounts: account_type_to_group_by_mirror_section_previous_period = account_type_payable_receivable else: account_type_to_group_by_mirror_section = [] - account_type_to_group_by_mirror_section_previous_period = [] if show_detailed_balance_columns: account_type_to_group_by_mirror_section_previous_period = account_type_payable_receivable - - -account_type_to_group_by_node = [at for at in balance_sheet_account_type_list - if at not in account_type_to_group_by_payment - and at not in account_type_to_group_by_mirror_section] - -account_type_to_group_by_node_previous_period = [at for at in account_type_to_group_by_node - if at not in account_type_to_group_by_mirror_section_previous_period] - + else: + account_type_to_group_by_mirror_section_previous_period = [] +node_uid_of_strict_account_type_to_group_by_mirror_section = getAccountUidListByCategory( + category=account_type_to_group_by_mirror_section, + strict_membership=1, +) + +account_type_to_group_by_node = [ + x for x in balance_sheet_account_type_list + if x not in account_type_to_group_by_payment and x not in account_type_to_group_by_mirror_section +] +node_uid_of_strict_account_type_to_group_by_node = getAccountUidListByCategory( + category=account_type_to_group_by_node, + strict_membership=1, +) total_debit = 0 total_credit = 0 @@ -138,10 +185,9 @@ total_initial_credit_balance = 0 total_final_balance_if_debit = 0 total_final_balance_if_credit = 0 -def getKey(brain, mirror_section=MARKER, payment=MARKER, all_empty=False): - key = (brain['node_relative_url'], - mirror_section, - payment) +MARKER = Object() +def getAccountProps(brain, mirror_section=MARKER, payment=MARKER, all_empty=False): + key = (brain['node_relative_url'], mirror_section, payment) for analytic in group_analytic: if all_empty: key += (MARKER, ) @@ -149,194 +195,111 @@ def getKey(brain, mirror_section=MARKER, payment=MARKER, all_empty=False): key += (getattr(brain, analytic), ) else: key += (brain.getObject().getProperty(analytic.replace('strict_', '', 1)), ) - return key - -analytic_title_dict = {None: '', } -def getAnalyticTitleFromUid(uid): - if uid is MARKER: - return '' try: - return analytic_title_dict[uid] + value = line_per_account[key] except KeyError: - node = getObject(uid) - title = node.getTranslatedTitle() - reference = node.getReference() - if reference: - title = '%s - %s' % (reference, title) - return analytic_title_dict.setdefault(uid, title) + line_per_account[key] = value = {'debit': 0, 'credit': 0} + return value -section_price_currency_dict = {None: ''} -def getSectionPriceCurrencyFromSectionUid(uid): - if uid is MARKER: - return '' - try: - return section_price_currency_dict[uid] - except KeyError: - section = getObject(uid) - price_currency = '' - if section is not None: - price_currency = section.getProperty('price_currency_reference') - return section_price_currency_dict.setdefault(uid, price_currency) +def addAccountProps(entry_list, *args, **kw): + account_props = getAccountProps(*args, **kw) + for key, value in entry_list: + account_props[key] = account_props.get(key, 0) + value # standards accounts {{{ -for node in getInventoryList( - node_category_strict_membership=account_type_to_group_by_node, - group_by_node=1, - omit_asset_decrease=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['debit'] = total_price +local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_node, + 'from_date': from_date, + 'at_date': at_date, + 'portal_type': accounting_movement_type_list, +} +for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node)['debit'] = total_price total_debit += round(total_price, precision) - -for node in getInventoryList( - node_category_strict_membership=account_type_to_group_by_node, - group_by_node=1, - omit_asset_increase=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['credit'] = -total_price +for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node)['credit'] = -total_price total_credit -= round(total_price, precision) # }}} ### profit & loss accounts {{{ -for node in getInventoryList( - node_category=profit_and_loss_account_type, - from_date=max(period_start_date, from_date), - group_by_node=1, - omit_asset_decrease=1, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['debit'] = total_price +local_inventory_params = { + 'node_uid': profit_and_loss_account_uid_list, + 'from_date': max(period_start_date, from_date), + 'at_date': at_date, + 'portal_type': accounting_movement_type_list, +} +for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node)['debit'] = total_price total_debit += round(total_price, precision) - -for node in getInventoryList( - node_category=profit_and_loss_account_type, - from_date=max(period_start_date, from_date), - group_by_node=1, - omit_asset_increase=1, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['credit'] = -total_price +for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node)['credit'] = -total_price total_credit -= round(total_price, precision) # }}} # payable / receivable accounts {{{ -if account_type_to_group_by_mirror_section: - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_mirror_section, - group_by_mirror_section=1, - group_by_node=1, - omit_asset_decrease=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, mirror_section=node['mirror_section_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['debit'] = total_price +if node_uid_of_strict_account_type_to_group_by_mirror_section: + if src__: + src_list.append('-- payable / receivable accounts') + local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_mirror_section, + 'group_by_mirror_section': 1, + 'from_date': from_date, + 'at_date': at_date, + 'portal_type': accounting_movement_type_list, + } + for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node, mirror_section=node['mirror_section_uid'])['debit'] = total_price total_debit += round(total_price, precision) - - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_mirror_section, - group_by_mirror_section=1, - group_by_node=1, - omit_asset_increase=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, mirror_section=node['mirror_section_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['credit'] = - total_price + for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node, mirror_section=node['mirror_section_uid'])['credit'] = -total_price total_credit -= round(total_price, precision) # }}} # bank accounts {{{ -if account_type_to_group_by_payment: - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - omit_asset_decrease=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['debit'] = total_price +if node_uid_of_strict_account_type_to_group_by_payment: + if src__: + src_list.append('-- bank accounts') + local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_payment, + 'group_by_payment': 1, + 'from_date': from_date, + 'at_date': at_date, + 'portal_type': accounting_movement_type_list, + } + for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node, payment=node['payment_uid'])['debit'] = total_price total_debit += round(total_price, precision) - - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - omit_asset_increase=1, - from_date=from_date, - at_date=at_date, - portal_type=accounting_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['credit'] = - total_price + for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + markNodeUsed(node) + total_price = getTotalPrice(node) + getAccountProps(node, payment=node['payment_uid'])['credit'] = - total_price total_credit -= round(total_price, precision) - # }}} - - -node_title_and_id_cache = {} -def getNodeTitleAndId(node_relative_url): - try: - return node_title_and_id_cache[node_relative_url] - except KeyError: - node = traverse(node_relative_url) - return node_title_and_id_cache.setdefault(node_relative_url, - ( node.getUid(), - node.getTranslatedTitle(), - node.Account_getGapId(gap_root=selected_gap), - node.getProperty('string_index'), - node)) +# }}} # include all accounts, even those not selected before (no movements in the # period) -for node in LazyFilter(context.account_module.contentValues(), skip=''): +for node in LazyFilter(portal.account_module.contentValues(), skip=''): # XXX: context should already be account_module if node.getRelativeUrl() not in account_used: - line_per_account.setdefault( - getKey(dict(node_relative_url=node.getRelativeUrl()), all_empty=True), - dict(debit=0, credit=0)) + getAccountProps( + { + 'node_relative_url': node.getRelativeUrl(), + }, + all_empty=True, + ) initial_balance_date = (from_date - 1).latestTime() @@ -344,305 +307,306 @@ initial_balance_date = (from_date - 1).latestTime() # standards accounts {{{ # balance at period start date +local_inventory_params = { + 'node_uid': getAccountUidListByCategory( + [ + x for x in account_type_to_group_by_node + if x not in account_type_to_group_by_mirror_section_previous_period + ], + strict_membership=1, + ), +} for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_node_previous_period, - group_by_node=1, - to_date=period_start_date, - portal_type=accounting_movement_type_list + - balance_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_balance'] = account_props.get( - 'initial_balance', 0) + total_price - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + max(total_price, 0) - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) + max(- total_price, 0) - + to_date=period_start_date, + portal_type=accounting_movement_type_list + balance_movement_type_list, + **local_inventory_params + ): + total_price = getTotalPrice(node) + addAccountProps( + ( + ('initial_balance', total_price), + ('initial_debit_balance', max(total_price, 0)), + ('initial_credit_balance', max(-total_price, 0)), + ), + node, + ) found_balance = False # Balance Transaction for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_node_previous_period, - group_by_node=1, - from_date=from_date, - at_date=from_date + 1, - portal_type=balance_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_balance'] = account_props.get( - 'initial_balance', 0) + total_price - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + max(total_price, 0) - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) + max(- total_price, 0) + from_date=from_date, + at_date=from_date + 1, + portal_type=balance_movement_type_list, + **local_inventory_params + ): + total_price = getTotalPrice(node) + addAccountProps( + ( + ('initial_balance', total_price), + ('initial_debit_balance', max(total_price, 0)), + ('initial_credit_balance', max(-total_price, 0)), + ), + node, + ) found_balance = True - period_movement_type_list = accounting_movement_type_list if not found_balance: - period_movement_type_list = accounting_movement_type_list +\ - balance_movement_type_list - -for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_node, - group_by_node=1, - omit_asset_decrease=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + total_price - -for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_node, - group_by_node=1, - omit_asset_increase=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) - total_price + period_movement_type_list += balance_movement_type_list +local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_node, + 'from_date': period_start_date, + 'to_date': from_date, + 'portal_type': period_movement_type_list, +} +for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + addAccountProps( + ( + ('initial_debit_balance', getTotalPrice(node)), + ), + node, + ) +for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + addAccountProps( + ( + ('initial_credit_balance', -(getTotalPrice(node))), + ), + node, + ) # }}} ### profit & loss accounts {{{ -for node in getInventoryList( - node_category=profit_and_loss_account_type, - omit_asset_decrease=1, - from_date=min(period_start_date, - initial_balance_date), - at_date=initial_balance_date, - group_by_node=1, - portal_type=accounting_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + total_price - -for node in getInventoryList( - node_category=profit_and_loss_account_type, - omit_asset_increase=1, - from_date=min(period_start_date, - initial_balance_date), - at_date=initial_balance_date, - group_by_node=1, - portal_type=accounting_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault(getKey(node), dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) - total_price +local_inventory_params = { + 'node_uid': profit_and_loss_account_uid_list, + 'from_date': min(period_start_date, initial_balance_date), + 'at_date': initial_balance_date, + 'portal_type': accounting_movement_type_list, +} +for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + addAccountProps( + ( + ('initial_debit_balance', getTotalPrice(node)), + ), + node, + ) +for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + addAccountProps( + ( + ('initial_credit_balance', -(getTotalPrice(node))), + ), + node, + ) # }}} # payable / receivable accounts {{{ -# initial balance -if account_type_to_group_by_mirror_section_previous_period: - for node in getInventoryList( - node_category_strict_membership=account_type_to_group_by_mirror_section_previous_period, - group_by_mirror_section=1, - group_by_node=1, - to_date=period_start_date, - portal_type=accounting_movement_type_list + - balance_movement_type_list, - **inventory_params): - mirror_section_key = MARKER - if expand_accounts: - mirror_section_key = node['mirror_section_uid'] - - account_props = line_per_account.setdefault( - getKey(node, mirror_section=mirror_section_key), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + max(total_price, 0) - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) + max(-total_price, 0) - found_balance=False -# Balance Transactions if account_type_to_group_by_mirror_section_previous_period: + if src__: + src_list.append('-- payable / receivable accounts') + # initial balance + local_inventory_params = { + 'node_uid': getAccountUidListByCategory( + category=account_type_to_group_by_mirror_section_previous_period, + strict_membership=1, + ), + 'group_by_mirror_section': 1, + } for node in getInventoryList( - node_category_strict_membership=account_type_to_group_by_mirror_section_previous_period, - group_by_mirror_section=1, - group_by_node=1, - from_date=from_date, - at_date=from_date + 1, - portal_type=balance_movement_type_list, - **inventory_params): - mirror_section_key = MARKER - if expand_accounts: - mirror_section_key = node['mirror_section_uid'] - account_props = line_per_account.setdefault( - getKey(node, mirror_section=mirror_section_key), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + max(total_price, 0) - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) + max(- total_price, 0) + to_date=period_start_date, + portal_type=accounting_movement_type_list + balance_movement_type_list, + **local_inventory_params + ): + total_price = getTotalPrice(node) + addAccountProps( + ( + ('initial_debit_balance', max(total_price, 0)), + ('initial_credit_balance', max(-total_price, 0)), + ), + node, + mirror_section=node['mirror_section_uid'] if expand_accounts else MARKER, + ) + # Balance Transactions + for node in getInventoryList( + from_date=from_date, + at_date=from_date + 1, + portal_type=balance_movement_type_list, + **local_inventory_params + ): + total_price = getTotalPrice(node) + addAccountProps( + ( + ('initial_debit_balance', max(total_price, 0)), + ('initial_credit_balance', max(-total_price, 0)), + ), + node, + mirror_section=node['mirror_section_uid'] if expand_accounts else MARKER, + ) found_balance=True - - period_movement_type_list = accounting_movement_type_list if not found_balance: - period_movement_type_list = accounting_movement_type_list +\ - balance_movement_type_list - - + period_movement_type_list += balance_movement_type_list if expand_accounts: - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_mirror_section, - group_by_mirror_section=1, - group_by_node=1, - omit_asset_decrease=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault( - getKey(node, mirror_section=node['mirror_section_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + total_price - - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_mirror_section, - group_by_mirror_section=1, - group_by_node=1, - omit_asset_increase=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault( - getKey(node, mirror_section=node['mirror_section_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) - total_price + if src__: + src_list.append('-- expand_accounts') + local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_mirror_section, + 'group_by_mirror_section': 1, + 'from_date': period_start_date, + 'to_date': from_date, + 'portal_type': period_movement_type_list, + } + for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + addAccountProps( + ( + ('initial_debit_balance', getTotalPrice(node)), + ), + node, + mirror_section=node['mirror_section_uid'], + ) + for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + addAccountProps( + ( + ('initial_credit_balance', -(getTotalPrice(node))), + ), + node, + mirror_section=node['mirror_section_uid'], + ) # }}} # bank accounts {{{ -if account_type_to_group_by_payment: +if node_uid_of_strict_account_type_to_group_by_payment: + if src__: + src_list.append('-- bank accounts') # Initial balance + local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_payment, + 'group_by_payment': 1, + } for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - to_date=period_start_date, - portal_type=accounting_movement_type_list + - balance_movement_type_list, - **inventory_params): - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + max(total_price, 0) - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) + max(- total_price, 0) - + to_date=period_start_date, + portal_type=accounting_movement_type_list + balance_movement_type_list, + **local_inventory_params + ): + total_price = getTotalPrice(node) + addAccountProps( + ( + ('initial_debit_balance', max(total_price, 0)), + ('initial_credit_balance', max(-total_price, 0)), + ), + node, + payment=node['payment_uid'], + ) found_balance = False # Balance Transaction for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - from_date=from_date, - at_date=from_date + 1, - portal_type=balance_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - total_price += account_props.get('initial_debit_balance', 0) - total_price -= account_props.get('initial_credit_balance', 0) + from_date=from_date, + at_date=from_date + 1, + portal_type=balance_movement_type_list, + **local_inventory_params + ): + account_props = getAccountProps(node, payment=node['payment_uid']) + total_price = (getTotalPrice(node)) + account_props.get('initial_debit_balance', 0) - account_props.get('initial_credit_balance', 0) account_props['initial_debit_balance'] = max(total_price, 0) account_props['initial_credit_balance'] = max(- total_price, 0) found_balance = True - period_movement_type_list = accounting_movement_type_list if not found_balance: - period_movement_type_list = accounting_movement_type_list +\ - balance_movement_type_list - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - omit_asset_decrease=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_debit_balance'] = account_props.get( - 'initial_debit_balance', 0) + total_price + period_movement_type_list += balance_movement_type_list + local_inventory_params = { + 'node_uid': node_uid_of_strict_account_type_to_group_by_payment, + 'group_by_payment': 1, + 'from_date': period_start_date, + 'to_date': from_date, + 'portal_type': period_movement_type_list, + } + for node in getInventoryList(omit_asset_decrease=1, **local_inventory_params): + addAccountProps( + ( + ('initial_debit_balance', getTotalPrice(node)), + ), + node, + payment=node['payment_uid'], + ) + for node in getInventoryList(omit_asset_increase=1, **local_inventory_params): + addAccountProps( + ( + ('initial_credit_balance', -(getTotalPrice(node))), + ), + node, + payment=node['payment_uid'], + ) +# }}} - for node in getInventoryList( - node_category_strict_membership= - account_type_to_group_by_payment, - group_by_payment=1, - group_by_node=1, - omit_asset_increase=1, - from_date=period_start_date, - to_date=from_date, - portal_type=period_movement_type_list, - **inventory_params): - account_used[node['node_relative_url']] = 1 - account_props = line_per_account.setdefault( - getKey(node, payment=node['payment_uid']), - dict(debit=0, credit=0)) - total_price = node['total_price'] or 0 - account_props['initial_credit_balance'] = account_props.get( - 'initial_credit_balance', 0) - total_price - # }}} +if src__: + return src_list +node_title_and_id_cache = {} +def getNodeTitleAndId(node_relative_url): + try: + return node_title_and_id_cache[node_relative_url] + except KeyError: + node = traverse(node_relative_url) + return node_title_and_id_cache.setdefault( + node_relative_url, + ( + node.getUid(), + node.getTranslatedTitle(), + node.Account_getGapId(gap_root=selected_gap), + node.getProperty('string_index'), + node, + ) + ) + +section_price_currency_dict = {None: ''} +def getSectionPriceCurrencyFromSectionUid(uid): + if uid is MARKER: + return '' + try: + return section_price_currency_dict[uid] + except KeyError: + section = getObject(uid) + if section is None: + price_currency = '' + else: + price_currency = section.getProperty('price_currency_reference') + section_price_currency_dict[uid] = price_currency + return price_currency + +analytic_title_dict = {None: ''} +def getAnalyticTitleFromUid(uid): + if uid is MARKER: + return '' + try: + return analytic_title_dict[uid] + except KeyError: + node = getObject(uid) + title = node.getTranslatedTitle() + reference = node.getReference() + if reference: + title = '%s - %s' % (reference, title) + analytic_title_dict[uid] = title + return title + +TRANSLATED_NONE = Base_translateString('None') line_list = [] -for key, data in line_per_account.items(): +for key, data in line_per_account.iteritems(): node_relative_url = key[0] mirror_section_uid = key[1] payment_uid = key[2] analytic_key_list = key[3:] - mirror_section_title = None if expand_accounts and mirror_section_uid is not MARKER: mirror_section_title = getObject(mirror_section_uid).getTitle() + else: + mirror_section_title = None - node_uid, node_title, node_id, node_string_index, node =\ - getNodeTitleAndId(node_relative_url) + node_uid, node_title, node_id, node_string_index, node = getNodeTitleAndId(node_relative_url) if selected_gap and not node.isMemberOf(selected_gap): continue if payment_uid is not MARKER: - if payment_uid is None: - node_title = '%s (%s)' % ( node_title, Base_translateString('None')) - else: - payment = getObject(payment_uid) - node_title = "%s (%s)" % ( node_title, payment.getTitle() ) + node_title += " (%s)" % ( + TRANSLATED_NONE if payment_uid is None else getObject(payment_uid).getTitle(), + ) if not node_string_index: node_string_index = '%-10s' % node_id @@ -652,29 +616,29 @@ for key, data in line_per_account.items(): total_initial_debit_balance += round(initial_debit_balance, precision) total_initial_credit_balance += round(initial_credit_balance, precision) - final_debit_balance = round(initial_debit_balance + data['debit'], - precision) - final_credit_balance = round(initial_credit_balance + data['credit'], - precision) + final_debit_balance = round(initial_debit_balance + data['debit'], precision) + final_credit_balance = round(initial_credit_balance + data['credit'], precision) closing_balance = final_debit_balance - final_credit_balance total_final_balance_if_debit += round(max(closing_balance, 0), precision) total_final_balance_if_credit += round(max(-closing_balance, 0) or 0, precision) - line = Object(uid='new_', - node_id=node_id, - node_title=node_title, - mirror_section_title=mirror_section_title, - node_relative_url=node_relative_url, - initial_balance=initial_debit_balance - initial_credit_balance, - initial_debit_balance=initial_debit_balance, - initial_credit_balance=initial_credit_balance, - debit=data['debit'], - credit=data['credit'], - final_balance=final_debit_balance - final_credit_balance, - final_debit_balance=final_debit_balance, - final_credit_balance=final_credit_balance, - final_balance_if_debit=max(closing_balance, 0), - final_balance_if_credit=max(-closing_balance, 0) or 0,) + line = Object( + uid='new_', + node_id=node_id, + node_title=node_title, + mirror_section_title=mirror_section_title, + node_relative_url=node_relative_url, + initial_balance=initial_debit_balance - initial_credit_balance, + initial_debit_balance=initial_debit_balance, + initial_credit_balance=initial_credit_balance, + debit=data['debit'], + credit=data['credit'], + final_balance=final_debit_balance - final_credit_balance, + final_debit_balance=final_debit_balance, + final_credit_balance=final_credit_balance, + final_balance_if_debit=max(closing_balance, 0), + final_balance_if_credit=max(-closing_balance, 0) or 0, + ) sort_key = (node_string_index, node_title, mirror_section_title) analytic_dict = {} @@ -686,94 +650,89 @@ for key, data in line_per_account.items(): # We sort on section title first sort_key = (title, ) + sort_key sort_key += (title, ) - + analytic_dict['sort_key'] = sort_key line.update(analytic_dict) line_list.append(line) - if not show_empty_accounts: - line_list = [ line for line in line_list - if line['debit'] or - line['credit'] or - line['initial_credit_balance'] or - line['initial_debit_balance'] ] - -line_list.sort(key=lambda obj:obj['sort_key']) + line_list = [ + line for line in line_list + if line['debit'] or + line['credit'] or + line['initial_credit_balance'] or + line['initial_debit_balance'] + ] +line_list.sort(key=lambda obj: obj['sort_key']) # cache values for stat -request.set('TrialBalance.total_initial_debit_balance', - total_initial_debit_balance) -request.set('TrialBalance.total_initial_credit_balance', - total_initial_credit_balance) +request.set('TrialBalance.total_initial_debit_balance', total_initial_debit_balance) +request.set('TrialBalance.total_initial_credit_balance', total_initial_credit_balance) request.set('TrialBalance.debit', total_debit) request.set('TrialBalance.credit', total_credit) request.set('TrialBalance.final_balance_if_debit', total_final_balance_if_debit) request.set('TrialBalance.final_balance_if_credit', total_final_balance_if_credit) -if not per_account_class_summary: - return line_list - -current_gap = selected_gap or \ - portal.portal_preferences.getPreferredAccountingTransactionGap() or '' -if current_gap.startswith('gap/'): - current_gap = current_gap[4:] -def getAccountClass(account_relative_url): - account = traverse(account_relative_url) - for gap in account.getGapList(): - if gap.startswith(current_gap): - gap_part_list = gap.split('/') - # country / accounting principle / ${class} - if len(gap_part_list) > 2: - return gap_part_list[2] - return None # this account has no class on the current GAP - -new_line_list = [] -account_per_class = {} -for brain in line_list: - account_per_class.setdefault( - getAccountClass(brain.node_relative_url), []).append(brain) - -account_class_list = account_per_class.keys() -account_class_list.sort() - -add_line = new_line_list.append -for account_class in account_class_list: - initial_debit_balance = 0 - debit = 0 - final_debit_balance = 0 - initial_credit_balance = 0 - credit = 0 - final_credit_balance = 0 - final_balance_if_debit = 0 - final_balance_if_credit = 0 - - for account in account_per_class[account_class]: - initial_debit_balance += account.initial_debit_balance - debit += account.debit - final_debit_balance += account.final_debit_balance - initial_credit_balance += account.initial_credit_balance - credit += account.credit - final_credit_balance += account.final_credit_balance - final_balance_if_debit += account.final_balance_if_debit - final_balance_if_credit += account.final_balance_if_credit - add_line(account) - - # summary - add_line(Object(node_title=Base_translateString('Total for class ${account_class}', - mapping=dict(account_class=account_class or '???')), - initial_balance=round(initial_debit_balance - initial_credit_balance, precision), - initial_debit_balance=round(initial_debit_balance, precision), - debit=round(debit, precision), - final_debit_balance=round(final_debit_balance, precision), - initial_credit_balance=round(initial_credit_balance, precision), - credit=round(credit, precision), - final_credit_balance=round(final_credit_balance, precision), - final_balance_if_debit=round(final_balance_if_debit, precision), - final_balance_if_credit=round(final_balance_if_credit, precision), - final_balance=round(final_debit_balance - final_credit_balance, precision),)) - - add_line(Object(node_title=' ')) - -return new_line_list +if per_account_class_summary: + current_gap = selected_gap or portal.portal_preferences.getPreferredAccountingTransactionGap() or '' + if current_gap.startswith('gap/'): + current_gap = current_gap[4:] + def getAccountClass(account_relative_url): + account = traverse(account_relative_url) + for gap in account.getGapList(): + if gap.startswith(current_gap): + gap_part_list = gap.split('/') + # country / accounting principle / ${class} + if len(gap_part_list) > 2: + return gap_part_list[2] + return None # this account has no class on the current GAP + + account_per_class = {} + for brain in line_list: + account_per_class.setdefault(getAccountClass(brain.node_relative_url), []).append(brain) + + line_list = [] + add_line = line_list.append + for account_class in sorted(account_per_class): + initial_debit_balance = 0 + debit = 0 + final_debit_balance = 0 + initial_credit_balance = 0 + credit = 0 + final_credit_balance = 0 + final_balance_if_debit = 0 + final_balance_if_credit = 0 + + for account in account_per_class[account_class]: + initial_debit_balance += account.initial_debit_balance + debit += account.debit + final_debit_balance += account.final_debit_balance + initial_credit_balance += account.initial_credit_balance + credit += account.credit + final_credit_balance += account.final_credit_balance + final_balance_if_debit += account.final_balance_if_debit + final_balance_if_credit += account.final_balance_if_credit + add_line(account) + + # summary + add_line(Object( + node_title=Base_translateString( + 'Total for class ${account_class}', + mapping={'account_class': account_class or '???'}, + ), + initial_balance=round(initial_debit_balance - initial_credit_balance, precision), + initial_debit_balance=round(initial_debit_balance, precision), + debit=round(debit, precision), + final_debit_balance=round(final_debit_balance, precision), + initial_credit_balance=round(initial_credit_balance, precision), + credit=round(credit, precision), + final_credit_balance=round(final_credit_balance, precision), + final_balance_if_debit=round(final_balance_if_debit, precision), + final_balance_if_credit=round(final_balance_if_credit, precision), + final_balance=round(final_debit_balance - final_credit_balance, precision), + )) + + add_line(Object(node_title=' ')) + +return line_list # vim: foldmethod=marker diff --git a/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.xml b/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.xml index e2288f5d56..d905bedf3f 100644 --- a/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.xml +++ b/bt5/erp5_accounting/SkinTemplateItem/portal_skins/erp5_accounting/AccountModule_getAccountListForTrialBalance.xml @@ -50,7 +50,7 @@ </item> <item> <key> <string>_params</string> </key> - <value> <string>show_empty_accounts, expand_accounts, at_date, from_date, period_start_date, section_uid, simulation_state, precision, node_uid, gap_root=None, per_account_class_summary=0, portal_type=None, function=None, funding=None, project=None, group_analytic=[], mirror_section_category=None, show_detailed_balance_columns=False, **kw</string> </value> + <value> <string>show_empty_accounts, expand_accounts, at_date, from_date, period_start_date, section_uid, simulation_state, precision, node_uid, gap_root=None, per_account_class_summary=0, portal_type=None, function=None, funding=None, project=None, group_analytic=[], mirror_section_category=None, show_detailed_balance_columns=False, src__=False, **kw</string> </value> </item> <item> <key> <string>id</string> </key> -- 2.30.9