diff --git a/addons/account/tests/test_account_move_in_invoice.py b/addons/account/tests/test_account_move_in_invoice.py index 73efe8e6afb..dd4a9a834e5 100644 --- a/addons/account/tests/test_account_move_in_invoice.py +++ b/addons/account/tests/test_account_move_in_invoice.py @@ -1193,3 +1193,47 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon): 'amount_total' : self.move_vals['amount_total'], 'amount_untaxed' : self.move_vals['amount_untaxed'], }) + + def test_in_invoice_accrual(self): + self.env.company.accrual_default_journal_id = self.company_data['default_journal_misc'] + self.env.company.expense_accrual_account_id = self.env['account.account'].create({ + 'name': 'Accrual Expense Account', + 'code': '234567', + 'user_type_id': self.env.ref('account.data_account_type_expenses').id, + 'reconcile': True, + }) + self.env.company.revenue_accrual_account_id = self.env['account.account'].create({ + 'name': 'Accrual Revenue Account', + 'code': '765432', + 'user_type_id': self.env.ref('account.data_account_type_expenses').id, + 'reconcile': True, + }) + + invoice_line = self.invoice.line_ids.filtered(lambda l: l.account_id == self.product_a.property_account_expense_id) + self.env['account.accrual.accounting.wizard'].with_context( + active_model='account.move.line', + active_ids=invoice_line.ids + ).create({ + 'date': '2016-01-01', + 'percentage': 60, + }).amend_entries() + + # Nothing changed except the account + self.assertInvoiceValues(self.invoice, [ + { + **self.product_line_vals_1, + 'account_id': self.env.company.expense_accrual_account_id.id, + }, + self.product_line_vals_2, + self.tax_line_vals_1, + self.tax_line_vals_2, + self.term_line_vals_1, + ], self.move_vals) + + accrual_moves = self.env['account.move'].search([('journal_id', '=', self.env.company.accrual_default_journal_id.id)]) + accrual_other_date = accrual_moves.filtered(lambda m: m.date == fields.Date.to_date('2016-01-01')) + accrual_same_date = accrual_moves.filtered(lambda m: m.date == invoice_line.date) + + self.assertEqual(accrual_same_date.amount_total, 0.4 * invoice_line.balance) + self.assertEqual(accrual_other_date.amount_total, 0.6 * invoice_line.balance) + self.assertTrue(accrual_other_date.line_ids.full_reconcile_id) diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index 7606c43a59f..c7a6330db8e 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -1267,4 +1267,48 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon): 'amount_tax' : self.move_vals['amount_tax'], 'amount_total' : self.move_vals['amount_total'], 'amount_untaxed' : self.move_vals['amount_untaxed'], - }) \ No newline at end of file + }) + + def test_out_invoice_accrual(self): + self.env.company.accrual_default_journal_id = self.company_data['default_journal_misc'] + self.env.company.expense_accrual_account_id = self.env['account.account'].create({ + 'name': 'Accrual Expense Account', + 'code': '234567', + 'user_type_id': self.env.ref('account.data_account_type_expenses').id, + 'reconcile': True, + }) + self.env.company.revenue_accrual_account_id = self.env['account.account'].create({ + 'name': 'Accrual Revenue Account', + 'code': '765432', + 'user_type_id': self.env.ref('account.data_account_type_expenses').id, + 'reconcile': True, + }) + + invoice_line = self.invoice.line_ids.filtered(lambda l: l.account_id == self.product_a.property_account_income_id) + self.env['account.accrual.accounting.wizard'].with_context( + active_model='account.move.line', + active_ids=invoice_line.ids + ).create({ + 'date': '2016-01-01', + 'percentage': 60, + }).amend_entries() + + # Nothing changed except the account + self.assertInvoiceValues(self.invoice, [ + { + **self.product_line_vals_1, + 'account_id': self.env.company.revenue_accrual_account_id.id, + }, + self.product_line_vals_2, + self.tax_line_vals_1, + self.tax_line_vals_2, + self.term_line_vals_1, + ], self.move_vals) + + accrual_moves = self.env['account.move'].search([('journal_id', '=', self.env.company.accrual_default_journal_id.id)]) + accrual_other_date = accrual_moves.filtered(lambda m: m.date == fields.Date.to_date('2016-01-01')) + accrual_same_date = accrual_moves.filtered(lambda m: m.date == invoice_line.date) + + self.assertEqual(accrual_same_date.amount_total, 0.4 * -invoice_line.balance) + self.assertEqual(accrual_other_date.amount_total, 0.6 * -invoice_line.balance) + self.assertTrue(accrual_other_date.line_ids.full_reconcile_id) diff --git a/addons/account/wizard/account_accrual_accounting.py b/addons/account/wizard/account_accrual_accounting.py index 86a01d1c538..1c155103563 100644 --- a/addons/account/wizard/account_accrual_accounting.py +++ b/addons/account/wizard/account_accrual_accounting.py @@ -8,7 +8,7 @@ class AccrualAccountingWizard(models.TransientModel): _description = 'Create accrual entry.' date = fields.Date(required=True) - company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company) + company_id = fields.Many2one('res.company', required=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, related="company_id.accrual_default_journal_id", readonly=False) @@ -41,6 +41,9 @@ class AccrualAccountingWizard(models.TransientModel): 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: ') + ", ".join(account_types_allowed.mapped('name'))) @@ -48,19 +51,15 @@ class AccrualAccountingWizard(models.TransientModel): return rec def amend_entries(self): - move_data = [] - to_reconcile = [] - message_data = [] - - #gather the origin account on seleced journal items + # gather the origin account on seleced journal items origin_accounts = {} for aml in self.active_move_line_ids: origin_accounts[aml.id] = aml.account_id.id - #set the accrual account on the selected journal items + # set the accrual account on the selected journal items self.active_move_line_ids.write({'account_id': (self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account).id}) - #create the accrual move(s) and reconcile accrual items together + # create the accrual move(s) and reconcile accrual items together for aml in self.active_move_line_ids: 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) @@ -91,7 +90,7 @@ class AccrualAccountingWizard(models.TransientModel): 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 + # 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({ @@ -126,11 +125,11 @@ class AccrualAccountingWizard(models.TransientModel): for move, msg in zip(created_ids, message_data): move.message_post(body=msg) - #reconcile journal items on the accrual account + # 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 + # open the generated entries action = { 'name': _('Generated Entries'), 'domain': [('id', 'in', created_ids.ids)],