Skip to content

Commit f24a87b

Browse files
committed
[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#114310 X-original-commit: 0c1592a Signed-off-by: William Henrotin (whe) <whe@odoo.com>
1 parent dbb6ad4 commit f24a87b

File tree

3 files changed

+60
-40
lines changed

3 files changed

+60
-40
lines changed

addons/stock_account/models/stock_move.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,9 @@ def _generate_valuation_lines_data(self, partner_id, qty, debit_value, credit_va
488488
'product_id': self.product_id.id,
489489
'quantity': qty,
490490
'product_uom_id': self.product_id.uom_id.id,
491+
'balance': -diff_amount,
491492
'ref': description,
492493
'partner_id': partner_id,
493-
'credit': diff_amount > 0 and diff_amount or 0,
494-
'debit': diff_amount < 0 and -diff_amount or 0,
495494
'account_id': price_diff_account.id,
496495
}
497496
return rslt
@@ -524,6 +523,7 @@ def _prepare_account_move_vals(self, credit_account_id, debit_account_id, journa
524523
'stock_move_id': self.id,
525524
'stock_valuation_layer_ids': [(6, None, [svl_id])],
526525
'move_type': 'entry',
526+
'is_storno': self.env.context.get('is_returned') and self.env.company.account_storno,
527527
}
528528

529529
def _account_analytic_entry_move(self):
@@ -559,15 +559,15 @@ def _account_entry_move(self, qty, description, svl_id, cost):
559559
# warehouse of the same company, the transit location belongs to this company, so we don't need to create accounting entries
560560
if self._is_in():
561561
if self._is_returned(valued_type='in'):
562-
am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
562+
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))
563563
else:
564564
am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost))
565565

566566
# Create Journal Entry for products leaving the company
567567
if self._is_out():
568568
cost = -1 * cost
569569
if self._is_returned(valued_type='out'):
570-
am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
570+
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))
571571
else:
572572
am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost))
573573

@@ -581,10 +581,10 @@ def _account_entry_move(self, qty, description, svl_id, cost):
581581
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost))
582582
elif self._is_dropshipped_returned():
583583
if cost > 0:
584-
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost))
584+
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))
585585
else:
586586
cost = -1 * cost
587-
am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost))
587+
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))
588588

589589
return am_vals
590590

addons/stock_account/tests/test_account_move.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
55
from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
66
from odoo.tests.common import tagged, Form
7-
7+
from odoo import fields
88

99
class TestAccountMoveStockCommon(AccountTestInvoicingCommon):
1010
@classmethod
@@ -117,3 +117,29 @@ def test_average_perpetual_01_mc_01(self):
117117
self.assertEqual(len(invoice.mapped("line_ids")), 4)
118118
self.assertEqual(len(invoice.mapped("line_ids").filtered(lambda l: l.display_type == 'cogs')), 2)
119119
self.assertEqual(len(invoice.mapped("line_ids.currency_id")), 2)
120+
121+
def test_storno_accounting(self):
122+
"""Storno accounting uses negative numbers on debit/credit to cancel other moves.
123+
This test checks that we do the same for the anglosaxon lines when storno is enabled.
124+
"""
125+
self.env.company.account_storno = True
126+
self.env.company.anglo_saxon_accounting = True
127+
128+
move = self.env['account.move'].create({
129+
'move_type': 'out_refund',
130+
'invoice_date': fields.Date.from_string('2019-01-01'),
131+
'partner_id': self.partner_a.id,
132+
'currency_id': self.currency_data['currency'].id,
133+
'invoice_line_ids': [
134+
(0, None, {'product_id': self.product_A.id}),
135+
]
136+
})
137+
move.action_post()
138+
139+
stock_output_line = move.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
140+
self.assertEqual(stock_output_line.debit, 0)
141+
self.assertEqual(stock_output_line.credit, -10)
142+
143+
expense_line = move.line_ids.filtered(lambda l: l.account_id == self.product_A.property_account_expense_id)
144+
self.assertEqual(expense_line.debit, -10)
145+
self.assertEqual(expense_line.credit, 0)

addons/stock_account/tests/test_stockvaluationlayer.py

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ def test_standard_auto_to_manual_2(self):
10081008
self.assertEqual(len(self.product1.stock_valuation_layer_ids), 3)
10091009

10101010
@tagged('post_install', '-at_install')
1011-
class TestAngloSaxonAccounting(AccountTestInvoicingCommon):
1011+
class TestAngloSaxonAccounting(AccountTestInvoicingCommon, TestStockValuationCommon):
10121012
@classmethod
10131013
def setUpClass(cls, chart_template_ref=None):
10141014
super().setUpClass(chart_template_ref=chart_template_ref)
@@ -1089,38 +1089,6 @@ def setUpClass(cls, chart_template_ref=None):
10891089
'property_stock_journal': cls.company_data['default_journal_misc'].id,
10901090
})
10911091

1092-
def _make_in_move(self, product, quantity, unit_cost=None, create_picking=False, loc_dest=None, pick_type=None):
1093-
""" Helper to create and validate a receipt move.
1094-
"""
1095-
unit_cost = unit_cost or product.standard_price
1096-
loc_dest = loc_dest or self.stock_location
1097-
pick_type = pick_type or self.picking_type_in
1098-
in_move = self.env['stock.move'].create({
1099-
'name': 'in %s units @ %s per unit' % (str(quantity), str(unit_cost)),
1100-
'product_id': product.id,
1101-
'location_id': self.supplier_location.id,
1102-
'location_dest_id': loc_dest.id,
1103-
'product_uom': self.uom_unit.id,
1104-
'product_uom_qty': quantity,
1105-
'price_unit': unit_cost,
1106-
'picking_type_id': pick_type.id,
1107-
})
1108-
1109-
if create_picking:
1110-
picking = self.env['stock.picking'].create({
1111-
'picking_type_id': in_move.picking_type_id.id,
1112-
'location_id': in_move.location_id.id,
1113-
'location_dest_id': in_move.location_dest_id.id,
1114-
})
1115-
in_move.write({'picking_id': picking.id})
1116-
1117-
in_move._action_confirm()
1118-
in_move._action_assign()
1119-
in_move.move_line_ids.qty_done = quantity
1120-
in_move._action_done()
1121-
1122-
return in_move.with_context(svl=True)
1123-
11241092
def test_avco_and_credit_note(self):
11251093
"""
11261094
When reversing an invoice that contains some anglo-saxo AML, the new anglo-saxo AML should have the same value
@@ -1160,3 +1128,29 @@ def test_avco_and_credit_note(self):
11601128
self.assertEqual(len(anglo_lines), 2)
11611129
self.assertEqual(abs(anglo_lines[0].balance), 10)
11621130
self.assertEqual(abs(anglo_lines[1].balance), 10)
1131+
1132+
def test_return_delivery_storno(self):
1133+
""" When using STORNO accounting, reverse accounting moves should have negative values for credit/debit.
1134+
"""
1135+
self.env.company.account_storno = True
1136+
self.product1.categ_id.property_cost_method = 'fifo'
1137+
1138+
self._make_in_move(self.product1, 10, unit_cost=10)
1139+
out_move = self._make_out_move(self.product1, 10, create_picking=True)
1140+
return_move = self._make_return(out_move, 10)
1141+
1142+
valuation_line = out_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_valuation_account)
1143+
stock_out_line = out_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
1144+
1145+
self.assertEqual(valuation_line.credit, 100)
1146+
self.assertEqual(valuation_line.debit, 0)
1147+
self.assertEqual(stock_out_line.credit, 0)
1148+
self.assertEqual(stock_out_line.debit, 100)
1149+
1150+
valuation_line = return_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_valuation_account)
1151+
stock_out_line = return_move.account_move_ids.line_ids.filtered(lambda l: l.account_id == self.stock_output_account)
1152+
1153+
self.assertEqual(valuation_line.credit, -100)
1154+
self.assertEqual(valuation_line.debit, 0)
1155+
self.assertEqual(stock_out_line.credit, 0)
1156+
self.assertEqual(stock_out_line.debit, -100)

0 commit comments

Comments
 (0)