[FIX] stock_account: correct accounts for dropship return

Before this commit:
When returning a dropshipping, the valuation layers created do not have
the correct accounts on it:
 - Valuation -> Input   for the first SVL
 - Output -> Valuation  for the second SVL

After this commit:
For a dropshipped move, valuation layers have the following chain
of accounts:
 - Input -> Valuation   for the first SVL
 - Valuation -> Output  for the second SVL
Therefore, the return should have it reversed:
 - Output -> Valuation  for the first SVL
 - Valuation -> Input   for the second SVL

Steps to reproduce:
1. Create a dropship product with automated inventory valuation
2. Create a Sales Order, go on the PO and confirm it
3. Set quantities and validate dropshipping
4. Return delivered product (dropship return)

opw-3391174

closes odoo/odoo#137497

X-original-commit: 3e2421982c229af44aa0f46dfd91bcff3fd729a0
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
Signed-off-by: Walravens Mathieu (wama) <wama@odoo.com>
This commit is contained in:
Mathieu Walravens
2023-10-04 19:40:26 +00:00
parent 490915effe
commit c46ed8af92
2 changed files with 151 additions and 2 deletions
+4 -2
View File
@@ -576,11 +576,13 @@ class StockMove(models.Model):
cost = -1 * cost
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:
if cost > 0 and self.location_dest_id._should_be_valued():
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))
elif cost > 0:
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))
else:
cost = -1 * 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))
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))
return am_vals
@@ -1137,6 +1137,67 @@ class TestAngloSaxonAccounting(AccountTestInvoicingCommon, TestStockValuationCom
'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 _make_dropship_move(self, product, quantity, unit_cost=None):
dropshipped = self.env['stock.move'].create({
'name': 'dropship %s units' % str(quantity),
'product_id': product.id,
'location_id': self.supplier_location.id,
'location_dest_id': self.customer_location.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': quantity,
'picking_type_id': self.picking_type_out.id,
})
if unit_cost:
dropshipped.price_unit = unit_cost
dropshipped._action_confirm()
dropshipped._action_assign()
dropshipped.move_line_ids.qty_done = quantity
dropshipped._action_done()
return dropshipped
def _make_return(self, move, quantity_to_return):
stock_return_picking = Form(self.env['stock.return.picking']\
.with_context(active_ids=[move.picking_id.id], active_id=move.picking_id.id, active_model='stock.picking'))
stock_return_picking = stock_return_picking.save()
stock_return_picking.product_return_moves.quantity = quantity_to_return
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.move_ids[0].move_line_ids[0].qty_done = quantity_to_return
return_pick._action_done()
return return_pick.move_ids
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
@@ -1201,3 +1262,89 @@ class TestAngloSaxonAccounting(AccountTestInvoicingCommon, TestStockValuationCom
self.assertEqual(valuation_line.debit, 0)
self.assertEqual(stock_out_line.credit, 0)
self.assertEqual(stock_out_line.debit, -100)
def test_dropship_return_accounts_1(self):
"""
When returning a dropshipped move, make sure the correct accounts are used
"""
# pylint: disable=bad-whitespace
self.product1.categ_id.property_cost_method = 'fifo'
move1 = self._make_dropship_move(self.product1, 2, unit_cost=10)
move2 = self._make_return(move1, 2)
# First: Input -> Valuation
# Second: Valuation -> Output
origin_svls = move1.stock_valuation_layer_ids.sorted('quantity', reverse=True)
# First: Output -> Valuation
# Second: Valuation -> Input
return_svls = move2.stock_valuation_layer_ids.sorted('quantity', reverse=True)
self.assertEqual(len(origin_svls), 2)
self.assertEqual(len(return_svls), 2)
acc_in, acc_out, acc_valuation = self.stock_input_account, self.stock_output_account, self.stock_valuation_account
# Dropshipping should be: Input -> Output
self.assertRecordValues(origin_svls[0].account_move_id.line_ids, [
{'account_id': acc_in.id, 'debit': 0, 'credit': 20},
{'account_id': acc_valuation.id, 'debit': 20, 'credit': 0},
])
self.assertRecordValues(origin_svls[1].account_move_id.line_ids, [
{'account_id': acc_valuation.id, 'debit': 0, 'credit': 20},
{'account_id': acc_out.id, 'debit': 20, 'credit': 0},
])
# Return should be: Output -> Input
self.assertRecordValues(return_svls[0].account_move_id.line_ids, [
{'account_id': acc_out.id, 'debit': 0, 'credit': 20},
{'account_id': acc_valuation.id, 'debit': 20, 'credit': 0},
])
self.assertRecordValues(return_svls[1].account_move_id.line_ids, [
{'account_id': acc_valuation.id, 'debit': 0, 'credit': 20},
{'account_id': acc_in.id, 'debit': 20, 'credit': 0},
])
def test_dropship_return_accounts_2(self):
"""
When returning a dropshipped move, make sure the correct accounts are used
"""
# pylint: disable=bad-whitespace
self.product1.categ_id.property_cost_method = 'fifo'
move1 = self._make_dropship_move(self.product1, 2, unit_cost=10)
# return to WH/Stock
stock_return_picking = Form(self.env['stock.return.picking']\
.with_context(active_ids=[move1.picking_id.id], active_id=move1.picking_id.id, active_model='stock.picking'))
stock_return_picking = stock_return_picking.save()
stock_return_picking.product_return_moves.quantity = 2
stock_return_picking.location_id = self.stock_location
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.move_ids[0].move_line_ids[0].qty_done = 2
return_pick._action_done()
move2 = return_pick.move_ids
# First: Input -> Valuation
# Second: Valuation -> Output
origin_svls = move1.stock_valuation_layer_ids.sorted('quantity', reverse=True)
# Only one: Output -> Valuation
return_svl = move2.stock_valuation_layer_ids
self.assertEqual(len(origin_svls), 2)
self.assertEqual(len(return_svl), 1)
acc_in, acc_out, acc_valuation = self.stock_input_account, self.stock_output_account, self.stock_valuation_account
# Dropshipping should be: Input -> Output
self.assertRecordValues(origin_svls[0].account_move_id.line_ids, [
{'account_id': acc_in.id, 'debit': 0, 'credit': 20},
{'account_id': acc_valuation.id, 'debit': 20, 'credit': 0},
])
self.assertRecordValues(origin_svls[1].account_move_id.line_ids, [
{'account_id': acc_valuation.id, 'debit': 0, 'credit': 20},
{'account_id': acc_out.id, 'debit': 20, 'credit': 0},
])
# Return should be: Output -> Valuation
self.assertRecordValues(return_svl.account_move_id.line_ids, [
{'account_id': acc_out.id, 'debit': 0, 'credit': 20},
{'account_id': acc_valuation.id, 'debit': 20, 'credit': 0},
])