[FIX] stock_account: anglo-saxon accounting & storno

First issue: post a credit note

Steps to reproduce:
- enable anglo-saxon accounting and storno
- create a storable product with sale price = 50 and cost = 30
- set costing method FIFO and automated inventory valuation on product category
- create a credit note using this product
- post credit note

Error:

There was a problem with the following move(s):
- Move with id 18
	The debit and credit should be negative and only one can be set

Second issue: return a product

In anglo-saxon accounting, returning a product means creating a reverse move.
Reverse move in storno should have a negative debit/credit.

opw-3110934

closes odoo/odoo#114671

X-original-commit: f24a87b1d0bb3a18ef1d2d4cd23fb34bf29d4bfb
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
nda-odoo
2023-03-08 13:49:14 +01:00
parent c6359dc342
commit af3938c182
3 changed files with 60 additions and 40 deletions
+6 -6
View File
@@ -486,10 +486,9 @@ class StockMove(models.Model):
'product_id': self.product_id.id,
'quantity': qty,
'product_uom_id': self.product_id.uom_id.id,
'balance': -diff_amount,
'ref': description,
'partner_id': partner_id,
'credit': diff_amount > 0 and diff_amount or 0,
'debit': diff_amount < 0 and -diff_amount or 0,
'account_id': price_diff_account.id,
}
return rslt
@@ -522,6 +521,7 @@ class StockMove(models.Model):
'stock_move_id': self.id,
'stock_valuation_layer_ids': [(6, None, [svl_id])],
'move_type': 'entry',
'is_storno': self.env.context.get('is_returned') and self.env.company.account_storno,
}
def _account_analytic_entry_move(self):
@@ -557,7 +557,7 @@ class StockMove(models.Model):
# warehouse of the same company, the transit location belongs to this company, so we don't need to create accounting entries
if self._is_in():
if self._is_returned(valued_type='in'):
am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
am_vals.append(self.with_company(company_to).with_context(is_returned=True)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
else:
am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost))
@@ -565,7 +565,7 @@ class StockMove(models.Model):
if self._is_out():
cost = -1 * cost
if self._is_returned(valued_type='out'):
am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
am_vals.append(self.with_company(company_from).with_context(is_returned=True)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
else:
am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost))
@@ -579,10 +579,10 @@ class StockMove(models.Model):
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost))
elif self._is_dropshipped_returned():
if cost > 0:
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
am_vals.append(self.with_company(self.company_id).with_context(is_returned=True)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
else:
cost = -1 * cost
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
am_vals.append(self.with_company(self.company_id).with_context(is_returned=True)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
return am_vals
@@ -4,7 +4,7 @@
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
from odoo.tests.common import tagged, Form
from odoo import fields
class TestAccountMoveStockCommon(AccountTestInvoicingCommon):
@classmethod
@@ -117,3 +117,29 @@ class TestAccountMove(TestAccountMoveStockCommon):
self.assertEqual(len(invoice.mapped("line_ids")), 4)
self.assertEqual(len(invoice.mapped("line_ids").filtered(lambda l: l.display_type == 'cogs')), 2)
self.assertEqual(len(invoice.mapped("line_ids.currency_id")), 2)
def test_storno_accounting(self):
"""Storno accounting uses negative numbers on debit/credit to cancel other moves.
This test checks that we do the same for the anglosaxon lines when storno is enabled.
"""
self.env.company.account_storno = True
self.env.company.anglo_saxon_accounting = True
move = self.env['account.move'].create({
'move_type': 'out_refund',
'invoice_date': fields.Date.from_string('2019-01-01'),
'partner_id': self.partner_a.id,
'currency_id': self.currency_data['currency'].id,
'invoice_line_ids': [
(0, None, {'product_id': self.product_A.id}),
]
})
move.action_post()
stock_output_line = move.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
self.assertEqual(stock_output_line.debit, 0)
self.assertEqual(stock_output_line.credit, -10)
expense_line = move.line_ids.filtered(lambda l: l.account_id == self.product_A.property_account_expense_id)
self.assertEqual(expense_line.debit, -10)
self.assertEqual(expense_line.credit, 0)
@@ -1022,7 +1022,7 @@ class TestStockValuationChangeValuation(TestStockValuationCommon):
self.assertAlmostEqual(abs(move.stock_valuation_layer_ids.value), 1123.39)
@tagged('post_install', '-at_install')
class TestAngloSaxonAccounting(AccountTestInvoicingCommon):
class TestAngloSaxonAccounting(AccountTestInvoicingCommon, TestStockValuationCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
@@ -1103,38 +1103,6 @@ class TestAngloSaxonAccounting(AccountTestInvoicingCommon):
'property_stock_journal': cls.company_data['default_journal_misc'].id,
})
def _make_in_move(self, product, quantity, unit_cost=None, create_picking=False, loc_dest=None, pick_type=None):
""" Helper to create and validate a receipt move.
"""
unit_cost = unit_cost or product.standard_price
loc_dest = loc_dest or self.stock_location
pick_type = pick_type or self.picking_type_in
in_move = self.env['stock.move'].create({
'name': 'in %s units @ %s per unit' % (str(quantity), str(unit_cost)),
'product_id': product.id,
'location_id': self.supplier_location.id,
'location_dest_id': loc_dest.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': quantity,
'price_unit': unit_cost,
'picking_type_id': pick_type.id,
})
if create_picking:
picking = self.env['stock.picking'].create({
'picking_type_id': in_move.picking_type_id.id,
'location_id': in_move.location_id.id,
'location_dest_id': in_move.location_dest_id.id,
})
in_move.write({'picking_id': picking.id})
in_move._action_confirm()
in_move._action_assign()
in_move.move_line_ids.qty_done = quantity
in_move._action_done()
return in_move.with_context(svl=True)
def test_avco_and_credit_note(self):
"""
When reversing an invoice that contains some anglo-saxo AML, the new anglo-saxo AML should have the same value
@@ -1174,3 +1142,29 @@ class TestAngloSaxonAccounting(AccountTestInvoicingCommon):
self.assertEqual(len(anglo_lines), 2)
self.assertEqual(abs(anglo_lines[0].balance), 10)
self.assertEqual(abs(anglo_lines[1].balance), 10)
def test_return_delivery_storno(self):
""" When using STORNO accounting, reverse accounting moves should have negative values for credit/debit.
"""
self.env.company.account_storno = True
self.product1.categ_id.property_cost_method = 'fifo'
self._make_in_move(self.product1, 10, unit_cost=10)
out_move = self._make_out_move(self.product1, 10, create_picking=True)
return_move = self._make_return(out_move, 10)
valuation_line = out_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_valuation_account)
stock_out_line = out_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
self.assertEqual(valuation_line.credit, 100)
self.assertEqual(valuation_line.debit, 0)
self.assertEqual(stock_out_line.credit, 0)
self.assertEqual(stock_out_line.debit, 100)
valuation_line = return_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_valuation_account)
stock_out_line = return_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
self.assertEqual(valuation_line.credit, -100)
self.assertEqual(valuation_line.debit, 0)
self.assertEqual(stock_out_line.credit, 0)
self.assertEqual(stock_out_line.debit, -100)