[FIX] account: fix change period reconciliation for automatic entry wizard
When creating automatic entries for multiple moves on different dates with the automatic entry wizard, the wizard would reconcile all the lines on the accrual account of the destination move with the lines on the accrual account of each accrual move. As this would imply reconciling the same lines multiple times, it triggers a reconciliation error. What must be done is, for each accrual move, reconcile it’s lines with only the related lines on the destination move. closes odoo/odoo#83732 Task: 2717578 X-original-commit: 502003ac548d6620374dfbab4fb7be6dee3c1bf5 Signed-off-by: Laurent Smet <las@odoo.com> Signed-off-by: Florian Gilbert <flg@odoo.com> Signed-off-by: de Wouters de Bouchout Jean-Benoît (jbw) <jbw@odoo.com>
This commit is contained in:
@@ -2813,6 +2813,140 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
])
|
||||
|
||||
def test_out_invoice_multi_date_change_period_accrual(self):
|
||||
dates = ['2017-01-01', '2017-01-01', '2017-02-01']
|
||||
values = []
|
||||
for date in dates:
|
||||
values.append({
|
||||
'move_type': 'out_invoice',
|
||||
'date': date,
|
||||
'partner_id': self.partner_a.id,
|
||||
'invoice_date': fields.Date.from_string(date),
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'invoice_payment_term_id': self.pay_terms_a.id,
|
||||
'invoice_line_ids': [
|
||||
(0, None, {
|
||||
'name': self.product_line_vals_1['name'],
|
||||
'product_id': self.product_line_vals_1['product_id'],
|
||||
'product_uom_id': self.product_line_vals_1['product_uom_id'],
|
||||
'quantity': self.product_line_vals_1['quantity'],
|
||||
'price_unit': self.product_line_vals_1['price_unit'],
|
||||
'tax_ids': self.product_line_vals_1['tax_ids'],
|
||||
}),
|
||||
(0, None, {
|
||||
'name': self.product_line_vals_2['name'],
|
||||
'product_id': self.product_line_vals_2['product_id'],
|
||||
'product_uom_id': self.product_line_vals_2['product_uom_id'],
|
||||
'quantity': self.product_line_vals_2['quantity'],
|
||||
'price_unit': self.product_line_vals_2['price_unit'],
|
||||
'tax_ids': self.product_line_vals_2['tax_ids'],
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
moves = self.env['account.move'].create(values)
|
||||
moves.action_post()
|
||||
|
||||
wizard = self.env['account.automatic.entry.wizard'].with_context(
|
||||
active_model='account.move.line',
|
||||
active_ids=moves.invoice_line_ids.ids,
|
||||
).create({
|
||||
'action': 'change_period',
|
||||
'date': '2018-01-01',
|
||||
'percentage': 60,
|
||||
'journal_id': self.company_data['default_journal_misc'].id,
|
||||
'expense_accrual_account': 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,
|
||||
}).id,
|
||||
'revenue_accrual_account': 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,
|
||||
}).id,
|
||||
})
|
||||
wizard_res = wizard.do_action()
|
||||
|
||||
for date, move, ref in zip(dates, moves, ['INV/2017/00001', 'INV/2017/00002', 'INV/2017/00003']):
|
||||
self.assertInvoiceValues(move, [
|
||||
{
|
||||
**self.product_line_vals_1,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'amount_currency': -1000.0,
|
||||
'debit': 0.0,
|
||||
'credit': 500.0,
|
||||
},
|
||||
{
|
||||
**self.product_line_vals_2,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'amount_currency': -200.0,
|
||||
'debit': 0.0,
|
||||
'credit': 100.0,
|
||||
},
|
||||
{
|
||||
**self.tax_line_vals_1,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'amount_currency': -180.0,
|
||||
'debit': 0.0,
|
||||
'credit': 90.0,
|
||||
},
|
||||
{
|
||||
**self.tax_line_vals_2,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'amount_currency': -30.0,
|
||||
'debit': 0.0,
|
||||
'credit': 15.0,
|
||||
},
|
||||
{
|
||||
**self.term_line_vals_1,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'name': ref,
|
||||
'amount_currency': 1410.0,
|
||||
'debit': 705.0,
|
||||
'credit': 0.0,
|
||||
'date_maturity': fields.Date.from_string(date),
|
||||
},
|
||||
], {
|
||||
**self.move_vals,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'date': fields.Date.from_string(date),
|
||||
'payment_reference': ref,
|
||||
})
|
||||
|
||||
moves = self.env['account.move'].browse(wizard_res['domain'][0][2])
|
||||
|
||||
accrual_lines = moves.line_ids.sorted('date')
|
||||
self.assertRecordValues(accrual_lines, [
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': -600.0, 'debit': 0.0, 'credit': 300.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 600.0, 'debit': 300.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
{'amount_currency': -120.0, 'debit': 0.0, 'credit': 60.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
|
||||
{'amount_currency': 120.0, 'debit': 60.0, 'credit': 0.0, 'account_id': wizard.revenue_accrual_account.id, 'reconciled': True},
|
||||
])
|
||||
|
||||
def test_out_invoice_filter_zero_balance_lines(self):
|
||||
zero_balance_payment_term = self.env['account.payment.term'].create({
|
||||
'name': 'zero_balance_payment_term',
|
||||
|
||||
@@ -321,22 +321,31 @@ class AutomaticEntryWizard(models.TransientModel):
|
||||
created_moves._post()
|
||||
|
||||
destination_move = created_moves[0]
|
||||
destination_move_offset = 0
|
||||
destination_messages = []
|
||||
accrual_move_messages = defaultdict(lambda: [])
|
||||
accrual_move_offsets = defaultdict(int)
|
||||
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()
|
||||
destination_move_lines = destination_move.mapped('line_ids').filtered(lambda line: line.account_id == accrual_account)[destination_move_offset:destination_move_offset+2]
|
||||
destination_move_offset += 2
|
||||
accrual_move_lines = accrual_move.mapped('line_ids').filtered(lambda line: line.account_id == accrual_account)[accrual_move_offsets[accrual_move]:accrual_move_offsets[accrual_move]+2]
|
||||
accrual_move_offsets[accrual_move] += 2
|
||||
(accrual_move_lines + destination_move_lines).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))
|
||||
accrual_move_messages[accrual_move] += [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))
|
||||
for accrual_move, messages in accrual_move_messages.items():
|
||||
accrual_move.message_post(body='<br/>\n'.join(messages))
|
||||
|
||||
# open the generated entries
|
||||
action = {
|
||||
|
||||
Reference in New Issue
Block a user