Browse Source

[IMP] mis_builder: use company currency decimal place in deciding if initial balances are null or 0

pull/189/head
Stéphane Bidoul 8 years ago
parent
commit
53192385fb
  1. 53
      mis_builder/models/aep.py
  2. 7
      mis_builder/models/mis_report.py
  3. 5
      mis_builder/models/mis_report_instance.py
  4. 7
      mis_builder/tests/test_aep.py

53
mis_builder/models/aep.py

@ -67,8 +67,9 @@ class AccountingExpressionProcessor(object):
r"(?P<accounts>_[a-zA-Z0-9]+|\[.*?\])"
r"(?P<domain>\[.*?\])?")
def __init__(self, env):
self.env = env
def __init__(self, company):
self.company = company
self.dp = company.currency_id.decimal_places
# before done_parsing: {(domain, mode): set(account_codes)}
# after done_parsing: {(domain, mode): list(account_ids)}
self._map_account_ids = defaultdict(set)
@ -83,8 +84,8 @@ class AccountingExpressionProcessor(object):
# to get the variation, so it's a bit slower
self.smart_end = True
def _load_account_codes(self, account_codes, company):
account_model = self.env['account.account']
def _load_account_codes(self, account_codes):
account_model = self.company.env['account.account']
exact_codes = set()
for account_code in account_codes:
if account_code in self._account_ids_by_code:
@ -92,19 +93,19 @@ class AccountingExpressionProcessor(object):
if account_code is None:
# None means we want all accounts
account_ids = account_model.\
search([('company_id', '=', company.id)]).ids
search([('company_id', '=', self.company.id)]).ids
self._account_ids_by_code[account_code].update(account_ids)
elif '%' in account_code:
account_ids = account_model.\
search([('code', '=like', account_code),
('company_id', '=', company.id)]).ids
('company_id', '=', self.company.id)]).ids
self._account_ids_by_code[account_code].update(account_ids)
else:
# search exact codes after the loop to do less queries
exact_codes.add(account_code)
for account in account_model.\
search([('code', 'in', list(exact_codes)),
('company_id', '=', company.id)]):
('company_id', '=', self.company.id)]):
self._account_ids_by_code[account.code].add(account.id)
def _parse_match_object(self, mo):
@ -146,13 +147,13 @@ class AccountingExpressionProcessor(object):
key = (domain, mode)
self._map_account_ids[key].update(account_codes)
def done_parsing(self, company):
def done_parsing(self):
"""Load account codes and replace account codes by
account ids in map."""
for key, account_codes in self._map_account_ids.items():
# TODO _load_account_codes could be done
# for all account_codes at once (also in v8)
self._load_account_codes(account_codes, company)
self._load_account_codes(account_codes)
account_ids = set()
for account_code in account_codes:
account_ids.update(self._account_ids_by_code[account_code])
@ -165,7 +166,7 @@ class AccountingExpressionProcessor(object):
def get_aml_domain_for_expr(self, expr,
date_from, date_to,
target_move, company,
target_move,
account_id=None):
""" Get a domain on account.move.line for an expression.
@ -197,15 +198,14 @@ class AccountingExpressionProcessor(object):
if mode not in date_domain_by_mode:
date_domain_by_mode[mode] = \
self.get_aml_domain_for_dates(date_from, date_to,
mode, target_move,
company)
mode, target_move)
assert aml_domains
return expression.OR(aml_domains) + \
expression.OR(date_domain_by_mode.values())
def get_aml_domain_for_dates(self, date_from, date_to,
mode,
target_move, company):
target_move):
if mode == self.MODE_VARIATION:
domain = [('date', '>=', date_from), ('date', '<=', date_to)]
elif mode in (self.MODE_INITIAL, self.MODE_END):
@ -214,7 +214,8 @@ class AccountingExpressionProcessor(object):
# sum from the beginning of time
date_from_date = fields.Date.from_string(date_from)
fy_date_from = \
company.compute_fiscalyear_dates(date_from_date)['date_from']
self.company.\
compute_fiscalyear_dates(date_from_date)['date_from']
domain = ['|',
('date', '>=', fields.Date.to_string(fy_date_from)),
('user_type_id.include_initial_balance', '=', True)]
@ -225,21 +226,22 @@ class AccountingExpressionProcessor(object):
elif mode == self.MODE_UNALLOCATED:
date_from_date = fields.Date.from_string(date_from)
fy_date_from = \
company.compute_fiscalyear_dates(date_from_date)['date_from']
self.company.\
compute_fiscalyear_dates(date_from_date)['date_from']
domain = [('date', '<', fields.Date.to_string(fy_date_from)),
('user_type_id.include_initial_balance', '=', False)]
if target_move == 'posted':
domain.append(('move_id.state', '=', 'posted'))
return expression.normalize_domain(domain)
def do_queries(self, company, date_from, date_to,
def do_queries(self, date_from, date_to,
target_move='posted', additional_move_line_filter=None):
"""Query sums of debit and credit for all accounts and domains
used in expressions.
This method must be executed after done_parsing().
"""
aml_model = self.env['account.move.line']
aml_model = self.company.env['account.move.line']
# {(domain, mode): {account_id: (debit, credit)}}
self._data = defaultdict(dict)
domain_by_mode = {}
@ -253,7 +255,7 @@ class AccountingExpressionProcessor(object):
if mode not in domain_by_mode:
domain_by_mode[mode] = \
self.get_aml_domain_for_dates(date_from, date_to,
mode, target_move, company)
mode, target_move)
domain = list(domain) + domain_by_mode[mode]
domain.append(('account_id', 'in', self._map_account_ids[key]))
if additional_move_line_filter:
@ -266,7 +268,8 @@ class AccountingExpressionProcessor(object):
debit = acc['debit'] or 0.0
credit = acc['credit'] or 0.0
if mode in (self.MODE_INITIAL, self.MODE_UNALLOCATED) and \
float_is_zero(debit-credit, precision_rounding=4):
float_is_zero(debit-credit,
precision_rounding=self.dp):
# in initial mode, ignore accounts with 0 balance
continue
self._data[key][acc['account_id'][0]] = (debit, credit)
@ -311,7 +314,7 @@ class AccountingExpressionProcessor(object):
# as it does not make sense to distinguish 0 from "no data"
if v is not AccountingNone and \
mode in (self.MODE_INITIAL, self.MODE_UNALLOCATED) and \
float_is_zero(v, precision_rounding=4):
float_is_zero(v, precision_rounding=self.dp):
v = AccountingNone
return '(' + repr(v) + ')'
@ -342,7 +345,7 @@ class AccountingExpressionProcessor(object):
# as it does not make sense to distinguish 0 from "no data"
if v is not AccountingNone and \
mode in (self.MODE_INITIAL, self.MODE_UNALLOCATED) and \
float_is_zero(v, precision_rounding=4):
float_is_zero(v, precision_rounding=self.dp):
v = AccountingNone
return '(' + repr(v) + ')'
@ -365,13 +368,13 @@ class AccountingExpressionProcessor(object):
def _get_balances(cls, mode, company, date_from, date_to,
target_move='posted'):
expr = 'deb{mode}[], crd{mode}[]'.format(mode=mode)
aep = AccountingExpressionProcessor(company.env)
aep = AccountingExpressionProcessor(company)
# disable smart_end to have the data at once, instead
# of initial + variation
aep.smart_end = False
aep.parse_expr(expr)
aep.done_parsing(company)
aep.do_queries(company, date_from, date_to, target_move)
aep.done_parsing()
aep.do_queries(date_from, date_to, target_move)
return aep._data[((), mode)]
@classmethod
@ -395,7 +398,7 @@ class AccountingExpressionProcessor(object):
""" A convenience method to obtain the ending balances of all accounts
at a given date.
It is the same as get_balances_init(date+1).
It is the same as get_balances_initial(date+1).
:param company:
:param date:

7
mis_builder/models/mis_report.py

@ -790,11 +790,11 @@ class MisReport(models.Model):
@api.multi
def prepare_aep(self, company):
self.ensure_one()
aep = AEP(self.env)
aep = AEP(company)
for kpi in self.kpi_ids:
for expression in kpi.expression_ids:
aep.parse_expr(expression.name)
aep.done_parsing(company)
aep.done_parsing()
return aep
@api.multi
@ -915,8 +915,7 @@ class MisReport(models.Model):
additional_move_line_filter = None
if get_additional_move_line_filter:
additional_move_line_filter = get_additional_move_line_filter()
aep.do_queries(company,
date_from, date_to,
aep.do_queries(date_from, date_to,
target_move,
additional_move_line_filter)

5
mis_builder/models/mis_report_instance.py

@ -399,14 +399,13 @@ class MisReportInstance(models.Model):
account_id = arg.get('account_id')
if period_id and expr and AEP.has_account_var(expr):
period = self.env['mis.report.instance.period'].browse(period_id)
aep = AEP(self.env)
aep = AEP(self.company_id)
aep.parse_expr(expr)
aep.done_parsing(self.company_id)
aep.done_parsing()
domain = aep.get_aml_domain_for_expr(
expr,
period.date_from, period.date_to,
self.target_move,
self.company_id,
account_id)
domain.extend(period._get_additional_move_line_filter())
return {

7
mis_builder/tests/test_aep.py

@ -66,7 +66,7 @@ class TestAEP(common.TransactionCase):
debit_acc=self.account_ar,
credit_acc=self.account_in)
# create the AEP, and prepare the expressions we'll need
self.aep = AEP(self.env)
self.aep = AEP(self.company)
self.aep.parse_expr("bali[]")
self.aep.parse_expr("bale[]")
self.aep.parse_expr("balp[]")
@ -81,7 +81,7 @@ class TestAEP(common.TransactionCase):
self.aep.parse_expr("crdp[700I%]")
self.aep.parse_expr("bal_700IN") # deprecated
self.aep.parse_expr("bals[700IN]") # deprecated
self.aep.done_parsing(self.company)
self.aep.done_parsing()
def _create_move(self, date, amount, debit_acc, credit_acc):
move = self.move_model.create({
@ -103,8 +103,7 @@ class TestAEP(common.TransactionCase):
self.aep.do_queries(
date_from=fields.Date.to_string(date_from),
date_to=fields.Date.to_string(date_to),
target_move='posted',
company=self.company)
target_move='posted')
def _eval(self, expr):
eval_dict = {'AccountingNone': AccountingNone}

Loading…
Cancel
Save