From 60dadc8ecdd341c79673418674ba97f9b0435bb2 Mon Sep 17 00:00:00 2001 From: wan Date: Mon, 26 Aug 2019 11:10:58 +0000 Subject: [PATCH] [IMP] account: acrual expenses/revenues ======= Purpose ======= Accruals are revenues and expenses that are incurred during an accounting period for which no invoices or payments were received or made. => We suggest a wizard allowing recognizing the Expense/Revenue in a different period keeping tax return in the invoice period. Example: A vendor bill received in February which was for the December consumption. You should recognize the expense in December but the tax return is still due to February. 1) Regular Vendor Bill in february Account D C 600 ACHAT 10000 411 TVA 2100 440 FOUR 12100 2) Action opening a wizard that allows specifying when we have to move the expense. - Targeted date, accrued account (expense, revenue, taxes, ...) - Action from account.move.line ? 3) Wizard result a) The expense account is replaced by the accrued expense account in the original vendor bill journal entry (february) Compte D C 444 FAE 10000 411 TVA 2100 440 FOUR 12100 b) A new accrual journal entry is created for the original expense account in december Compte D C 600 ACHAT 10000 444 FAE 10000 Was task 2006617 closes odoo/odoo#36053 Signed-off-by: Quentin De Paoli (qdp) --- addons/account/__manifest__.py | 1 + addons/account/models/account_move.py | 5 + addons/account/models/company.py | 5 + addons/account/views/account_move_views.xml | 8 + addons/account/wizard/__init__.py | 1 + .../wizard/account_accrual_accounting.py | 144 ++++++++++++++++++ .../account_accrual_accounting_view.xml | 38 +++++ 7 files changed, 202 insertions(+) create mode 100644 addons/account/wizard/account_accrual_accounting.py create mode 100644 addons/account/wizard/account_accrual_accounting_view.xml 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 + +
+