diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index 975c88cdf16..4eb59c79090 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -510,7 +510,7 @@ class account_journal(models.Model): [action] = self.env[model].browse(action_id).read() action['context'] = ctx if ctx.get('use_domain', False): - action['domain'] = ['|', ('journal_id', '=', self.id), ('journal_id', '=', False)] + action['domain'] = isinstance(ctx['use_domain'], list) and ctx['use_domain'] or ['|', ('journal_id', '=', self.id), ('journal_id', '=', False)] action['name'] += ' for journal ' + self.name return action diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 83a65f028f0..fcb7f4b08ad 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -3,11 +3,83 @@ from odoo import api, fields, models, _ from odoo.tools import float_compare, float_is_zero from odoo.exceptions import UserError - import re from math import copysign +class AccountReconcileModelLine(models.Model): + _name = 'account.reconcile.model.line' + _description = 'Rules for the reconciliation model' + _order = 'sequence, id' + + model_id = fields.Many2one('account.reconcile.model', readonly=True) + match_total_amount = fields.Boolean(related='model_id.match_total_amount') + match_total_amount_param = fields.Float(related='model_id.match_total_amount_param') + rule_type = fields.Selection(related='model_id.rule_type') + company_id = fields.Many2one(related='model_id.company_id') + sequence = fields.Integer(required=True, default=10) + account_id = fields.Many2one('account.account', string='Account', ondelete='cascade', domain=[('deprecated', '=', False)], required=True) + journal_id = fields.Many2one('account.journal', string='Journal', ondelete='cascade', help="This field is ignored in a bank statement reconciliation.") + label = fields.Char(string='Journal Item Label') + amount_type = fields.Selection([ + ('fixed', 'Fixed'), + ('percentage', 'Percentage of balance'), + ('regex', 'From label'), + ], required=True, default='percentage') + show_force_tax_included = fields.Boolean(compute='_compute_show_force_tax_included', help='Technical field used to show the force tax included button') + force_tax_included = fields.Boolean(string='Tax Included in Price', help='Force the tax to be managed as a price included tax.') + amount = fields.Float(string="Float Amount", compute='_compute_float_amount', store=True, help="Technical shortcut to parse the amount to a float") + amount_string = fields.Char(string="Amount", default='100', required=True, help="""Value for the amount of the writeoff line + * Percentage: Percentage of the balance, between 0 and 100. + * Fixed: The fixed value of the writeoff. The amount will count as a debit if it is negative, as a credit if it is positive. + * From Label: There is no need for regex delimiter, only the regex is needed. For instance if you want to extract the amount from\nR:9672938 10/07 AX 9415126318 T:5L:NA BRT: 3358,07 C:\nYou could enter\nBRT: ([\d,]+)""") + tax_ids = fields.Many2many('account.tax', string='Taxes', ondelete='restrict') + analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', ondelete='set null') + analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags', + relation='account_reconcile_model_analytic_tag_rel') + + @api.onchange('tax_ids') + def _onchange_tax_ids(self): + # Multiple taxes with force_tax_included results in wrong computation, so we + # only allow to set the force_tax_included field if we have one tax selected + if len(self.tax_ids) != 1: + self.force_tax_included = False + + @api.depends('tax_ids') + def _compute_show_force_tax_included(self): + for record in self: + record.show_force_tax_included = False if len(record.tax_ids) != 1 else True + + @api.onchange('amount_type') + def _onchange_amount_type(self): + self.amount_string = '' + if self.amount_type == 'percentage': + self.amount_string = '100' + elif self.amount_type == 'regex': + self.amount_string = '([\d,]+)' + + @api.depends('amount_string') + def _compute_float_amount(self): + for record in self: + try: + record.amount = float(record.amount_string) + except ValueError: + record.amount = 0 + + @api.constrains('amount_string') + def _validate_amount(self): + for record in self: + if record.amount_type == 'fixed' and record.amount == 0: + raise UserError(_('The amount is not a number')) + if record.amount_type == 'percentage' and not 0 < record.amount <= 100: + raise UserError(_('The amount is not a percentage')) + if record.amount_type == 'regex': + try: + re.compile(record.amount_string) + except re.error: + raise UserError(_('The regex is not valid')) + + class AccountReconcileModel(models.Model): _name = 'account.reconcile.model' _description = 'Preset to create journal entries during a invoices and payments matching' @@ -88,47 +160,10 @@ class AccountReconcileModel(models.Model): match_partner_category_ids = fields.Many2many('res.partner.category', string='Restrict Partner Categories to', help='The reconciliation model will only be applied to the selected customer/vendor categories.') - # ===== Write-Off ===== - # First part fields. - account_id = fields.Many2one('account.account', string='Account', ondelete='cascade', domain=[('deprecated', '=', False)]) - journal_id = fields.Many2one('account.journal', string='Journal', ondelete='cascade', help="This field is ignored in a bank statement reconciliation.") - label = fields.Char(string='Journal Item Label') - amount_type = fields.Selection([ - ('fixed', 'Fixed'), - ('percentage', 'Percentage of balance'), - ('regex', 'From label'), - ], required=True, default='percentage') - show_force_tax_included = fields.Boolean(compute='_compute_show_force_tax_included', help='Technical field used to show the force tax included button') - force_tax_included = fields.Boolean(string='Tax Included in Price', - help='Force the tax to be managed as a price included tax.') - amount = fields.Float(string='Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.") - amount_from_label_regex = fields.Char(string="Amount from Label (regex)", default=r"([\d\.,]+)", help="There is no need for regex delimiter, only the regex is needed. For instance if you want to extract the amount from\nR:9672938 10/07 AX 9415126318 T:5L:NA BRT: 3358,07 C:\nYou could enter\nBRT: ([\d,]+)") + line_ids = fields.One2many('account.reconcile.model.line', 'model_id') + decimal_separator = fields.Char(default=lambda self: self.env['res.lang']._lang_get(self.env.user.lang).decimal_point, help="Every character that is nor a digit nor this separator will be removed from the matching string") - tax_ids = fields.Many2many('account.tax', string='Taxes', ondelete='restrict') - analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', ondelete='set null') - analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags', - relation='account_reconcile_model_analytic_tag_rel') - - # Second part fields. - has_second_line = fields.Boolean(string='Add a second line', default=False) - second_account_id = fields.Many2one('account.account', string='Second Account', ondelete='cascade', domain=[('deprecated', '=', False)]) - second_journal_id = fields.Many2one('account.journal', string='Second Journal', ondelete='cascade', help="This field is ignored in a bank statement reconciliation.") - second_label = fields.Char(string='Second Journal Item Label') - second_amount_type = fields.Selection([ - ('fixed', 'Fixed'), - ('percentage', 'Percentage of balance'), - ('regex', 'From label'), - ], string="Second Amount type",required=True, default='percentage') - show_second_force_tax_included = fields.Boolean(compute='_compute_show_second_force_tax_included', help='Technical field used to show the force tax included button') - force_second_tax_included = fields.Boolean(string='Second Tax Included in Price', - help='Force the second tax to be managed as a price included tax.') - second_amount = fields.Float(string='Second Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.") - second_amount_from_label_regex = fields.Char(string="Second Amount from Label (regex)", default=r"([\d\.,]+)") - second_tax_ids = fields.Many2many('account.tax', relation='account_reconcile_model_account_tax_bis_rel', string='Second Taxes', ondelete='restrict') - second_analytic_account_id = fields.Many2one('account.analytic.account', string='Second Analytic Account', ondelete='set null') - second_analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Second Analytic Tags', - relation='account_reconcile_model_second_analytic_tag_rel') - + show_decimal_separator = fields.Boolean(compute='_compute_show_decimal_separator', help="Technical field to decide if we should show the decimal separator for the regex matching field.") number_entries = fields.Integer(string='Number of entries related to this model', compute='_compute_number_entries') def action_reconcile_stat(self): @@ -152,29 +187,10 @@ class AccountReconcileModel(models.Model): for model in self: model.number_entries = mapped_data.get(model.id, 0) - @api.onchange('tax_ids') - def _onchange_tax_ids(self): - # Multiple taxes with force_tax_included results in wrong computation, so we - # only allow to set the force_tax_included field if we have one tax selected - if len(self.tax_ids) != 1: - self.force_tax_included = False - - @api.depends('tax_ids') - def _compute_show_force_tax_included(self): + @api.depends('line_ids.amount_type') + def _compute_show_decimal_separator(self): for record in self: - record.show_force_tax_included = False if len(record.tax_ids) != 1 else True - - @api.onchange('second_tax_ids') - def _onchange_second_tax_ids(self): - # Multiple taxes with force_tax_included results in wrong computation, so we - # only allow to set the force_tax_included field if we have one tax selected - if len(self.second_tax_ids) != 1: - self.force_second_tax_included = False - - @api.depends('second_tax_ids') - def _compute_show_second_force_tax_included(self): - for record in self: - record.show_second_force_tax_included = False if len(record.second_tax_ids) != 1 else True + record.show_decimal_separator = any(l.amount_type == 'regex' for l in record.line_ids) @api.onchange('match_total_amount_param') def _onchange_match_total_amount_param(self): @@ -185,13 +201,13 @@ class AccountReconcileModel(models.Model): # RECONCILIATION PROCESS #################################################### - @api.model def _get_taxes_move_lines_dict(self, tax, base_line_dict): ''' Get move.lines dict (to be passed to the create()) corresponding to a tax. :param tax: An account.tax record. :param base_line_dict: A dict representing the move.line containing the base amount. :return: A list of dict representing move.lines to be created corresponding to the tax. ''' + self.ensure_one() balance = base_line_dict['debit'] - base_line_dict['credit'] currency = base_line_dict.get('currency_id') and self.env['res.currency'].browse(base_line_dict['currency_id']) @@ -212,7 +228,8 @@ class AccountReconcileModel(models.Model): 'tax_exigible': tax_res['tax_exigibility'], 'tax_repartition_line_id': tax_res['tax_repartition_line_id'], 'tax_ids': tax_res['tax_ids'], - 'tag_ids': tax_res['tag_ids'] + 'tag_ids': tax_res['tag_ids'], + 'reconcile_model_id': self.id, }) # Handle price included taxes. @@ -221,7 +238,7 @@ class AccountReconcileModel(models.Model): base_line_dict['tag_ids'] = [(6, 0, res['base_tags'])] return new_aml_dicts - def _get_write_off_move_lines_dict(self, st_line, move_lines=None): + def _get_write_off_move_lines_dict(self, st_line, move_lines=None, residual_balance=None): ''' Get move.lines dict (to be passed to the create()) corresponding to the reconciliation model's write-off lines. :param st_line: An account.bank.statement.line record. :param move_lines: An account.move.line recordset. @@ -238,76 +255,43 @@ class AccountReconcileModel(models.Model): balance = total_residual - line_residual - if not self.account_id or float_is_zero(balance, precision_rounding=line_currency.rounding): - return [] - - if self.amount_type == 'percentage': - line_balance = balance * (self.amount / 100.0) - elif self.amount_type == "regex": - match = re.search(self.amount_from_label_regex, st_line.name) - if match: - line_balance = copysign(float(re.sub(r'\D' + self.decimal_separator, '', match.group(1)).replace(self.decimal_separator, '.')) * (1 if balance > 0.0 else -1), balance) - else: - line_balance = 0 - else: - line_balance = self.amount * (1 if balance > 0.0 else -1) - new_aml_dicts = [] + if residual_balance is None: + residual_balance = balance + for line in self.line_ids: + if not line.account_id or float_is_zero(residual_balance, precision_rounding=line_currency.rounding): + continue - # First write-off line. - writeoff_line = { - 'name': self.label or st_line.name, - 'account_id': self.account_id.id, - 'analytic_account_id': self.analytic_account_id.id, - 'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)], - 'debit': line_balance > 0 and line_balance or 0, - 'credit': line_balance < 0 and -line_balance or 0, - 'reconcile_model_id': self.id, - } - new_aml_dicts.append(writeoff_line) - - if self.tax_ids: - writeoff_line['tax_ids'] = [(6, None, self.tax_ids.ids)] - tax = self.tax_ids - # Multiple taxes with force_tax_included results in wrong computation, so we - # only allow to set the force_tax_included field if we have one tax selected - if self.force_tax_included: - tax = tax[0].with_context(force_price_include=True) - new_aml_dicts += self._get_taxes_move_lines_dict(tax, writeoff_line) - - # Second write-off line. - if self.has_second_line and self.second_account_id: - remaining_balance = balance - sum(aml['debit'] - aml['credit'] for aml in new_aml_dicts) - if self.second_amount_type == 'percentage': - line_balance = remaining_balance * (self.second_amount / 100.0) - elif self.second_amount_type == "regex": - match = re.search(self.second_amount_from_label_regex, st_line.name) + if line.amount_type == 'percentage': + line_balance = residual_balance * (line.amount / 100.0) + elif line.amount_type == "regex": + match = re.search(line.amount_string, st_line.name) if match: - line_balance = copysign(float(re.sub(r'\D' + self.decimal_separator, '', match.group(1)).replace(self.decimal_separator, '.')), remaining_balance) + line_balance = copysign(float(re.sub(r'\D' + self.decimal_separator, '', match.group(1)).replace(self.decimal_separator, '.')) * (1 if balance > 0.0 else -1), balance) else: line_balance = 0 else: - line_balance = self.second_amount * (1 if remaining_balance > 0.0 else -1) - - second_writeoff_line = { - 'name': self.second_label or st_line.name, - 'account_id': self.second_account_id.id, - 'analytic_account_id': self.second_analytic_account_id.id, - 'analytic_tag_ids': [(6, 0, self.second_analytic_tag_ids.ids)], + line_balance = line.amount * (1 if residual_balance > 0.0 else -1) + writeoff_line = { + 'name': line.label or st_line.name, + 'account_id': line.account_id.id, + 'analytic_account_id': line.analytic_account_id.id, + 'analytic_tag_ids': [(6, 0, line.analytic_tag_ids.ids)], 'debit': line_balance > 0 and line_balance or 0, 'credit': line_balance < 0 and -line_balance or 0, 'reconcile_model_id': self.id, } - new_aml_dicts.append(second_writeoff_line) + new_aml_dicts.append(writeoff_line) - if self.second_tax_ids: - second_writeoff_line['tax_ids'] = [(6, None, self.second_tax_ids.ids)] - tax = self.second_tax_ids + residual_balance -= line_balance + if line.tax_ids: + writeoff_line['tax_ids'] = [(6, None, line.tax_ids.ids)] + tax = line.tax_ids # Multiple taxes with force_tax_included results in wrong computation, so we # only allow to set the force_tax_included field if we have one tax selected - if self.force_second_tax_included: + if line.force_tax_included: tax = tax[0].with_context(force_price_include=True) - new_aml_dicts += self._get_taxes_move_lines_dict(tax, second_writeoff_line) + new_aml_dicts += self._get_taxes_move_lines_dict(tax, writeoff_line) return new_aml_dicts diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 6a5220f50ed..6dd67e8fce5 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -698,44 +698,42 @@ class AccountChartTemplate(models.Model): """ This method generates a dictionary of all the values for the account.reconcile.model that will be created. """ self.ensure_one() + account_reconcile_model_lines = self.env['account.reconcile.model.line.template'].search([ + ('model_id', '=', account_reconcile_model.id) + ]) return { - 'name': account_reconcile_model.name, - 'sequence': account_reconcile_model.sequence, - 'has_second_line': account_reconcile_model.has_second_line, - 'company_id': company.id, - 'account_id': acc_template_ref[account_reconcile_model.account_id.id], - 'label': account_reconcile_model.label, - 'to_check': account_reconcile_model.to_check, - 'amount_type': account_reconcile_model.amount_type, - 'force_tax_included': account_reconcile_model.force_tax_included, - 'amount': account_reconcile_model.amount, - 'tax_ids': [[4, tax_template_ref[tax.id], 0] for tax in account_reconcile_model.tax_ids], - 'second_account_id': account_reconcile_model.second_account_id and acc_template_ref[account_reconcile_model.second_account_id.id] or False, - 'second_label': account_reconcile_model.second_label, - 'second_amount_type': account_reconcile_model.second_amount_type, - 'force_second_tax_included': account_reconcile_model.force_second_tax_included, - 'second_amount': account_reconcile_model.second_amount, - 'rule_type': account_reconcile_model.rule_type, - 'auto_reconcile': account_reconcile_model.auto_reconcile, - 'match_journal_ids': [(6, None, account_reconcile_model.match_journal_ids.ids)], - 'match_nature': account_reconcile_model.match_nature, - 'match_amount': account_reconcile_model.match_amount, - 'match_amount_min': account_reconcile_model.match_amount_min, - 'match_amount_max': account_reconcile_model.match_amount_max, - 'match_label': account_reconcile_model.match_label, - 'match_label_param': account_reconcile_model.match_label_param, - 'match_note': account_reconcile_model.match_note, - 'match_note_param': account_reconcile_model.match_note_param, - 'match_transaction_type': account_reconcile_model.match_transaction_type, - 'match_transaction_type_param': account_reconcile_model.match_transaction_type_param, - 'match_same_currency': account_reconcile_model.match_same_currency, - 'match_total_amount': account_reconcile_model.match_total_amount, - 'match_total_amount_param': account_reconcile_model.match_total_amount_param, - 'match_partner': account_reconcile_model.match_partner, - 'match_partner_ids': [(6, None, account_reconcile_model.match_partner_ids.ids)], - 'match_partner_category_ids': [(6, None, account_reconcile_model.match_partner_category_ids.ids)], - 'second_tax_ids': [[4, tax_template_ref[tax.id], 0] for tax in account_reconcile_model.second_tax_ids], - } + 'name': account_reconcile_model.name, + 'sequence': account_reconcile_model.sequence, + 'company_id': company.id, + 'rule_type': account_reconcile_model.rule_type, + 'auto_reconcile': account_reconcile_model.auto_reconcile, + 'to_check': account_reconcile_model.to_check, + 'match_journal_ids': [(6, None, account_reconcile_model.match_journal_ids.ids)], + 'match_nature': account_reconcile_model.match_nature, + 'match_amount': account_reconcile_model.match_amount, + 'match_amount_min': account_reconcile_model.match_amount_min, + 'match_amount_max': account_reconcile_model.match_amount_max, + 'match_label': account_reconcile_model.match_label, + 'match_label_param': account_reconcile_model.match_label_param, + 'match_note': account_reconcile_model.match_note, + 'match_note_param': account_reconcile_model.match_note_param, + 'match_transaction_type': account_reconcile_model.match_transaction_type, + 'match_transaction_type_param': account_reconcile_model.match_transaction_type_param, + 'match_same_currency': account_reconcile_model.match_same_currency, + 'match_total_amount': account_reconcile_model.match_total_amount, + 'match_total_amount_param': account_reconcile_model.match_total_amount_param, + 'match_partner': account_reconcile_model.match_partner, + 'match_partner_ids': [(6, None, account_reconcile_model.match_partner_ids.ids)], + 'match_partner_category_ids': [(6, None, account_reconcile_model.match_partner_category_ids.ids)], + 'line_ids': [(0, 0, { + 'account_id': acc_template_ref[line.account_id.id], + 'label': line.label, + 'amount_type': line.amount_type, + 'force_tax_included': line.force_tax_included, + 'amount_string': line.amount_string, + 'tax_ids': [[4, tax_template_ref[tax.id], 0] for tax in line.tax_ids], + }) for line in account_reconcile_model_lines], + } def generate_account_reconcile_model(self, tax_template_ref, acc_template_ref, company): """ This method creates account reconcile models @@ -1175,31 +1173,23 @@ class AccountReconcileModelTemplate(models.Model): match_partner_category_ids = fields.Many2many('res.partner.category', string='Restrict Partner Categories to', help='The reconciliation model will only be applied to the selected customer/vendor categories.') - # First part fields. + line_ids = fields.One2many('account.reconcile.model.line.template', 'model_id') + decimal_separator = fields.Char(help="Every character that is nor a digit nor this separator will be removed from the matching string") + + +class AccountReconcileModelLineTemplate(models.Model): + _name = "account.reconcile.model.line.template" + _description = 'Reconcile Model Line Template' + + model_id = fields.Many2one('account.reconcile.model.template') + sequence = fields.Integer(required=True, default=10) account_id = fields.Many2one('account.account.template', string='Account', ondelete='cascade', domain=[('deprecated', '=', False)]) label = fields.Char(string='Journal Item Label') amount_type = fields.Selection([ ('fixed', 'Fixed'), ('percentage', 'Percentage of balance'), ('regex', 'From label'), - ], required=True, default='percentage') - amount = fields.Float(string='Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.") - amount_from_label_regex = fields.Char(string="Amount from Label (regex)", default=r"([\d\.,]+)") - decimal_separator = fields.Char(help="Every character that is nor a digit nor this separator will be removed from the matching string") - force_tax_included = fields.Boolean(string='Tax Included in Price', - help='Force the tax to be managed as a price included tax.') - # Second part fields. - has_second_line = fields.Boolean(string='Add a second line', default=False) + ], required=True, default='percentage') + amount_string = fields.Char(string="Amount") + force_tax_included = fields.Boolean(string='Tax Included in Price', help='Force the tax to be managed as a price included tax.') tax_ids = fields.Many2many('account.tax.template', string='Taxes', ondelete='restrict') - second_account_id = fields.Many2one('account.account.template', string='Second Account', ondelete='cascade', domain=[('deprecated', '=', False)]) - second_label = fields.Char(string='Second Journal Item Label') - second_amount_type = fields.Selection([ - ('fixed', 'Fixed'), - ('percentage', 'Percentage of amount'), - ('regex', 'From label'), - ], string="Second Amount type",required=True, default='percentage') - second_amount = fields.Float(string='Second Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.") - second_amount_from_label_regex = fields.Char(string="Second Amount from Label (regex)", default=r"([\d\.,]+)") - force_second_tax_included = fields.Boolean(string='Second Tax Included in Price', - help='Force the second tax to be managed as a price included tax.') - second_tax_ids = fields.Many2many('account.tax.template', relation='account_reconcile_model_tmpl_account_tax_bis_rel', string='Second Taxes', ondelete='restrict') diff --git a/addons/account/security/account_security.xml b/addons/account/security/account_security.xml index c665789497f..7b67561fc6d 100644 --- a/addons/account/security/account_security.xml +++ b/addons/account/security/account_security.xml @@ -180,6 +180,13 @@ ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + Account reconcile model_line template company rule + + + ['|',('company_id','=',False),('company_id', 'in', company_ids)] + + Account payment company rule diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv index 5e43dbc88a0..58ecc502f4f 100644 --- a/addons/account/security/ir.model.access.csv +++ b/addons/account/security/ir.model.access.csv @@ -64,7 +64,9 @@ access_account_account_tax,account.account.tag,model_account_account_tag,account access_account_account_tax_user,account.account.tag,model_account_account_tag,account.group_account_invoice,1,0,0,0 access_account_reconcile_model_billing,account.reconcile.model.billing,model_account_reconcile_model,account.group_account_invoice,1,0,1,0 access_account_reconcile_model,account.reconcile.model,model_account_reconcile_model,account.group_account_user,1,1,1,1 -access_account_reconcile_model_template,account.reconcile.model.template,model_account_reconcile_model_template,account.group_account_invoice,1,1,1,1 +access_account_reconcile_model_template,account.reconcile.model.template,model_account_reconcile_model_template,account.group_account_manager,1,1,1,1 +access_account_reconcile_model_line,account.reconcile.model.line,model_account_reconcile_model_line,account.group_account_user,1,1,1,1 +access_account_reconcile_model_line_template,account.reconcile.model.line.template,model_account_reconcile_model_line_template,account.group_account_manager,1,1,1,1 access_account_partial_reconcile_group_invoice,account.partial.reconcile.group.invoice,model_account_partial_reconcile,account.group_account_invoice,1,1,1,1 access_account_partial_reconcile,account.partial.reconcile,model_account_partial_reconcile,account.group_account_user,1,1,1,1 access_account_full_reconcile_group_invoice,account.full.reconcile.group.invoice,model_account_full_reconcile,account.group_account_invoice,1,1,1,1 diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index 7ef983ae4d1..07f56b2ae7c 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -45,7 +45,7 @@ class TestReconciliationMatchingRules(AccountTestCommon): }) cls.rule_1 = cls.rule_0.copy() - cls.rule_1.account_id = current_assets_account + cls.rule_1.write({'line_ids': [(0, 0, {'account_id': current_assets_account.id})]}) cls.rule_1.match_partner = True cls.rule_1.match_partner_ids |= cls.partner_1 + cls.partner_2 cls.rule_2 = cls.env['account.reconcile.model'].create({ @@ -53,7 +53,7 @@ class TestReconciliationMatchingRules(AccountTestCommon): 'rule_type': 'writeoff_suggestion', 'match_partner': True, 'match_partner_ids': [], - 'account_id': current_assets_account.id, + 'line_ids': [(0, 0, {'account_id': current_assets_account.id})], }) invoice_number = cls.invoice_line_1.move_id.name @@ -67,14 +67,14 @@ class TestReconciliationMatchingRules(AccountTestCommon): 'statement_id': cls.bank_st.id, 'name': 'invoice %s-%s' % (invoice_number.split('/')[1], invoice_number.split('/')[2]), 'partner_id': cls.partner_1.id, - 'amount': 100, + 'amount': '100', 'sequence': 1, }) cls.bank_line_2 = cls.env['account.bank.statement.line'].create({ 'statement_id': cls.bank_st.id, 'name': 'xxxxx', 'partner_id': cls.partner_1.id, - 'amount': 600, + 'amount': '600', 'sequence': 2, }) @@ -86,14 +86,14 @@ class TestReconciliationMatchingRules(AccountTestCommon): 'statement_id': cls.cash_st.id, 'name': 'yyyyy', 'partner_id': cls.partner_2.id, - 'amount': -1000, + 'amount': '-1000', 'sequence': 1, }) cls.tax21 = cls.env['account.tax'].create({ 'name': '21%', 'type_tax_use': 'purchase', - 'amount': 21, + 'amount': '21', }) @classmethod @@ -338,9 +338,11 @@ class TestReconciliationMatchingRules(AccountTestCommon): self.rule_1.write({ 'auto_reconcile': True, - 'force_tax_included': True, - 'tax_ids': [(6, 0, self.tax21.ids)], 'rule_type': 'writeoff_suggestion', + 'line_ids': [(1, self.rule_1.line_ids.id, { + 'force_tax_included': True, + 'tax_ids': [(6, 0, self.tax21.ids)], + })] }) self.bank_line_2.unlink() diff --git a/addons/account/tests/test_templates_consistency.py b/addons/account/tests/test_templates_consistency.py index f91599cd552..40a89d8a124 100644 --- a/addons/account/tests/test_templates_consistency.py +++ b/addons/account/tests/test_templates_consistency.py @@ -61,7 +61,10 @@ class AccountingTestTemplConsistency(TransactionCase): '''Test fields consistency for ('account.reconcile.model', 'account.reconcile.model.template') ''' self.check_fields_consistency('account.reconcile.model.template', 'account.reconcile.model', exceptions=['chart_template_id']) - self.check_fields_consistency('account.reconcile.model', 'account.reconcile.model.template', exceptions=['company_id', 'journal_id', 'analytic_account_id', 'second_journal_id', 'second_analytic_account_id', 'analytic_tag_ids', 'second_analytic_tag_ids']) + self.check_fields_consistency('account.reconcile.model', 'account.reconcile.model.template', exceptions=['company_id']) + # lines + self.check_fields_consistency('account.reconcile.model.line.template', 'account.reconcile.model.line', exceptions=['chart_template_id']) + self.check_fields_consistency('account.reconcile.model.line', 'account.reconcile.model.line.template', exceptions=['company_id', 'journal_id', 'analytic_account_id', 'analytic_tag_ids', 'amount']) def test_account_group_fields(self): '''Test fields consistency for ('account.group', 'account.group.template') diff --git a/addons/account/views/account_journal_dashboard_view.xml b/addons/account/views/account_journal_dashboard_view.xml index 8b5623ceebf..7fc2b3d27af 100644 --- a/addons/account/views/account_journal_dashboard_view.xml +++ b/addons/account/views/account_journal_dashboard_view.xml @@ -103,7 +103,7 @@ Reconciliation
- Reconciliation Models + Reconciliation Models
diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 8b041624cb2..0968754104d 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -802,6 +802,7 @@ action = model.setting_init_bank_account_action() + @@ -882,72 +883,68 @@ action = model.setting_init_bank_account_action() - - - - - - - - - - - - - - -
- -
- - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
+ + account.reconcile.model.line.form + account.reconcile.model.line + +
+ + + + + + + + + + + + + + + + + + + + + +
account.reconcile.model.tree account.reconcile.model @@ -955,9 +952,8 @@ action = model.setting_init_bank_account_action() - - - + + @@ -966,9 +962,9 @@ action = model.setting_init_bank_account_action() account.reconcile.model - - - + + + diff --git a/addons/l10n_be/data/account_reconcile_model_template.xml b/addons/l10n_be/data/account_reconcile_model_template.xml index d2417090926..2d1ecee80d3 100644 --- a/addons/l10n_be/data/account_reconcile_model_template.xml +++ b/addons/l10n_be/data/account_reconcile_model_template.xml @@ -3,44 +3,59 @@ Escompte + + + percentage - 100 + 100 Escompte accordé Frais bancaires HTVA + + + percentage - 100 + 100 Frais bancaires HTVA Frais bancaires TVA21 + + + percentage - 100 + 100 Frais bancaires TVA21 - Virements internes - percentage - 100 - Virements internes + + + + percentage + 100 + Virements internes + - Compte Attente - percentage - 100 - + + + + percentage + 100 + + diff --git a/addons/l10n_de_skr03/data/account_reconcile_model_template.xml b/addons/l10n_de_skr03/data/account_reconcile_model_template.xml index 779b5d3a776..e25ce0c1a75 100644 --- a/addons/l10n_de_skr03/data/account_reconcile_model_template.xml +++ b/addons/l10n_de_skr03/data/account_reconcile_model_template.xml @@ -3,57 +3,75 @@ Skonto-EK-7% + + + + percentage - 100 + 100 Skonto-EK-7% - Skonto-EK-19% + + + + percentage - 100 + 100 Skonto-EK-19% - Skonto-VK-7% + + + + percentage - 100 + 100 Skonto-VK-7% - Skonto-VK-19% + + + + percentage - 100 + 100 Skonto-VK-19% - Forderungsverlust-7% + + + + percentage - 100 + 100 Forderungsverlust-7% - Forderungsverlust-19% + + + + percentage - 100 + 100 Forderungsverlust-19% - - \ No newline at end of file + diff --git a/addons/l10n_de_skr04/data/account_reconcile_model_template.xml b/addons/l10n_de_skr04/data/account_reconcile_model_template.xml index 09025543fad..3f672eb180a 100644 --- a/addons/l10n_de_skr04/data/account_reconcile_model_template.xml +++ b/addons/l10n_de_skr04/data/account_reconcile_model_template.xml @@ -3,57 +3,75 @@ Skonto-EK-7% + + + + percentage - 100 + 100 Skonto-EK-7% - Skonto-EK-19% + + + + percentage - 100 + 100 Skonto-EK-19% - Skonto-VK-7% + + + + percentage - 100 + 100 Skonto-VK-7% - Skonto-VK-19% + + + + percentage - 100 + 100 Skonto-VK-19% - Forderungsverlust-7% + + + + percentage - 100 + 100 Forderungsverlust-7% - Forderungsverlust-19% + + + + percentage - 100 + 100 Forderungsverlust-19% - - \ No newline at end of file + diff --git a/addons/l10n_fr/data/account_reconcile_model_template.xml b/addons/l10n_fr/data/account_reconcile_model_template.xml index d098a0c1c2d..edee1e908eb 100644 --- a/addons/l10n_fr/data/account_reconcile_model_template.xml +++ b/addons/l10n_fr/data/account_reconcile_model_template.xml @@ -6,8 +6,11 @@ Frais bancaires + + + percentage - 100 + 100 diff --git a/addons/l10n_generic_coa/demo/account_reconcile_model.xml b/addons/l10n_generic_coa/demo/account_reconcile_model.xml index 3be9c3a1bde..5934fdd0ebc 100644 --- a/addons/l10n_generic_coa/demo/account_reconcile_model.xml +++ b/addons/l10n_generic_coa/demo/account_reconcile_model.xml @@ -6,20 +6,29 @@ writeoff_suggestion contains BRT + , + + + + + 1 Due amount regex - BRT: ([\d,]+) - , - - Bank Fees - BRT: ([\d,]+) + + + + + 2 + Bank Fees + - percentage - 100 + percentage + 100 diff --git a/addons/l10n_lu/data/account_reconcile_model_template_data.xml b/addons/l10n_lu/data/account_reconcile_model_template_data.xml index c0762c77139..2aa33c598b4 100644 --- a/addons/l10n_lu/data/account_reconcile_model_template_data.xml +++ b/addons/l10n_lu/data/account_reconcile_model_template_data.xml @@ -3,19 +3,25 @@ Bank Fees + writeoff_button + + + percentage - 100 + 100 Bank Fees - writeoff_button Cash Discount - - percentage - 100 - Cash Discount writeoff_button + + + + percentage + 100 + Cash Discount + diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index ed0bcc3e8c8..61ecb3af1da 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -2756,6 +2756,13 @@ var FieldSelection = AbstractField.extend({ var required = this.attrs.modifiersValue && this.attrs.modifiersValue.required; for (var i = 0 ; i < this.values.length ; i++) { var disabled = required && this.values[i][0] === false; + console.log(this.values); + console.log(i); + console.log(this.values[i]) + // console.log(this.values[i][0]) + if (this.values[i] == undefined) { + debugger + } this.$el.append($('