diff --git a/mis_builder/models/aep.py b/mis_builder/models/aep.py index e50f84cc..25f8970d 100644 --- a/mis_builder/models/aep.py +++ b/mis_builder/models/aep.py @@ -67,8 +67,9 @@ class AccountingExpressionProcessor(object): r"(?P_[a-zA-Z0-9]+|\[.*?\])" r"(?P\[.*?\])?") - 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: diff --git a/mis_builder/models/mis_report.py b/mis_builder/models/mis_report.py index 15fe11cb..ed8f8215 100644 --- a/mis_builder/models/mis_report.py +++ b/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) diff --git a/mis_builder/models/mis_report_instance.py b/mis_builder/models/mis_report_instance.py index e0462307..8d436343 100644 --- a/mis_builder/models/mis_report_instance.py +++ b/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 { diff --git a/mis_builder/tests/test_aep.py b/mis_builder/tests/test_aep.py index 1be10b13..5b1f349a 100644 --- a/mis_builder/tests/test_aep.py +++ b/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}