diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py
index c1951b19666..1670fd3bc62 100644
--- a/addons/account/__manifest__.py
+++ b/addons/account/__manifest__.py
@@ -24,6 +24,7 @@ You could use this simplified accounting in case you work with an (external) acc
'data/digest_data.xml',
'views/account_menuitem.xml',
'views/account_payment_view.xml',
+ 'wizard/account_accrual_accounting_view.xml',
'wizard/account_unreconcile_view.xml',
'wizard/account_move_reversal_view.xml',
'views/account_move_views.xml',
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 69af644a794..c162b869d25 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -3568,6 +3568,11 @@ class AccountMoveLine(models.Model):
action['domain'] = [('id', 'in', ids)]
return action
+ def action_accrual_entry(self):
+ [action] = self.env.ref('account.account_accrual_accounting_wizard_action').read()
+ action['context'] = self.env.context
+ return action
+
@api.model
def _get_suspense_moves_domain(self):
return [
diff --git a/addons/account/models/company.py b/addons/account/models/company.py
index 95980862702..a2d71f8645d 100644
--- a/addons/account/models/company.py
+++ b/addons/account/models/company.py
@@ -107,6 +107,11 @@ Best Regards,'''))
# Needed in the Point of Sale
account_default_pos_receivable_account_id = fields.Many2one('account.account', string="Default PoS Receivable Account")
+ # Accrual Accounting
+ expense_accrual_account_id = fields.Many2one('account.account', help="Account used to move the period of an expense", domain=[('internal_group', '=', 'liability'), ('reconcile', '=', True)])
+ revenue_accrual_account_id = fields.Many2one('account.account', help="Account used to move the period of a revenue", domain=[('internal_group', '=', 'asset'), ('reconcile', '=', True)])
+ accrual_default_journal_id = fields.Many2one('account.journal', help="Journal used by default for moving the period of an entry", domain="[('type', '=', 'general')]")
+
@api.constrains('account_opening_move_id', 'fiscalyear_last_day', 'fiscalyear_last_month')
def _check_fiscalyear_last_day(self):
# if the user explicitly chooses the 29th of February we allow it:
diff --git a/addons/account/views/account_move_views.xml b/addons/account/views/account_move_views.xml
index 3e704a282cb..89d3103898c 100644
--- a/addons/account/views/account_move_views.xml
+++ b/addons/account/views/account_move_views.xml
@@ -983,6 +983,14 @@
manual_reconciliation_view
+
+ Change Period
+
+
+ code
+ action = records.action_accrual_entry()
+
+
{name}').format(
+ percent=self.percentage,
+ id=aml.move_id.id,
+ name=aml.move_id.name,
+ )]
+ #in case the percentage to recognize is not 100%, another entry is created to keep the remaining balance in the same account at the original date
+ if self.percentage < 100:
+ ref = _('Accrual Adjusting Entry ({percent}% recognized) for invoice: {name}').format(percent=100 - self.percentage, name=aml.move_id.name)
+ move_data.append({
+ 'date': aml.move_id.date,
+ 'ref': ref,
+ 'journal_id': self.journal_id.id,
+ 'line_ids': [
+ (0, 0, {
+ 'name': aml.name,
+ 'debit': aml.debit - reported_debit,
+ 'credit': aml.credit - reported_credit,
+ 'account_id': origin_accounts[aml.id],
+ 'partner_id': aml.partner_id.id,
+ }),
+ (0, 0, {
+ 'name': ref,
+ 'debit': aml.credit - reported_credit,
+ 'credit': aml.debit - reported_debit,
+ 'account_id': (self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account).id,
+ 'partner_id': aml.partner_id.id,
+ }),
+ ],
+ })
+ message_data.append((_('Accrual Adjusting Entry ({percent}% recognized) for invoice:') + ' {name}').format(
+ percent=self.percentage,
+ id=aml.move_id.id,
+ name=aml.move_id.name,
+ ))
+
+ created_ids = self.env['account.move'].create(move_data)
+ created_ids.post()
+ for move, msg in zip(created_ids, message_data):
+ move.message_post(body=msg)
+
+ #reconcile journal items on the accrual account
+ to_reconcile = created_ids.line_ids.filtered(lambda line: line.account_id in (self.revenue_accrual_account + self.expense_accrual_account)) + aml
+ to_reconcile.reconcile()
+
+ #open the generated entries
+ action = {
+ 'name': _('Generated Entries'),
+ 'domain': [('id', 'in', created_ids.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_ids) == 1:
+ action.update({'view_mode': 'form', 'res_id': created_ids.id})
+ return action
diff --git a/addons/account/wizard/account_accrual_accounting_view.xml b/addons/account/wizard/account_accrual_accounting_view.xml
new file mode 100644
index 00000000000..62d3a7a377f
--- /dev/null
+++ b/addons/account/wizard/account_accrual_accounting_view.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ account.accrual.accounting.wizard.form
+ account.accrual.accounting.wizard
+
+
+
+
+
+
+ Change Period for the expense/revenue recognition
+ account.accrual.accounting.wizard
+ form
+ new
+
+
+