AccountingTransactionModule_get*AgedBalanceLineList: Rework.
Make it more easily extensible by exposing a callback. Stop loading documents in the simple version that are only needed by the detailed version. Also, stop checking for this inside the main loop, and instead use the callback mechanism. Use a single query to look for mirror section title instead of one per mirror section. Behaviour change: mirror section (ie, the entity) title is not translated anymore. It used to be because there did not seem to be a reasion not to. It is not anymore to avoid loading rach entity from ZODB in the default report. This rework makes customisation easier, including overwriting this untranslated title with any desired transformation.
Showing
""" | |||
at_date (DateTime) | |||
See getMovementHistoryList. | |||
section_category (str) | |||
section_category_strict (bool) | |||
See Base_getSectionUidListForSectionCategory. | |||
Result passed to getMovementHistoryList. | |||
simulation_state (str or list of str) | |||
See getMovementHistoryList. | |||
period_list (list of numbers) | |||
List of operation age ranges, in days. Used to dispatch operations by age: | |||
period_0: older than earliest period | |||
period_1: younger than earliest period, older than next period | |||
... | |||
period_n: younger than period n-1, older than at_date | |||
period_future: Posterior to at_date | |||
account_type (str) | |||
Must be one of: | |||
'account_type/asset/receivable' | |||
'account_type/liability/payable' | |||
lineCallback ((brain, period_name, line_dict) -> dict) | |||
Called for each line found by getMovementHistoryList. | |||
brain | |||
Current line. | |||
period_name (string) | |||
Name of the period this line belongs to. | |||
line_dict (dict) | |||
Dictionary containing properties of corresponding line in the report. | |||
May be modified by callback. | |||
Returned value is resulting line property dictionary, or None to skip this | |||
row. | |||
reportCallback ((line_list) -> list of dict) | |||
Called once all lines from getMovementHistoryList have been processed. | |||
line_list (list) | |||
Each entry is the dict returned by lineCallback, in order. | |||
May be modified by callback. | |||
Returned value is final line list. Each line must be a dict. If unsure, return | |||
line_list. | |||
""" | |||
from collections import defaultdict | |||
from Products.ZSQLCatalog.SQLCatalog import SimpleQuery, ComplexQuery | |||
from Products.PythonScripts.standard import Object | |||
if reportCallback is None: | |||
reportCallback = lambda x: x | |||
portal = context.getPortalObject() | |||
portal_catalog = portal.portal_catalog | |||
portal_categories = portal.portal_categories | |||
# we set the precision in request, for formatting on editable fields | |||
portal.REQUEST.set( | |||
'precision', | |||
context.account_module.getQuantityPrecisionFromResource( | |||
context.Base_getCurrencyForSection(section_category), | |||
), | |||
) | |||
line_list = [] | |||
assert account_type in ('account_type/asset/receivable', 'account_type/liability/payable') | |||
reverse_price_sign = account_type == 'account_type/liability/payable' | |||
by_mirror_section_list_dict = defaultdict(list) | |||
node_uid_list = [ | |||
x.uid | |||
for x in portal_catalog( | |||
portal_type='Account', | |||
strict_account_type_uid=portal_categories.restrictedTraverse(account_type).getUid(), | |||
) | |||
] | |||
if not node_uid_list: | |||
return [] | |||
extra_kw = {} | |||
ledger_relative_url_list = kw.get('ledger', None) | |||
if ledger_relative_url_list: | |||
if not isinstance(ledger_relative_url_list, list): | |||
ledger_relative_url_list = [ledger_relative_url_list] | |||
traverse = portal.portal_categories.restrictedTraverse | |||
extra_kw['ledger_uid'] = [traverse(x).getUid() for x in ledger_relative_url_list] | |||
period_list = [ | |||
('period_%i' % x, y) | |||
for x, y in enumerate(sorted(period_list)) | |||
] | |||
last_period_id = 'period_%s' % len(period_list) | |||
for brain in portal.portal_simulation.getMovementHistoryList( | |||
at_date=at_date, | |||
simulation_state=simulation_state, | |||
node_uid=node_uid_list, | |||
portal_type=portal.getPortalAccountingMovementTypeList(), | |||
section_uid=portal.Base_getSectionUidListForSectionCategory( | |||
section_category, | |||
section_category_strict, | |||
), | |||
grouping_query=ComplexQuery( | |||
SimpleQuery(grouping_reference=None), | |||
SimpleQuery(grouping_date=at_date, comparison_operator=">="), | |||
logical_operator="OR", | |||
), | |||
**extra_kw | |||
): | |||
total_price = brain.total_price or 0 | |||
if reverse_price_sign: | |||
total_price = -total_price | |||
# Note that we use date_utc because date would load the object and we are just | |||
# interested in the difference of days. | |||
age = int(at_date - brain.date_utc) | |||
if age < 0: | |||
period_name = 'period_future' | |||
else: | |||
for period_name, period in period_list: | |||
if age <= period: | |||
break | |||
else: | |||
period_name = last_period_id | |||
line_dict = lineCallback( | |||
brain=brain, | |||
period_name=period_name, | |||
line_dict={ | |||
'mirror_section_uid': brain.mirror_section_uid, | |||
'total_price': total_price, | |||
'age': age, | |||
period_name: total_price, | |||
}, | |||
) | |||
if line_dict is not None: | |||
by_mirror_section_list_dict[brain.mirror_section_uid].append(line_dict) | |||
line_list.append(line_dict) | |||
for row in portal_catalog( | |||
select_list=['title'], | |||
uid=by_mirror_section_list_dict.keys(), | |||
|
|||
): | |||
title = row.title | |||
for line in by_mirror_section_list_dict[row.uid]: | |||
line['mirror_section_title'] = title | |||
return [ | |||
Object( | |||
uid='new_', | |||
**x | |||
) | |||
for x in reportCallback(line_list) | |||
] |