diff --git a/addons/account/models/account.py b/addons/account/models/account.py index ec97bafd1c6..f42268edd70 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -481,7 +481,7 @@ class AccountJournal(models.Model): post_at_bank_rec = fields.Boolean(string="Post At Bank Reconciliation", help="Whether or not the payments made in this journal should be generated in draft state, so that the related journal entries are only posted when performing bank reconciliation.") # alias configuration for 'purchase' type journals - alias_id = fields.Many2one('mail.alias', string='Alias') + alias_id = fields.Many2one('mail.alias', string='Alias', copy=False) alias_domain = fields.Char('Alias domain', compute='_compute_alias_domain', default=lambda self: self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")) alias_name = fields.Char('Alias Name for Vendor Bills', related='alias_id.alias_name', help="It creates draft vendor bill by sending an email.", readonly=False) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index d0632970bed..d22962ebbd0 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -587,8 +587,11 @@ class AccountBankStatementLine(models.Model): # Fully reconciled moves are just linked to the bank statement total = self.amount + currency = self.currency_id or statement_currency for aml_rec in payment_aml_rec: - total -= aml_rec.debit - aml_rec.credit + balance = aml_rec.amount_currency if aml_rec.currency_id else aml_rec.balance + aml_currency = aml_rec.currency_id or aml_rec.company_currency_id + total -= aml_currency._convert(balance, currency, aml_rec.company_id, aml_rec.date) aml_rec.with_context(check_move_validity=False).write({'statement_line_id': self.id}) counterpart_moves = (counterpart_moves | aml_rec.move_id) if aml_rec.journal_id.post_at_bank_rec and aml_rec.payment_id and aml_rec.move_id.state == 'draft': diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6d4ef94ddd9..1d1483b2335 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -384,18 +384,20 @@ class AccountMove(models.Model): @api.multi def _reverse_move(self, date=None, journal_id=None, auto=False): self.ensure_one() - reversed_move = self.copy(default={ - 'date': date, - 'journal_id': journal_id.id if journal_id else self.journal_id.id, - 'ref': (_('Automatic reversal of: %s') if auto else _('Reversal of: %s')) % (self.name), - 'auto_reverse': False}) - for acm_line in reversed_move.line_ids.with_context(check_move_validity=False): - acm_line.write({ - 'debit': acm_line.credit, - 'credit': acm_line.debit, - 'amount_currency': -acm_line.amount_currency - }) - self.reverse_entry_id = reversed_move + with self.env.norecompute(): + reversed_move = self.copy(default={ + 'date': date, + 'journal_id': journal_id.id if journal_id else self.journal_id.id, + 'ref': (_('Automatic reversal of: %s') if auto else _('Reversal of: %s')) % (self.name), + 'auto_reverse': False}) + for acm_line in reversed_move.line_ids.with_context(check_move_validity=False): + acm_line.write({ + 'debit': acm_line.credit, + 'credit': acm_line.debit, + 'amount_currency': -acm_line.amount_currency + }) + self.reverse_entry_id = reversed_move + self.recompute() return reversed_move @api.multi @@ -524,7 +526,7 @@ class AccountMoveLine(models.Model): #computing the `reconciled` field. reconciled = False digits_rounding_precision = line.company_id.currency_id.rounding - if float_is_zero(amount, precision_rounding=digits_rounding_precision): + if (line.matched_debit_ids or line.matched_credit_ids) and float_is_zero(amount, precision_rounding=digits_rounding_precision): if line.currency_id and line.amount_currency: if float_is_zero(amount_residual_currency, precision_rounding=line.currency_id.rounding): reconciled = True @@ -905,7 +907,7 @@ class AccountMoveLine(models.Model): for line in self: company_ids.add(line.company_id.id) all_accounts.append(line.account_id) - if line.reconciled: + if (line.matched_debit_ids or line.matched_credit_ids) and line.reconciled: raise UserError(_('You are trying to reconcile some entries that are already reconciled.')) if len(company_ids) > 1: raise UserError(_('To reconcile the entries company should be the same for all entries.')) @@ -1053,6 +1055,56 @@ class AccountMoveLine(models.Model): ) return rec_move_ids.unlink() + def _apply_taxes(self, vals, amount): + tax_lines_vals = [] + # Get ids from triplets : https://www.odoo.com/documentation/10.0/reference/orm.html#odoo.models.Model.write + tax_ids = [tax['id'] for tax in self.resolve_2many_commands('tax_ids', vals['tax_ids']) if tax.get('id')] + # Since create() receives ids instead of recordset, let's just use the old-api bridge + taxes = self.env['account.tax'].browse(tax_ids) + currency = self.env['res.currency'].browse(vals.get('currency_id')) + partner = self.env['res.partner'].browse(vals.get('partner_id')) + ctx = dict(self._context) + ctx['round'] = ctx.get('round', True) + res = taxes.with_context(ctx).compute_all(amount, + currency, 1, vals.get('product_id'), partner) + # Adjust line amount if any tax is price_include + if abs(res['total_excluded']) < abs(amount): + if vals['debit'] != 0.0: vals['debit'] = res['total_excluded'] + if vals['credit'] != 0.0: vals['credit'] = -res['total_excluded'] + if vals.get('amount_currency'): + vals['amount_currency'] = self.env['res.currency'].browse(vals['currency_id']).round(vals['amount_currency'] * (res['total_excluded']/amount)) + # Create tax lines + for tax_vals in res['taxes']: + if tax_vals['amount']: + tax = self.env['account.tax'].browse([tax_vals['id']]) + account_id = (amount > 0 and tax_vals['account_id'] or tax_vals['refund_account_id']) + if not account_id: account_id = vals['account_id'] + temp = { + 'account_id': account_id, + 'name': vals['name'] + ' ' + tax_vals['name'], + 'tax_line_id': tax_vals['id'], + 'move_id': vals['move_id'], + 'partner_id': vals.get('partner_id'), + 'statement_id': vals.get('statement_id'), + 'debit': tax_vals['amount'] > 0 and tax_vals['amount'] or 0.0, + 'credit': tax_vals['amount'] < 0 and -tax_vals['amount'] or 0.0, + 'analytic_account_id': vals.get('analytic_account_id') if tax.analytic else False, + } + bank = self.env["account.bank.statement.line"].browse(vals.get('statement_line_id')).statement_id + if bank.currency_id != bank.company_id.currency_id: + ctx = {} + if 'date' in vals: + ctx['date'] = vals['date'] + elif 'date_maturity' in vals: + ctx['date'] = vals['date_maturity'] + temp['currency_id'] = bank.currency_id.id + temp['amount_currency'] = bank.company_id.currency_id.with_context(ctx).compute(tax_vals['amount'], bank.currency_id, round=True) + if vals.get('tax_exigible'): + temp['tax_exigible'] = True + temp['account_id'] = tax.cash_basis_account.id or account_id + tax_lines_vals.append(temp) + return tax_lines_vals + #################################################### # CRUD methods #################################################### @@ -1486,90 +1538,91 @@ class AccountPartialReconcile(models.Model): self.ensure_one() move_date = self.debit_move_id.date newly_created_move = self.env['account.move'] - for move in (self.debit_move_id.move_id, self.credit_move_id.move_id): - #move_date is the max of the 2 reconciled items - if move_date < move.date: - move_date = move.date - percentage_before = percentage_before_rec[move.id] - percentage_after = move.line_ids[0]._get_matched_percentage()[move.id] - # update the percentage before as the move can be part of - # multiple partial reconciliations - percentage_before_rec[move.id] = percentage_after + with self.env.norecompute(): + for move in (self.debit_move_id.move_id, self.credit_move_id.move_id): + #move_date is the max of the 2 reconciled items + if move_date < move.date: + move_date = move.date + percentage_before = percentage_before_rec[move.id] + percentage_after = move.line_ids[0]._get_matched_percentage()[move.id] + # update the percentage before as the move can be part of + # multiple partial reconciliations + percentage_before_rec[move.id] = percentage_after - for line in move.line_ids: - if not line.tax_exigible: - #amount is the current cash_basis amount minus the one before the reconciliation - amount = line.balance * percentage_after - line.balance * percentage_before - rounded_amt = self._get_amount_tax_cash_basis(amount, line) - if float_is_zero(rounded_amt, precision_rounding=line.company_id.currency_id.rounding): - continue - if line.tax_line_id and line.tax_line_id.tax_exigibility == 'on_payment': - if not newly_created_move: - newly_created_move = self._create_tax_basis_move() - #create cash basis entry for the tax line - to_clear_aml = self.env['account.move.line'].with_context(check_move_validity=False).create({ - 'name': line.move_id.name, - 'debit': abs(rounded_amt) if rounded_amt < 0 else 0.0, - 'credit': rounded_amt if rounded_amt > 0 else 0.0, - 'account_id': line.account_id.id, - 'analytic_account_id': line.analytic_account_id.id, - 'analytic_tag_ids': line.analytic_tag_ids.ids, - 'tax_exigible': True, - 'amount_currency': line.amount_currency and line.currency_id.round(-line.amount_currency * amount / line.balance) or 0.0, - 'currency_id': line.currency_id.id, - 'move_id': newly_created_move.id, - 'partner_id': line.partner_id.id, - }) - # Group by cash basis account and tax - self.env['account.move.line'].with_context(check_move_validity=False).create({ - 'name': line.name, - 'debit': rounded_amt if rounded_amt > 0 else 0.0, - 'credit': abs(rounded_amt) if rounded_amt < 0 else 0.0, - 'account_id': line.tax_line_id.cash_basis_account_id.id, - 'analytic_account_id': line.analytic_account_id.id, - 'analytic_tag_ids': line.analytic_tag_ids.ids, - 'tax_line_id': line.tax_line_id.id, - 'tax_exigible': True, - 'amount_currency': line.amount_currency and line.currency_id.round(line.amount_currency * amount / line.balance) or 0.0, - 'currency_id': line.currency_id.id, - 'move_id': newly_created_move.id, - 'partner_id': line.partner_id.id, - }) - if line.account_id.reconcile: - #setting the account to allow reconciliation will help to fix rounding errors - to_clear_aml |= line - to_clear_aml.reconcile() - - if any([tax.tax_exigibility == 'on_payment' for tax in line.tax_ids]): - if not newly_created_move: - newly_created_move = self._create_tax_basis_move() - #create cash basis entry for the base - for tax in line.tax_ids.filtered(lambda t: t.tax_exigibility == 'on_payment'): - account_id = self._get_tax_cash_basis_base_account(line, tax) - self.env['account.move.line'].with_context(check_move_validity=False).create({ - 'name': line.name, - 'debit': rounded_amt > 0 and rounded_amt or 0.0, - 'credit': rounded_amt < 0 and abs(rounded_amt) or 0.0, - 'account_id': account_id.id, + for line in move.line_ids: + if not line.tax_exigible: + #amount is the current cash_basis amount minus the one before the reconciliation + amount = line.balance * percentage_after - line.balance * percentage_before + rounded_amt = self._get_amount_tax_cash_basis(amount, line) + if float_is_zero(rounded_amt, precision_rounding=line.company_id.currency_id.rounding): + continue + if line.tax_line_id and line.tax_line_id.tax_exigibility == 'on_payment': + if not newly_created_move: + newly_created_move = self._create_tax_basis_move() + #create cash basis entry for the tax line + to_clear_aml = self.env['account.move.line'].with_context(check_move_validity=False).create({ + 'name': line.move_id.name, + 'debit': abs(rounded_amt) if rounded_amt < 0 else 0.0, + 'credit': rounded_amt if rounded_amt > 0 else 0.0, + 'account_id': line.account_id.id, + 'analytic_account_id': line.analytic_account_id.id, + 'analytic_tag_ids': line.analytic_tag_ids.ids, 'tax_exigible': True, - 'tax_ids': [(6, 0, [tax.id])], - 'move_id': newly_created_move.id, + 'amount_currency': line.amount_currency and line.currency_id.round(-line.amount_currency * amount / line.balance) or 0.0, 'currency_id': line.currency_id.id, - 'amount_currency': self.amount_currency and line.currency_id.round(line.amount_currency * amount / line.balance) or 0.0, + 'move_id': newly_created_move.id, 'partner_id': line.partner_id.id, }) + # Group by cash basis account and tax self.env['account.move.line'].with_context(check_move_validity=False).create({ 'name': line.name, - 'credit': rounded_amt > 0 and rounded_amt or 0.0, - 'debit': rounded_amt < 0 and abs(rounded_amt) or 0.0, - 'account_id': account_id.id, + 'debit': rounded_amt if rounded_amt > 0 else 0.0, + 'credit': abs(rounded_amt) if rounded_amt < 0 else 0.0, + 'account_id': line.tax_line_id.cash_basis_account_id.id, + 'analytic_account_id': line.analytic_account_id.id, + 'analytic_tag_ids': line.analytic_tag_ids.ids, + 'tax_line_id': line.tax_line_id.id, 'tax_exigible': True, - 'move_id': newly_created_move.id, + 'amount_currency': line.amount_currency and line.currency_id.round(line.amount_currency * amount / line.balance) or 0.0, 'currency_id': line.currency_id.id, - 'amount_currency': self.amount_currency and line.currency_id.round(-line.amount_currency * amount / line.balance) or 0.0, + 'move_id': newly_created_move.id, 'partner_id': line.partner_id.id, }) + if line.account_id.reconcile: + #setting the account to allow reconciliation will help to fix rounding errors + to_clear_aml |= line + to_clear_aml.reconcile() + if any([tax.tax_exigibility == 'on_payment' for tax in line.tax_ids]): + if not newly_created_move: + newly_created_move = self._create_tax_basis_move() + #create cash basis entry for the base + for tax in line.tax_ids.filtered(lambda t: t.tax_exigibility == 'on_payment'): + account_id = self._get_tax_cash_basis_base_account(line, tax) + self.env['account.move.line'].with_context(check_move_validity=False).create({ + 'name': line.name, + 'debit': rounded_amt > 0 and rounded_amt or 0.0, + 'credit': rounded_amt < 0 and abs(rounded_amt) or 0.0, + 'account_id': account_id.id, + 'tax_exigible': True, + 'tax_ids': [(6, 0, [tax.id])], + 'move_id': newly_created_move.id, + 'currency_id': line.currency_id.id, + 'amount_currency': self.amount_currency and line.currency_id.round(line.amount_currency * amount / line.balance) or 0.0, + 'partner_id': line.partner_id.id, + }) + self.env['account.move.line'].with_context(check_move_validity=False).create({ + 'name': line.name, + 'credit': rounded_amt > 0 and rounded_amt or 0.0, + 'debit': rounded_amt < 0 and abs(rounded_amt) or 0.0, + 'account_id': account_id.id, + 'tax_exigible': True, + 'move_id': newly_created_move.id, + 'currency_id': line.currency_id.id, + 'amount_currency': self.amount_currency and line.currency_id.round(-line.amount_currency * amount / line.balance) or 0.0, + 'partner_id': line.partner_id.id, + }) + self.recompute() if newly_created_move: if move_date > (self.company_id.period_lock_date or date.min) and newly_created_move.date != move_date: # The move date should be the maximum date between payment and invoice (in case diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index bb2e7ff4f03..7dffbaa2233 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -211,6 +211,8 @@ class account_abstract_payment(models.AbstractModel): self.amount = abs(self._compute_payment_amount()) # Set by default the first liquidity journal having this currency if exists. + if self.journal_id: + return journal = self.env['account.journal'].search( [('type', 'in', ('bank', 'cash')), ('currency_id', '=', self.currency_id.id)], limit=1) if journal: diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 717b99ad26d..bfbab8809ca 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -173,7 +173,7 @@ class AccountChartTemplate(models.Model): # (won't work well for multi-company) company = self.env.user.company_id # If we don't have any chart of account on this company, install this chart of account - if not self.existing_accounting(company): + if not company.chart_template_id and not self.existing_accounting(company): self.load_for_current_company(15.0, 15.0) def load_for_current_company(self, sale_tax_rate, purchase_tax_rate): diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv index ef09176438b..a091adbd8b8 100644 --- a/addons/account/security/ir.model.access.csv +++ b/addons/account/security/ir.model.access.csv @@ -68,7 +68,7 @@ access_account_account_type_invoice,account.account.type invoice,model_account_a access_account_account_tax,account.account.tag,model_account_account_tag,account.group_account_user,1,1,1,1 access_account_account_tax_user,account.account.tag,model_account_account_tag,account.group_account_invoice,1,0,0,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_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_partial_reconcile_group_invoice,account.partial.reconcile.group.invoice,model_account_partial_reconcile,account.group_account_invoice,1,1,1,0 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,0 diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index 06387df0579..d948895bda4 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -904,11 +904,11 @@ var StatementModel = BasicModel.extend({ }); var company_currency = session.get_currency(line.st_line.currency_id); var company_precision = company_currency && company_currency.digits[1] || 2; - total = utils.round_decimals(total*1000, company_precision)/1000 || 0; + total = utils.round_decimals(total, company_precision) || 0; if(isOtherCurrencyId){ var other_currency = session.get_currency(isOtherCurrencyId); var other_precision = other_currency && other_currency.digits[1] || 2; - amount_currency = utils.round_decimals(amount_currency, other_precision) + amount_currency = utils.round_decimals(amount_currency, other_precision); } line.balance = { amount: total, diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js index b5e97566936..cbc5b8bdcd6 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js @@ -260,7 +260,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { 'click .accounting_view thead td': '_onTogglePanel', 'click .accounting_view tfoot td:not(.cell_left,.cell_right)': '_onShowPanel', 'click .cell': '_onEditAmount', - 'input input.filter': '_onFilterChange', + 'change input.filter': '_onFilterChange', 'click .match .load-more a': '_onLoadMore', 'click .match .mv_line td': '_onSelectMoveLine', 'click .accounting_view tbody .mv_line td': '_onSelectProposition', diff --git a/addons/account/static/src/xml/account_reconciliation.xml b/addons/account/static/src/xml/account_reconciliation.xml index d07ea5a6e60..c8cd06d258e 100644 --- a/addons/account/static/src/xml/account_reconciliation.xml +++ b/addons/account/static/src/xml/account_reconciliation.xml @@ -144,7 +144,8 @@