[REF] stock_account: dropshipping valuation
We standardize the dropshipping by handling it as it was an receipt directly followed by an out. We also follow the same logic whatever the cost method, ie we don't run fifo or update the AVCO. task-1875873
This commit is contained in:
@@ -240,6 +240,52 @@ class StockMove(models.Model):
|
||||
svl_vals_list.append(svl_vals)
|
||||
return self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
|
||||
def _create_dropshipped_svl(self, forced_quantity=None):
|
||||
"""Create a `stock.valuation.layer` from `self`.
|
||||
|
||||
:param forced_quantity: under some circunstances, the quantity to value is different than
|
||||
the initial demand of the move (Default value = None)
|
||||
"""
|
||||
svl_vals_list = []
|
||||
for move in self:
|
||||
valued_move_lines = move.move_line_ids
|
||||
valued_quantity = 0
|
||||
for valued_move_line in valued_move_lines:
|
||||
valued_quantity += valued_move_line.product_uom_id._compute_quantity(valued_move_line.qty_done, move.product_id.uom_id)
|
||||
quantity = forced_quantity or valued_quantity
|
||||
|
||||
unit_cost = move._get_price_unit()
|
||||
if move.product_id.cost_method == 'standard':
|
||||
unit_cost = move.product_id.standard_price
|
||||
|
||||
common_vals = dict(move._prepare_common_svl_vals(), remaining_qty=0)
|
||||
|
||||
# create the in
|
||||
in_vals = {
|
||||
'unit_cost': unit_cost,
|
||||
'value': unit_cost * quantity,
|
||||
'quantity': quantity,
|
||||
}
|
||||
in_vals.update(common_vals)
|
||||
svl_vals_list.append(in_vals)
|
||||
|
||||
# create the out
|
||||
out_vals = {
|
||||
'unit_cost': unit_cost,
|
||||
'value': unit_cost * quantity * -1,
|
||||
'quantity': quantity * -1,
|
||||
}
|
||||
out_vals.update(common_vals)
|
||||
svl_vals_list.append(out_vals)
|
||||
return self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
|
||||
def _create_dropshipped_returned_svl(self, forced_quantity=None):
|
||||
"""Create a `stock.valuation.layer` from `self`.
|
||||
|
||||
:param forced_quantity: under some circunstances, the quantity to value is different than
|
||||
the initial demand of the move (Default value = None)
|
||||
"""
|
||||
return self._create_dropshipped_svl(forced_quantity=forced_quantity)
|
||||
|
||||
@api.model
|
||||
def _run_fifo(self, move, quantity=None):
|
||||
@@ -734,9 +780,21 @@ class StockMove(models.Model):
|
||||
# Creates an account entry from stock_input to stock_output on a dropship move. https://github.com/odoo/odoo/issues/12687
|
||||
journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation()
|
||||
if self._is_dropshipped():
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_src, acc_dest, journal_id)
|
||||
value = self.env.context.get('force_valuation_amount')
|
||||
if value > 0:
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_src, acc_valuation, journal_id)
|
||||
else:
|
||||
force_valuation_amount = self.env.context['force_valuation_amount']
|
||||
self.env.context = dict(self.env.context, force_valuation_amount=-1*force_valuation_amount)
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_valuation, acc_dest, journal_id)
|
||||
elif self._is_dropshipped_returned():
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_dest, acc_src, journal_id)
|
||||
value = self.env.context.get('force_valuation_amount')
|
||||
if value > 0:
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_valuation, acc_src, journal_id)
|
||||
else:
|
||||
force_valuation_amount = self.env.context['force_valuation_amount']
|
||||
self.env.context = dict(self.env.context, force_valuation_amount=-1*force_valuation_amount)
|
||||
self.with_context(force_company=self.company_id.id)._create_account_move_line(acc_dest, acc_valuation, journal_id)
|
||||
|
||||
if self.company_id.anglo_saxon_accounting:
|
||||
#eventually reconcile together the invoice and valuation accounting entries on the stock interim accounts
|
||||
|
||||
@@ -110,6 +110,10 @@ class StockMoveLine(models.Model):
|
||||
stock_valuation_layers |= move._create_in_svl(forced_quantity=abs(diff))
|
||||
elif move._is_in() and diff < 0 or move._is_out() and diff > 0:
|
||||
stock_valuation_layers |= move._create_out_svl(forced_quantity=abs(diff))
|
||||
elif move._is_dropshipped() and diff > 0 or move._is_dropshipped_returned() and diff < 0:
|
||||
stock_valuation_layers |= move._create_dropshipped_svl(forced_quantity=abs(diff))
|
||||
elif move._is_dropshipped() and diff < 0 or move._is_dropshipped_returned() and diff > 0:
|
||||
stock_valuation_layers |= move._create_dropshipped_returned_svl(forced_quantity=abs(diff))
|
||||
|
||||
for stock_valuation_layer in stock_valuation_layers:
|
||||
if not stock_valuation_layer.product_id.valuation == 'real_time':
|
||||
|
||||
@@ -2276,7 +2276,6 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertAlmostEqual(self.product1.quantity_svl, 25)
|
||||
self.assertAlmostEqual(self.product1.value_svl, 350)
|
||||
|
||||
@skip('need to implement dropship')
|
||||
def test_average_perpetual_8(self):
|
||||
""" Receive 1@10, then dropship 1@20, finally return the dropship. Dropship should not
|
||||
impact the price.
|
||||
|
||||
@@ -96,6 +96,24 @@ class TestStockValuationCommon(SavepointCase):
|
||||
self.days += 1
|
||||
return out_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.unit_cost = 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'))
|
||||
@@ -215,6 +233,33 @@ class TestStockValuationStandard(TestStockValuationCommon):
|
||||
self.assertEqual(self.product1.value_svl, 50)
|
||||
self.assertEqual(self.product1.quantity_svl, 5)
|
||||
|
||||
def test_dropship_1(self):
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'manual_periodic'
|
||||
|
||||
move1 = self._make_dropship_move(self.product1, 10)
|
||||
|
||||
valuation_layers = self.product1.stock_valuation_layer_ids
|
||||
self.assertEqual(len(valuation_layers), 2)
|
||||
self.assertEqual(valuation_layers[0].value, 100)
|
||||
self.assertEqual(valuation_layers[1].value, -100)
|
||||
self.assertEqual(self.product1.value_svl, 0)
|
||||
self.assertEqual(self.product1.quantity_svl, 0)
|
||||
|
||||
def test_change_in_past_increase_dropship_1(self):
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'manual_periodic'
|
||||
|
||||
move1 = self._make_dropship_move(self.product1, 10)
|
||||
move1.move_line_ids.with_context(svl=True).qty_done = 15
|
||||
|
||||
valuation_layers = self.product1.stock_valuation_layer_ids
|
||||
self.assertEqual(len(valuation_layers), 4)
|
||||
self.assertEqual(valuation_layers[0].value, 100)
|
||||
self.assertEqual(valuation_layers[1].value, -100)
|
||||
self.assertEqual(valuation_layers[2].value, 50)
|
||||
self.assertEqual(valuation_layers[3].value, -50)
|
||||
self.assertEqual(self.product1.value_svl, 0)
|
||||
self.assertEqual(self.product1.quantity_svl, 0)
|
||||
|
||||
|
||||
class TestStockValuationAVCO(TestStockValuationCommon):
|
||||
def setUp(self):
|
||||
@@ -381,6 +426,15 @@ class TestStockValuationAVCO(TestStockValuationCommon):
|
||||
self.assertEqual(self.product1.standard_price, 15)
|
||||
self.assertEqual(sum(self.product1.stock_valuation_layer_ids.mapped('remaining_qty')), 1)
|
||||
|
||||
def test_dropship_1(self):
|
||||
move1 = self._make_in_move(self.product1, 1, unit_cost=10)
|
||||
move2 = self._make_in_move(self.product1, 1, unit_cost=20)
|
||||
move3 = self._make_dropship_move(self.product1, 1, unit_cost=10)
|
||||
|
||||
self.assertEqual(self.product1.value_svl, 30)
|
||||
self.assertEqual(self.product1.quantity_svl, 2)
|
||||
self.assertEqual(self.product1.standard_price, 15)
|
||||
|
||||
|
||||
class TestStockValuationFIFO(TestStockValuationCommon):
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user