summaryrefslogtreecommitdiff
path: root/addons/account/wizard
diff options
context:
space:
mode:
authorwilliam <wan@odoo.com>2020-03-30 11:46:44 +0000
committerwilliam <wan@odoo.com>2020-08-05 11:57:10 +0000
commit0ea9254c81ea42a7fd9af455f05d70e3ca227460 (patch)
tree507ce2017e7ecb77e592107d918a6a77ddb160ab /addons/account/wizard
parent82dc0cb7b91ae59beae7e1c865b670afc5958b31 (diff)
[IMP] account: fusion wizards for automatic entries
Task 2227389 The wizards for creating Accrual Entries and Transfer Entries are quite similar. We are merging them as they share code and business logic. Entries in the future should not be posted for both wizards, but set to be auto posted instead.
Diffstat (limited to 'addons/account/wizard')
-rw-r--r--addons/account/wizard/__init__.py3
-rw-r--r--addons/account/wizard/account_accrual_accounting.py248
-rw-r--r--addons/account/wizard/account_accrual_accounting_view.xml42
-rw-r--r--addons/account/wizard/account_automatic_entry_wizard.py398
-rw-r--r--addons/account/wizard/account_automatic_entry_wizard_views.xml55
-rw-r--r--addons/account/wizard/account_transfer_wizard.py195
-rw-r--r--addons/account/wizard/account_transfer_wizard.xml41
7 files changed, 454 insertions, 528 deletions
diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py
index a130d327938..b88c746d3f5 100644
--- a/addons/account/wizard/__init__.py
+++ b/addons/account/wizard/__init__.py
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from . import account_accrual_accounting
+from . import account_automatic_entry_wizard
from . import account_unreconcile
from . import account_validate_account_move
from . import pos_box
@@ -15,5 +15,4 @@ from . import setup_wizards
from . import wizard_tax_adjustments
from . import account_invoice_send
from . import base_document_layout
-from . import account_transfer_wizard
from . import account_payment_register
diff --git a/addons/account/wizard/account_accrual_accounting.py b/addons/account/wizard/account_accrual_accounting.py
deleted file mode 100644
index 2f22ac54e11..00000000000
--- a/addons/account/wizard/account_accrual_accounting.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# -*- coding: utf-8 -*-
-from odoo import api, fields, models, _
-from odoo.exceptions import UserError
-from odoo.tools.misc import format_date
-
-import json
-
-class AccrualAccountingWizard(models.TransientModel):
- _name = 'account.accrual.accounting.wizard'
- _description = 'Create accrual entries.'
-
- date = fields.Date(required=True)
- company_id = fields.Many2one('res.company', required=True, readonly=True)
- account_type = fields.Selection([('income', 'Revenue'), ('expense', 'Expense')])
- active_move_line_ids = fields.Many2many('account.move.line')
- journal_id = fields.Many2one('account.journal', required=True, readonly=False,
- domain="[('company_id', '=', company_id), ('type', '=', 'general')]",
- related="company_id.accrual_default_journal_id")
- expense_accrual_account = fields.Many2one('account.account', readonly=False,
- domain="[('company_id', '=', company_id), ('internal_type', 'not in', ('receivable', 'payable')), ('internal_group', '=', 'liability'), ('reconcile', '=', True)]",
- related="company_id.expense_accrual_account_id")
- revenue_accrual_account = fields.Many2one('account.account', readonly=False,
- domain="[('company_id', '=', company_id), ('internal_type', 'not in', ('receivable', 'payable')), ('internal_group', '=', 'asset'), ('reconcile', '=', True)]",
- related="company_id.revenue_accrual_account_id")
- percentage = fields.Float("Percentage", default=100.0)
- total_amount = fields.Monetary(compute="_compute_total_amount", currency_field='company_currency_id')
- company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id')
- data = fields.Text(compute="_compute_data")
- preview_data = fields.Text(compute="_compute_preview_data")
-
- @api.constrains('percentage')
- def _constraint_percentage(self):
- for record in self:
- if not (0.0 < record.percentage <= 100.0):
- raise UserError(_("Percentage must be between 0 and 100"))
-
- @api.depends('percentage', 'active_move_line_ids')
- def _compute_total_amount(self):
- for record in self:
- record.total_amount = sum(record.active_move_line_ids.mapped(lambda l: record.percentage * (l.debit + l.credit) / 100))
-
- @api.model
- def default_get(self, fields):
- if self.env.context.get('active_model') != 'account.move.line' or not self.env.context.get('active_ids'):
- raise UserError(_('This can only be used on journal items'))
- rec = super(AccrualAccountingWizard, self).default_get(fields)
- if not set(fields) & set(['active_move_line_ids', 'company_id', 'account_type']):
- return super().default_get(fields)
- active_move_line_ids = self.env['account.move.line'].browse(self.env.context['active_ids'])
- rec['active_move_line_ids'] = active_move_line_ids.ids
-
- if any(move.state != 'posted' for move in active_move_line_ids.mapped('move_id')):
- raise UserError(_('You can only change the period for posted journal items.'))
- if any(move_line.reconciled for move_line in active_move_line_ids):
- raise UserError(_('You can only change the period for items that are not yet reconciled.'))
- if any(line.account_id.user_type_id != active_move_line_ids[0].account_id.user_type_id for line in active_move_line_ids):
- raise UserError(_('All accounts on the lines must be from the same type.'))
- if any(line.company_id != active_move_line_ids[0].company_id for line in active_move_line_ids):
- raise UserError(_('All lines must be from the same company.'))
- rec['company_id'] = active_move_line_ids[0].company_id.id
- account_types_allowed = self.env.ref('account.data_account_type_expenses') + self.env.ref('account.data_account_type_revenue') + self.env.ref('account.data_account_type_other_income')
- if active_move_line_ids[0].account_id.user_type_id not in account_types_allowed:
- raise UserError(_('You can only change the period for items in these types of accounts: %s') % ", ".join(account_types_allowed.mapped('name')))
- rec['account_type'] = active_move_line_ids[0].account_id.user_type_id.internal_group
- return rec
-
- @api.depends('active_move_line_ids', 'journal_id', 'revenue_accrual_account', 'expense_accrual_account', 'percentage', 'date', 'account_type')
- def _compute_data(self):
- for record in self:
- # set the accrual account on the selected journal items
- accrual_account = record.revenue_accrual_account if record.account_type == 'income' else record.expense_accrual_account
-
- move_data = {}
-
- # compute the account.move.lines and the total amount per move
- for aml in record.active_move_line_ids:
- if aml.move_id not in move_data:
- move_data[aml.move_id] = {
- 'total_amount': 0,
- 'move_vals': {
- 'new_date': {'line_ids': []},
- 'original_date': {'line_ids': []},
- }
- }
- # total amount per move is used to build the account.move references and chatter messages
- move_data[aml.move_id]['total_amount'] += aml.balance
-
- # account.move.line data
- reported_debit = aml.company_id.currency_id.round((record.percentage / 100) * aml.debit)
- reported_credit = aml.company_id.currency_id.round((record.percentage / 100) * aml.credit)
- if aml.currency_id:
- reported_amount_currency = aml.currency_id.round((record.percentage / 100) * aml.amount_currency)
- else:
- reported_amount_currency = 0.0
-
- move_data[aml.move_id]['move_vals']['new_date']['line_ids'] += [
- (0, 0, {
- 'name': aml.name,
- 'debit': reported_debit,
- 'credit': reported_credit,
- 'amount_currency': reported_amount_currency,
- 'currency_id': aml.currency_id.id,
- 'account_id': aml.account_id.id,
- 'partner_id': aml.partner_id.id,
- }),
- (0, 0, {
- 'name': _('Accrual Adjusting Entry'),
- 'debit': reported_credit,
- 'credit': reported_debit,
- 'amount_currency': -reported_amount_currency,
- 'currency_id': aml.currency_id.id,
- 'account_id': accrual_account.id,
- 'partner_id': aml.partner_id.id,
- }),
- ]
- move_data[aml.move_id]['move_vals']['original_date']['line_ids'] += [
- (0, 0, {
- 'name': aml.name,
- 'debit': reported_credit,
- 'credit': reported_debit,
- 'amount_currency': -reported_amount_currency,
- 'currency_id': aml.currency_id.id,
- 'account_id': aml.account_id.id,
- 'partner_id': aml.partner_id.id,
- }),
- (0, 0, {
- 'name': _('Accrual Adjusting Entry'),
- 'debit': reported_debit,
- 'credit': reported_credit,
- 'amount_currency': reported_amount_currency,
- 'currency_id': aml.currency_id.id,
- 'account_id': accrual_account.id,
- 'partner_id': aml.partner_id.id,
- }),
- ]
-
- # complete the account.move data
- for move in record.active_move_line_ids.move_id:
- def format_strings(string):
- return string.format(
- percent=record.percentage,
- name=move.name,
- id=move.id,
- origin_amount=origin_amount,
- date=format_date(self.env, move.date),
- new_date=record.date and format_date(self.env, record.date) or _('[Not set]'),
- )
- origin_amount = abs(move_data[move]['total_amount'])
- ref1 = format_strings(_('Adjusting Entry of {name} ({percent}% of {origin_amount} recognized from {date})'))
- ref2 = format_strings(_('Adjusting Entry of {name} ({percent}% of {origin_amount} recognized on {new_date})'))
- move_data[move]['move_vals']['new_date']['ref'] = ref1
- move_data[move]['move_vals']['new_date']['date'] = fields.Date.to_string(record.date)
- move_data[move]['move_vals']['new_date']['journal_id'] = record.journal_id.id
- move_data[move]['move_vals']['original_date']['ref'] = ref2
- move_data[move]['move_vals']['original_date']['date'] = fields.Date.to_string(move.date)
- move_data[move]['move_vals']['original_date']['journal_id'] = record.journal_id.id
- move_data[move]['log_messages'] = {
- 'new_date': format_strings(
- _('Accrual Adjusting Entry')
- + ' <a href=# data-oe-model=account.move data-oe-id={id}>{name}</a>: '
- + _('{percent}% of {origin_amount} recognized from {date}')
- ),
- 'original_date': format_strings(
- _('Accrual Adjusting Entry for')
- + ' <a href=# data-oe-model=account.move data-oe-id={id}>{name}</a>: '
- + _('{percent}% of {origin_amount} recognized on {date}')
- ),
- 'origin': format_strings(
- _('Accrual Adjusting Entries have been created for this invoice')
- + ':<ul><li><a href=# data-oe-model=account.move data-oe-id=%(second_id)d>%(second_name)s</a> '
- + _('cancelling {percent}%% of {origin_amount} ')
- + '</li><li><a href=# data-oe-model=account.move data-oe-id=%(first_id)d>%(first_name)s</a> '
- + _('postponing it to {date}')
- + '</li></ul>'
- )
- }
-
- move_vals = [m for o in move_data.values() for m in o['move_vals'].values()]
- log_messages = [o['log_messages'] for o in move_data.values()]
-
- record.data = json.dumps({
- 'move_vals': move_vals,
- 'log_messages': log_messages,
- })
-
- @api.depends('data')
- def _compute_preview_data(self):
- for record in self:
- data = json.loads(record.data)
- move_vals, log_messages = (data['move_vals'], data['log_messages'])
-
- preview_vals = []
- for move in move_vals[:4]:
- preview_vals += [self.env['account.move']._move_dict_to_preview_vals(move, record.company_id.currency_id)]
-
- preview_discarded = max(0, len(move_vals) - len(preview_vals))
- preview_columns = [
- {'field': 'account_id', 'label': _('Account')},
- {'field': 'name', 'label': _('Label')},
- {'field': 'debit', 'label': _('Debit'), 'class': 'text-right text-nowrap'},
- {'field': 'credit', 'label': _('Credit'), 'class': 'text-right text-nowrap'},
- ]
-
- record.preview_data = json.dumps({
- 'groups_vals': preview_vals,
- 'options': {
- 'discarded_number': _("%d moves", preview_discarded) if preview_discarded else False,
- 'columns': preview_columns,
- },
- })
-
- def amend_entries(self):
- accrual_account = self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account
- data = json.loads(self.data)
- move_vals, log_messages = (data['move_vals'], data['log_messages'])
-
- created_moves = self.env['account.move'].create(move_vals)
- created_moves.post()
-
- # Reconcile.
- index = 0
- for move in self.active_move_line_ids.mapped('move_id'):
- accrual_moves = created_moves[index:index + 2]
-
- to_reconcile = accrual_moves.mapped('line_ids').filtered(lambda line: line.account_id == accrual_account)
- to_reconcile.reconcile()
- move.message_post(body=log_messages[index//2]['origin'] % {
- 'first_id': accrual_moves[0].id,
- 'first_name': accrual_moves[0].name,
- 'second_id': accrual_moves[1].id,
- 'second_name': accrual_moves[1].name,
- })
- accrual_moves[0].message_post(body=log_messages[index//2]['new_date'])
- accrual_moves[1].message_post(body=log_messages[index//2]['original_date'])
- index += 2
-
- # open the generated entries
- action = {
- 'name': _('Generated Entries'),
- 'domain': [('id', 'in', created_moves.ids)],
- 'res_model': 'account.move',
- 'view_mode': 'tree,form',
- 'type': 'ir.actions.act_window',
- 'views': [(self.env.ref('account.view_move_tree').id, 'tree'), (False, 'form')],
- }
- if len(created_moves) == 1:
- action.update({'view_mode': 'form', 'res_id': created_moves.id})
- return action
diff --git a/addons/account/wizard/account_accrual_accounting_view.xml b/addons/account/wizard/account_accrual_accounting_view.xml
deleted file mode 100644
index 98b88d94530..00000000000
--- a/addons/account/wizard/account_accrual_accounting_view.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
- <data>
- <record id="account_accrual_accounting_wizard_form_view" model="ir.ui.view">
- <field name="name">account.accrual.accounting.wizard.form</field>
- <field name="model">account.accrual.accounting.wizard</field>
- <field name="arch" type="xml">
- <form>
- <field name="account_type" invisible="1"/>
- <field name="company_id" invisible="1"/>
- <group>
- <group>
- <field name="date" string="Recognize on"/>
- <field name="expense_accrual_account" string="Accrued Account"
- attrs="{'invisible': [('account_type', '!=', 'expense')], 'required': [('account_type', '=', 'expense')]}"/>
- <field name="revenue_accrual_account" string="Accrued Account"
- attrs="{'invisible': [('account_type', '!=', 'income')], 'required': [('account_type', '=', 'income')]}"/>
- </group>
- <group>
- <field name="percentage" string="Percent (%)"/>
- <field name="total_amount" string="Amount"/>
- <field name="journal_id"/>
- </group>
- </group>
- <label for="preview_data" string="The following Journal Entries will be generated"/>
- <field name="preview_data" widget="grouped_view_widget"/>
- <footer>
- <button string="Create Journal Entries" name="amend_entries" type="object" class="oe_highlight"/>
- <button string="Cancel" class="btn btn-secondary" special="cancel"/>
- </footer>
- </form>
- </field>
- </record>
-
- <record id="account_accrual_accounting_wizard_action" model="ir.actions.act_window">
- <field name="name">Create Accrual Entries for the expense/revenue recognition</field>
- <field name="res_model">account.accrual.accounting.wizard</field>
- <field name="view_mode">form</field>
- <field name="target">new</field>
- </record>
- </data>
-</odoo>
diff --git a/addons/account/wizard/account_automatic_entry_wizard.py b/addons/account/wizard/account_automatic_entry_wizard.py
new file mode 100644
index 00000000000..920e209c5a5
--- /dev/null
+++ b/addons/account/wizard/account_automatic_entry_wizard.py
@@ -0,0 +1,398 @@
+# -*- coding: utf-8 -*-
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+from odoo.tools.misc import format_date, formatLang
+
+from collections import defaultdict
+from itertools import groupby
+import json
+
+class AutomaticEntryWizard(models.TransientModel):
+ _name = 'account.automatic.entry.wizard'
+ _description = 'Create Automatic Entries'
+
+ # General
+ action = fields.Selection([('change_period', 'Change Period'), ('change_account', 'Change Account')], required=True)
+ move_data = fields.Text(compute="_compute_move_data", help="JSON value of the moves to be created")
+ preview_move_data = fields.Text(compute="_compute_preview_move_data", help="JSON value of the data to be displayed in the previewer")
+ move_line_ids = fields.Many2many('account.move.line')
+ date = fields.Date(required=True, default=fields.Date.today())
+ company_id = fields.Many2one('res.company', required=True, readonly=True)
+ company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id')
+ percentage = fields.Float("Percentage", compute='_compute_percentage', readonly=False, store=True, help="Percentage of each line to execute the action on.")
+ total_amount = fields.Monetary(compute='_compute_total_amount', store=True, readonly=False, currency_field='company_currency_id', help="Total amount impacted by the automatic entry.")
+ journal_id = fields.Many2one('account.journal', required=True, readonly=False, string="Journal",
+ domain="[('company_id', '=', company_id), ('type', '=', 'general')]",
+ related="company_id.automatic_entry_default_journal_id",
+ help="Journal where to create the entry.")
+
+ # change period
+ account_type = fields.Selection([('income', 'Revenue'), ('expense', 'Expense')], compute='_compute_account_type', store=True)
+ expense_accrual_account = fields.Many2one('account.account', readonly=False,
+ domain="[('company_id', '=', company_id), ('internal_type', 'not in', ('receivable', 'payable'))]",
+ related="company_id.expense_accrual_account_id")
+ revenue_accrual_account = fields.Many2one('account.account', readonly=False,
+ domain="[('company_id', '=', company_id), ('internal_type', 'not in', ('receivable', 'payable'))]",
+ related="company_id.revenue_accrual_account_id")
+
+ # change account
+ destination_account_id = fields.Many2one(string="To", comodel_name='account.account', help="Account to transfer to.")
+ display_currency_helper = fields.Boolean(string="Currency Conversion Helper", compute='_compute_display_currency_helper', help="Technical field used to indicate whether or not to display the tooltip informing a currency conversion will be performed with the transfer")
+
+ @api.constrains('percentage', 'action')
+ def _constraint_percentage(self):
+ for record in self:
+ if not (0.0 < record.percentage <= 100.0):
+ raise UserError(_("Percentage must be between 0 and 100"))
+ if record.percentage != 100 and record.action != 'change_period':
+ print(record.percentage)
+ raise UserError(_("Percentage can only be set for Change Period method"))
+
+ @api.depends('percentage', 'move_line_ids')
+ def _compute_total_amount(self):
+ for record in self:
+ record.total_amount = (record.percentage or 100) * sum(record.move_line_ids.mapped('balance')) / 100
+
+ @api.depends('total_amount', 'move_line_ids')
+ def _compute_percentage(self):
+ for record in self:
+ record.percentage = record.total_amount / (sum(record.move_line_ids.mapped('balance')) or record.total_amount) * 100
+
+ @api.depends('move_line_ids')
+ def _compute_account_type(self):
+ for record in self:
+ record.account_type = 'income' if sum(record.move_line_ids.mapped('balance')) < 0 else 'expense'
+
+ @api.depends('destination_account_id')
+ def _compute_display_currency_helper(self):
+ for record in self:
+ record.display_currency_helper = bool(record.destination_account_id.currency_id)
+
+ @api.model
+ def default_get(self, fields):
+ res = super().default_get(fields)
+ if not set(fields) & set(['move_line_ids', 'company_id']):
+ return res
+
+ if self.env.context.get('active_model') != 'account.move.line' or not self.env.context.get('active_ids'):
+ raise UserError(_('This can only be used on journal items'))
+ move_line_ids = self.env['account.move.line'].browse(self.env.context['active_ids'])
+ res['move_line_ids'] = [(6, 0, move_line_ids.ids)]
+
+ if any(move.state != 'posted' for move in move_line_ids.mapped('move_id')):
+ raise UserError(_('You can only change the period/account for posted journal items.'))
+ if any(move_line.reconciled for move_line in move_line_ids):
+ raise UserError(_('You can only change the period/account for items that are not yet reconciled.'))
+ if any(line.company_id != move_line_ids[0].company_id for line in move_line_ids):
+ raise UserError(_('You cannot use this wizard on journal entries belonging to different companies.'))
+ res['company_id'] = move_line_ids[0].company_id.id
+
+ allowed_actions = set(dict(self._fields['action'].selection))
+ if self.env.context.get('default_action'):
+ allowed_actions = {self.env.context['default_action']}
+ if any(line.account_id.user_type_id != move_line_ids[0].account_id.user_type_id for line in move_line_ids):
+ allowed_actions.discard('change_period')
+ if not allowed_actions:
+ raise UserError(_('No possible action found with the selected lines.'))
+ res['action'] = allowed_actions.pop()
+ return res
+
+ def _get_move_dict_vals_change_account(self):
+ line_vals = []
+
+ # Group data from selected move lines
+ counterpart_balances = defaultdict(lambda: defaultdict(lambda: 0))
+ grouped_source_lines = defaultdict(lambda: self.env['account.move.line'])
+
+ for line in self.move_line_ids.filtered(lambda x: x.account_id != self.destination_account_id):
+ counterpart_currency = line.currency_id
+ counterpart_amount_currency = line.amount_currency
+
+ if self.destination_account_id.currency_id and self.destination_account_id.currency_id != self.company_id.currency_id:
+ counterpart_currency = self.destination_account_id.currency_id
+ counterpart_amount_currency = self.company_id.currency_id._convert(line.balance, self.destination_account_id.currency_id, self.company_id, line.date)
+
+ if counterpart_currency:
+ counterpart_balances[(line.partner_id, counterpart_currency)]['amount_currency'] += counterpart_amount_currency
+
+ counterpart_balances[(line.partner_id, counterpart_currency)]['balance'] += line.balance
+ grouped_source_lines[(line.partner_id, line.currency_id, line.account_id)] += line
+
+ # Generate counterpart lines' vals
+ for (counterpart_partner, counterpart_currency), counterpart_vals in counterpart_balances.items():
+ source_accounts = self.move_line_ids.mapped('account_id')
+ counterpart_label = len(source_accounts) == 1 and _("Transfer from %s", source_accounts.display_name) or _("Transfer counterpart")
+
+ if not self.company_id.currency_id.is_zero(counterpart_vals['balance']) or (counterpart_currency and not counterpart_currency.is_zero(counterpart_vals['amount_currency'])):
+ line_vals.append({
+ 'name': counterpart_label,
+ 'debit': counterpart_vals['balance'] > 0 and self.company_id.currency_id.round(counterpart_vals['balance']) or 0,
+ 'credit': counterpart_vals['balance'] < 0 and self.company_id.currency_id.round(-counterpart_vals['balance']) or 0,
+ 'account_id': self.destination_account_id.id,
+ 'partner_id': counterpart_partner.id or None,
+ 'amount_currency': counterpart_currency and counterpart_currency.round((counterpart_vals['balance'] < 0 and -1 or 1) * abs(counterpart_vals['amount_currency'])) or 0,
+ 'currency_id': counterpart_currency.id or None,
+ })
+
+ # Generate change_account lines' vals
+ for (partner, currency, account), lines in grouped_source_lines.items():
+ account_balance = sum(line.balance for line in lines)
+ if not (currency or self.company_id.currency_id).is_zero(account_balance):
+ account_amount_currency = currency and currency.round(sum(line.amount_currency for line in lines)) or 0
+ line_vals.append({
+ 'name': _('Transfer to %s', self.destination_account_id.display_name or _('[Not set]')),
+ 'debit': account_balance < 0 and self.company_id.currency_id.round(-account_balance) or 0,
+ 'credit': account_balance > 0 and self.company_id.currency_id.round(account_balance) or 0,
+ 'account_id': account.id,
+ 'partner_id': partner.id or None,
+ 'currency_id': currency.id or None,
+ 'amount_currency': (account_balance > 0 and -1 or 1) * abs(account_amount_currency),
+ })
+
+ return [{
+ 'currency_id': self.journal_id.currency_id.id or self.journal_id.company_id.currency_id.id,
+ 'move_type': 'entry',
+ 'journal_id': self.journal_id.id,
+ 'date': fields.Date.to_string(self.date),
+ 'ref': self.destination_account_id.display_name and _("Transfer entry to %s", self.destination_account_id.display_name or ''),
+ 'line_ids': [(0, 0, line) for line in line_vals],
+ }]
+
+ def _get_move_dict_vals_change_period(self):
+ # set the change_period account on the selected journal items
+ accrual_account = self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account
+
+ move_data = {'new_date': {
+ 'currency_id': self.journal_id.currency_id.id or self.journal_id.company_id.currency_id.id,
+ 'move_type': 'entry',
+ 'line_ids': [],
+ 'ref': _('Adjusting Entry'),
+ 'date': fields.Date.to_string(self.date),
+ 'journal_id': self.journal_id.id,
+ }}
+ # complete the account.move data
+ for date, grouped_lines in groupby(self.move_line_ids, lambda m: m.move_id.date):
+ grouped_lines = list(grouped_lines)
+ amount = sum(l.balance for l in grouped_lines)
+ move_data[date] = {
+ 'currency_id': self.journal_id.currency_id.id or self.journal_id.company_id.currency_id.id,
+ 'move_type': 'entry',
+ 'line_ids': [],
+ 'ref': self._format_strings(_('Adjusting Entry of {date} ({percent:f}% recognized on {new_date})'), grouped_lines[0].move_id, amount),
+ 'date': fields.Date.to_string(date),
+ 'journal_id': self.journal_id.id,
+ }
+
+ # compute the account.move.lines and the total amount per move
+ for aml in self.move_line_ids:
+ # account.move.line data
+ reported_debit = aml.company_id.currency_id.round((self.percentage / 100) * aml.debit)
+ reported_credit = aml.company_id.currency_id.round((self.percentage / 100) * aml.credit)
+ if aml.currency_id:
+ reported_amount_currency = aml.currency_id.round((self.percentage / 100) * aml.amount_currency)
+ else:
+ reported_amount_currency = 0.0
+
+ move_data['new_date']['line_ids'] += [
+ (0, 0, {
+ 'name': aml.name,
+ 'debit': reported_debit,
+ 'credit': reported_credit,
+ 'amount_currency': reported_amount_currency,
+ 'currency_id': aml.currency_id.id,
+ 'account_id': aml.account_id.id,
+ 'partner_id': aml.partner_id.id,
+ }),
+ (0, 0, {
+ 'name': _('Adjusting Entry'),
+ 'debit': reported_credit,
+ 'credit': reported_debit,
+ 'amount_currency': -reported_amount_currency,
+ 'currency_id': aml.currency_id.id,
+ 'account_id': accrual_account.id,
+ 'partner_id': aml.partner_id.id,
+ }),
+ ]
+ move_data[aml.move_id.date]['line_ids'] += [
+ (0, 0, {
+ 'name': aml.name,
+ 'debit': reported_credit,
+ 'credit': reported_debit,
+ 'amount_currency': -reported_amount_currency,
+ 'currency_id': aml.currency_id.id,
+ 'account_id': aml.account_id.id,
+ 'partner_id': aml.partner_id.id,
+ }),
+ (0, 0, {
+ 'name': _('Adjusting Entry'),
+ 'debit': reported_debit,
+ 'credit': reported_credit,
+ 'amount_currency': reported_amount_currency,
+ 'currency_id': aml.currency_id.id,
+ 'account_id': accrual_account.id,
+ 'partner_id': aml.partner_id.id,
+ }),
+ ]
+
+ move_vals = [m for m in move_data.values()]
+ return move_vals
+
+ @api.depends('move_line_ids', 'journal_id', 'revenue_accrual_account', 'expense_accrual_account', 'percentage', 'date', 'account_type', 'action', 'destination_account_id')
+ def _compute_move_data(self):
+ for record in self:
+ if record.action == 'change_period':
+ if any(line.account_id.user_type_id != record.move_line_ids[0].account_id.user_type_id for line in record.move_line_ids):
+ raise UserError(_('All accounts on the lines must be of the same type.'))
+ if record.action == 'change_period':
+ record.move_data = json.dumps(record._get_move_dict_vals_change_period())
+ elif record.action == 'change_account':
+ record.move_data = json.dumps(record._get_move_dict_vals_change_account())
+
+ @api.depends('move_data')
+ def _compute_preview_move_data(self):
+ for record in self:
+ preview_columns = [
+ {'field': 'account_id', 'label': _('Account')},
+ {'field': 'name', 'label': _('Label')},
+ {'field': 'debit', 'label': _('Debit'), 'class': 'text-right text-nowrap'},
+ {'field': 'credit', 'label': _('Credit'), 'class': 'text-right text-nowrap'},
+ ]
+ if record.action == 'change_account':
+ preview_columns[2:2] = [{'field': 'partner_id', 'label': _('Partner')}]
+
+ move_vals = json.loads(record.move_data)
+ preview_vals = []
+ for move in move_vals[:4]:
+ preview_vals += [self.env['account.move']._move_dict_to_preview_vals(move, record.company_id.currency_id)]
+ preview_discarded = max(0, len(move_vals) - len(preview_vals))
+
+ record.preview_move_data = json.dumps({
+ 'groups_vals': preview_vals,
+ 'options': {
+ 'discarded_number': _("%d moves", preview_discarded) if preview_discarded else False,
+ 'columns': preview_columns,
+ },
+ })
+
+ def do_action(self):
+ move_vals = json.loads(self.move_data)
+ if self.action == 'change_period':
+ return self._do_action_change_period(move_vals)
+ elif self.action == 'change_account':
+ return self._do_action_change_account(move_vals)
+
+ def _do_action_change_period(self, move_vals):
+ accrual_account = self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account
+
+ created_moves = self.env['account.move'].create(move_vals)
+ created_moves._post()
+
+ destination_move = created_moves[0]
+ destination_messages = []
+ for move in self.move_line_ids.move_id:
+ amount = sum((self.move_line_ids._origin & move.line_ids).mapped('balance'))
+ accrual_move = created_moves[1:].filtered(lambda m: m.date == move.date)
+
+ if accrual_account.reconcile:
+ to_reconcile = (accrual_move + destination_move).mapped('line_ids').filtered(lambda line: line.account_id == accrual_account)
+ to_reconcile.reconcile()
+ move.message_post(body=self._format_strings(_('Adjusting Entries have been created for this invoice:<ul><li>%(link1)s cancelling '
+ '{percent:f}%% of {amount}</li><li>%(link0)s postponing it to {new_date}</li></ul>',
+ link0=self._format_move_link(destination_move),
+ link1=self._format_move_link(accrual_move),
+ ), move, amount))
+ destination_messages += [self._format_strings(_('Adjusting Entry {link}: {percent:f}% of {amount} recognized from {date}'), move, amount)]
+ accrual_move.message_post(body=self._format_strings(_('Adjusting Entry for {link}: {percent:f}% of {amount} recognized on {new_date}'), move, amount))
+ destination_move.message_post(body='<br/>\n'.join(destination_messages))
+
+ # open the generated entries
+ action = {
+ 'name': _('Generated Entries'),
+ 'domain': [('id', 'in', created_moves.ids)],
+ 'res_model': 'account.move',
+ 'view_mode': 'tree,form',
+ 'type': 'ir.actions.act_window',
+ 'views': [(self.env.ref('account.view_move_tree').id, 'tree'), (False, 'form')],
+ }
+ if len(created_moves) == 1:
+ action.update({'view_mode': 'form', 'res_id': created_moves.id})
+ return action
+
+ def _do_action_change_account(self, move_vals):
+ new_move = self.env['account.move'].create(move_vals)
+ new_move._post()
+
+ # Group lines
+ grouped_lines = defaultdict(lambda: self.env['account.move.line'])
+ destination_lines = self.move_line_ids.filtered(lambda x: x.account_id == self.destination_account_id)
+ for line in self.move_line_ids - destination_lines:
+ grouped_lines[(line.partner_id, line.currency_id, line.account_id)] += line
+
+ # Reconcile
+ for (partner, currency, account), lines in grouped_lines.items():
+ if account.reconcile:
+ to_reconcile = lines + new_move.line_ids.filtered(lambda x: x.account_id == account and x.partner_id == partner and x.currency_id == currency)
+ to_reconcile.reconcile()
+
+ if destination_lines and self.destination_account_id.reconcile:
+ to_reconcile = destination_lines + new_move.line_ids.filtered(lambda x: x.account_id == self.destination_account_id and x.partner_id == partner and x.currency_id == currency)
+ to_reconcile.reconcile()
+
+ # Log the operation on source moves
+ acc_transfer_per_move = defaultdict(lambda: defaultdict(lambda: 0)) # dict(move, dict(account, balance))
+ for line in self.move_line_ids:
+ acc_transfer_per_move[line.move_id][line.account_id] += line.balance
+
+ for move, balances_per_account in acc_transfer_per_move.items():
+ message_to_log = self._format_transfer_source_log(balances_per_account, new_move)
+ if message_to_log:
+ move.message_post(body=message_to_log)
+
+ # Log on target move as well
+ new_move.message_post(body=self._format_new_transfer_move_log(acc_transfer_per_move))
+
+ return {
+ 'name': _("Transfer"),
+ 'type': 'ir.actions.act_window',
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'account.move',
+ 'res_id': new_move.id,
+ }
+
+ # Transfer utils
+ def _format_new_transfer_move_log(self, acc_transfer_per_move):
+ format = _("<li>{amount} ({debit_credit}) from {link}, <strong>%(account_source_name)s</strong></li>")
+ rslt = _("This entry transfers the following amounts to <strong>%(destination)s</strong> <ul>", destination=self.destination_account_id.display_name)
+ for move, balances_per_account in acc_transfer_per_move.items():
+ for account, balance in balances_per_account.items():
+ if account != self.destination_account_id: # Otherwise, logging it here is confusing for the user
+ rslt += self._format_strings(format, move, balance) % {'account_source_name': account.display_name}
+
+ rslt += '</ul>'
+ return rslt
+
+ def _format_transfer_source_log(self, balances_per_account, transfer_move):
+ transfer_format = _("<li>{amount} ({debit_credit}) from <strong>%s</strong> were transferred to <strong>{account_target_name}</strong> by {link}</li>")
+ content = ''
+ for account, balance in balances_per_account.items():
+ if account != self.destination_account_id:
+ content += self._format_strings(transfer_format, transfer_move, balance) % account.display_name
+ return content and '<ul>' + content + '</ul>' or None
+
+ def _format_move_link(self, move):
+ move_link_format = "<a href=# data-oe-model=account.move data-oe-id={move_id}>{move_name}</a>"
+ return move_link_format.format(move_id=move.id, move_name=move.name)
+
+ def _format_strings(self, string, move, amount):
+ return string.format(
+ percent=self.percentage,
+ name=move.name,
+ id=move.id,
+ amount=formatLang(self.env, abs(amount), currency_obj=self.company_id.currency_id),
+ debit_credit=amount < 0 and _('C') or _('D'),
+ link=self._format_move_link(move),
+ date=format_date(self.env, move.date),
+ new_date=self.date and format_date(self.env, self.date) or _('[Not set]'),
+ account_target_name=self.destination_account_id.display_name,
+ )
diff --git a/addons/account/wizard/account_automatic_entry_wizard_views.xml b/addons/account/wizard/account_automatic_entry_wizard_views.xml
new file mode 100644
index 00000000000..6b22bd3fa61
--- /dev/null
+++ b/addons/account/wizard/account_automatic_entry_wizard_views.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <record id="account_automatic_entry_wizard_form" model="ir.ui.view">
+ <field name="name">account.automatic.entry.wizard.form</field>
+ <field name="model">account.automatic.entry.wizard</field>
+ <field name="arch" type="xml">
+ <form>
+ <field name="account_type" invisible="1"/>
+ <field name="company_id" invisible="1"/>
+ <field name="display_currency_helper" invisible="1"/>
+ <div attrs="{'invisible': [('display_currency_helper', '=', False)]}" class="alert alert-info text-center" role="status">
+ The selected destination account is set to use a specific currency. Every entry transferred to it will be converted into this currency, causing
+ the loss of any pre-existing foreign currency amount.
+ </div>
+ <field name="action" invisible="context.get('hide_automatic_options')" widget="radio" options="{'horizontal': true}"/>
+ <group>
+ <group attrs="{'invisible': [('action', '!=', 'change_period')]}">
+ <field name="date" string="Recognition Date"/>
+ <field name="expense_accrual_account" string="Accrued Account"
+ attrs="{'invisible': [('account_type', '!=', 'expense')], 'required': [('account_type', '=', 'expense'), ('action', '=', 'change_period')]}"/>
+ <field name="revenue_accrual_account" string="Accrued Account"
+ attrs="{'invisible': [('account_type', '!=', 'income')], 'required': [('account_type', '=', 'income'), ('action', '=', 'change_period')]}"/>
+ </group>
+ <group attrs="{'invisible': [('action', '!=', 'change_account')]}">
+ <field name="date" string="Transfer Date"/>
+ <field name="destination_account_id" attrs="{'required': [('action', '=', 'change_account')]}" domain="[('company_id', '=', company_id)]"/>
+ </group>
+ <group>
+ <label for="total_amount" string="Adjusting Amount" attrs="{'invisible': [('action', '!=', 'change_period')]}"/>
+ <div attrs="{'invisible': [('action', '!=', 'change_period')]}">
+ <field name="percentage" style="width:40% !important" class="oe_inline" attrs="{'readonly': [('action', '!=', 'change_period')]}"/>%<span class="px-3"></span>(<field name="total_amount" class="oe_inline"/>)
+ </div>
+ <field name="total_amount" readonly="1" attrs="{'invisible': [('action', '=', 'change_period')]}"/>
+ <field name="journal_id"/>
+ </group>
+ </group>
+ <label for="preview_move_data" string="The following Journal Entries will be generated"/>
+ <field name="preview_move_data" widget="grouped_view_widget"/>
+ <footer>
+ <button string="Create Journal Entries" name="do_action" type="object" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="account_automatic_entry_wizard_action" model="ir.actions.act_window">
+ <field name="name">Create Automatic Entries for selected Journal Items</field>
+ <field name="res_model">account.automatic.entry.wizard</field>
+ <field name="view_mode">form</field>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/account/wizard/account_transfer_wizard.py b/addons/account/wizard/account_transfer_wizard.py
deleted file mode 100644
index 709adc51f74..00000000000
--- a/addons/account/wizard/account_transfer_wizard.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, _
-from odoo.exceptions import UserError
-from odoo.tools.misc import format_date, formatLang
-
-from collections import defaultdict
-
-import json
-
-
-class AccountTransferWizard(models.TransientModel):
- _name = 'account.transfer.wizard'
- _description = "Account Transfer Wizard"
-
- move_line_ids = fields.One2many(string="Journal Items", comodel_name='account.move.line', compute="_retrieve_fields_from_context", help="Journal entries to transfer accounts from.")
- destination_account_id = fields.Many2one(string="To", comodel_name='account.account', help="Account to transfer to.")
- journal_id = fields.Many2one(string="Journal", comodel_name='account.journal', help="Journal where to create the transfer entry.")
- date = fields.Date(string="Date", help="Date to be set on the transfer entry.", default=fields.Date.today)
- company_id = fields.Many2one(string="Company", comodel_name='res.company', compute='_retrieve_fields_from_context')
- display_currency_helper = fields.Boolean(string="Currency Conversion Helper", compute='_compute_display_currency_helper', help="Technical field used to indicate whether or not to display the tooltip informing a currency conversion will be performed with the transfer")
- aml_preview_data = fields.Text(string="AML Preview Data", compute='_compute_aml_preview_data', help="Preview JSON data for aml preview widget")
-
- @api.depends_context('active_model')
- def _retrieve_fields_from_context(self):
- if self._context.get('active_model') == 'account.move.line':
- aml = self.env['account.move.line'].browse(self._context.get('active_ids', []))
-
- company = aml.mapped('company_id')
- if len(company) > 1:
- raise UserError(_("You cannot create a transfer for entries belonging to different companies."))
-
- for record in self:
- record.move_line_ids = aml
- record.company_id = company
- else:
- raise UserError(_("Transfer wizard should only be called on account.move.line objects"))
-
- @api.depends('destination_account_id')
- def _compute_display_currency_helper(self):
- for record in self:
- record.display_currency_helper = bool(record.destination_account_id.currency_id)
-
- @api.depends('destination_account_id')
- def _compute_aml_preview_data(self):
- for record in self:
- record.aml_preview_data = json.dumps({
- 'groups_vals': [self.env['account.move']._move_dict_to_preview_vals(self._get_move_to_create_dict(), record.company_id.currency_id)],
- 'options': {
- 'columns': [
- {'field': 'account_id', 'label': _('Account')},
- {'field': 'name', 'label': _('Label')},
- {'field': 'partner_id', 'label': _('Partner')},
- {'field': 'debit', 'label': _('Debit'), 'class': 'text-right text-nowrap'},
- {'field': 'credit', 'label': _('Credit'), 'class': 'text-right text-nowrap'},
- ],
- },
- })
-
- def _get_move_to_create_dict(self):
- line_vals = []
-
- # Group data from selected move lines
- counterpart_balances = defaultdict(lambda: defaultdict(lambda: 0))
- grouped_source_lines = defaultdict(lambda: self.env['account.move.line'])
-
- for line in self.move_line_ids.filtered(lambda x: x.account_id != self.destination_account_id):
- counterpart_currency = line.currency_id
- counterpart_amount_currency = line.amount_currency
-
- if self.destination_account_id.currency_id and self.destination_account_id.currency_id != self.company_id.currency_id:
- counterpart_currency = self.destination_account_id.currency_id
- counterpart_amount_currency = self.company_id.currency_id._convert(line.balance, self.destination_account_id.currency_id, self.company_id, line.date)
-
- if counterpart_currency:
- counterpart_balances[(line.partner_id, counterpart_currency)]['amount_currency'] += counterpart_amount_currency
-
- counterpart_balances[(line.partner_id, counterpart_currency)]['balance'] += line.balance
- grouped_source_lines[(line.partner_id, line.currency_id, line.account_id)] += line
-
- # Generate counterpart lines' vals
- for (counterpart_partner, counterpart_currency), counterpart_vals in counterpart_balances.items():
- source_accounts = self.move_line_ids.mapped('account_id')
- counterpart_label = len(source_accounts) == 1 and _("Transfer from %s", source_accounts.display_name) or _("Transfer counterpart")
-
- if not self.company_id.currency_id.is_zero(counterpart_vals['balance']) or (counterpart_currency and not counterpart_currency.is_zero(counterpart_vals['amount_currency'])):
- line_vals.append({
- 'name': counterpart_label,
- 'debit': counterpart_vals['balance'] > 0 and self.company_id.currency_id.round(counterpart_vals['balance']) or 0,
- 'credit': counterpart_vals['balance'] < 0 and self.company_id.currency_id.round(-counterpart_vals['balance']) or 0,
- 'account_id': self.destination_account_id.id,
- 'partner_id': counterpart_partner.id or None,
- 'amount_currency': counterpart_currency and counterpart_currency.round((counterpart_vals['balance'] < 0 and -1 or 1) * abs(counterpart_vals['amount_currency'])) or 0,
- 'currency_id': counterpart_currency.id or None,
- })
-
- # Generate transfer lines' vals
- for (partner, currency, account), lines in grouped_source_lines.items():
- account_balance = sum(line.balance for line in lines)
- if not (currency or self.company_id.currency_id).is_zero(account_balance):
- account_amount_currency = currency and currency.round(sum(line.amount_currency for line in lines)) or 0
- line_vals.append({
- 'name': _('Transfer to %s') % (self.destination_account_id.display_name or _('Destination Account')),
- 'debit': account_balance < 0 and self.company_id.currency_id.round(-account_balance) or 0,
- 'credit': account_balance > 0 and self.company_id.currency_id.round(account_balance) or 0,
- 'account_id': account.id,
- 'partner_id': partner.id or None,
- 'currency_id': currency.id or None,
- 'amount_currency': (account_balance > 0 and -1 or 1) * abs(account_amount_currency),
- })
-
- return {
- 'journal_id': self.journal_id.id,
- 'date': self.date,
- 'ref': self.destination_account_id.display_name and _("Transfer entry to %s", self.destination_account_id.display_name) or '',
- 'line_ids': [(0, 0, line) for line in line_vals],
- }
-
- def button_transfer(self):
- new_move = self.env['account.move'].create(self._get_move_to_create_dict())
- new_move.post()
-
- # Group lines
- grouped_lines = defaultdict(lambda: self.env['account.move.line'])
- destination_lines = self.move_line_ids.filtered(lambda x: x.account_id == self.destination_account_id)
- for line in self.move_line_ids - destination_lines:
- grouped_lines[(line.partner_id, line.currency_id, line.account_id)] += line
-
- # Reconcile
- for (partner, currency, account), lines in grouped_lines.items():
- if account.reconcile:
- to_reconcile = lines + new_move.line_ids.filtered(lambda x: x.account_id == account and x.partner_id == partner and x.currency_id == currency)
- to_reconcile.reconcile()
-
- if destination_lines and self.destination_account_id.reconcile:
- to_reconcile = destination_lines + new_move.line_ids.filtered(lambda x: x.account_id == self.destination_account_id and x.partner_id == partner and x.currency_id == currency)
- to_reconcile.reconcile()
-
- # Log the operation on source moves
- acc_transfer_per_move = defaultdict(lambda: defaultdict(lambda: 0)) # dict(move, dict(account, balance))
- for line in self.move_line_ids:
- acc_transfer_per_move[line.move_id][line.account_id] += line.balance
-
- for move, balances_per_account in acc_transfer_per_move.items():
- message_to_log = self._format_source_log(balances_per_account, new_move)
- if message_to_log:
- move.message_post(body=message_to_log)
-
- # Log on target move as well
- new_move.message_post(body=self._format_new_move_log(acc_transfer_per_move))
-
- return {
- 'name': _("Transfer"),
- 'type': 'ir.actions.act_window',
- 'view_type': 'form',
- 'view_mode': 'form',
- 'res_model': 'account.move',
- 'res_id': new_move.id,
- }
-
- def _format_new_move_log(self, acc_transfer_per_move):
- format = _("%(amount)s %(currency_symbol)s (%(debit_credit)s) from %(link)s, <strong>%(account_source_name)s</strong>")
- rslt = _("This entry transfers the following amounts to <strong>%(destination)s</strong> <ul>") % {'destination': self.destination_account_id.display_name}
- for move, balances_per_account in acc_transfer_per_move.items():
- for account, balance in balances_per_account.items():
- if account != self.destination_account_id: # Otherwise, logging it here is confusing for the user
- rslt += ('<li>' + format +'</li>') % {
- 'amount': abs(balance),
- 'debit_credit': balance < 0 and _('C') or _('D'),
- 'currency_symbol': self.company_id.currency_id.symbol,
- 'account_source_name': account.display_name,
- 'link': self._format_move_link(move),
- }
-
- rslt += '</ul>'
- return rslt
-
- def _format_source_log(self, balances_per_account, transfer_move):
- transfer_format = _("%(amount)s %(currency_symbol)s (%(debit_credit)s) from <strong>%(account_source_name)s</strong> were transferred to <strong>%(account_target_name)s</strong> by %(link)s")
- content = ''
- for account, balance in balances_per_account.items():
- if account != self.destination_account_id:
- content += ('<li>' + transfer_format + '</li>') % {
- 'amount': abs(balance),
- 'debit_credit': balance < 0 and _('C') or _('D'),
- 'currency_symbol': self.company_id.currency_id.symbol,
- 'account_source_name': account.display_name,
- 'account_target_name': self.destination_account_id.display_name,
- 'link': self._format_move_link(transfer_move),
- }
- return content and '<ul>' + content + '</ul>' or None
-
- def _format_move_link(self, move):
- move_link_format = "<a href=# data-oe-model=account.move data-oe-id=%(move_id)s>%(move_name)s</a>"
- return move_link_format % {'move_id': move.id, 'move_name': move.name}
diff --git a/addons/account/wizard/account_transfer_wizard.xml b/addons/account/wizard/account_transfer_wizard.xml
deleted file mode 100644
index 052bf8cdc9b..00000000000
--- a/addons/account/wizard/account_transfer_wizard.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
- <data>
-
- <record id="account_move_transfer_accounts_wizard" model="ir.ui.view">
- <field name="name">account.transfer.wizard.form</field>
- <field name="model">account.transfer.wizard</field>
- <field name="arch" type="xml">
- <form>
-
- <field name="display_currency_helper" invisible="1"/>
- <div attrs="{'invisible': [('display_currency_helper', '=', False)]}" class="alert alert-info text-center" role="status">
- The selected destination account is set to use a specific currency. Every entry transferred to it will be converted into this currency, causing
- the loss of any pre-existing foreign currency amount.
- </div>
-
- <group>
- <group>
- <field name="company_id" invisible="1"/>
- <field name="destination_account_id" required="1" domain="[('company_id', '=', company_id)]"/>
- <field name="date" required="1"/>
- </group>
- <group>
- <field name="journal_id" required="1" domain="[('type', '=', 'general'), ('company_id', '=', company_id)]"/>
- </group>
- </group>
-
- <p><strong>The following journal entry will be generated</strong></p>
-
- <field name="aml_preview_data" widget="grouped_view_widget"/>
-
- <footer>
- <button string="Transfer Entries" name="button_transfer" type="object" class="oe_highlight"/>
- <button string="Cancel" special="cancel"/>
- </footer>
- </form>
- </field>
- </record>
-
- </data>
-</odoo>