From fc61ea4acb3d42a1ec6394970bc59266df671f67 Mon Sep 17 00:00:00 2001 From: yhu-odoo Date: Fri, 2 Jun 2023 09:54:36 +0000 Subject: [PATCH] [FIX] stock_account: valuation layer is zero when return dropshipping To reproduce: 1. Create a Sales Order for a product whose product category is set to FIFO and automated. Use route "dropship". 2. Confirm the PO created. 3. Deliver the products (DS transfer) 4. Create the customer invoice 5. Return, for example, 1 unit of product 6. Add a credit note to the invoice for that 1 unit returned (reset to draft then change qty and post) Issues: The value on the valuation layers of the returned picking is 0, posted entries for COGS and stock interim (delivered) account for credit note is also 0. Since #85751, When create valuation layer for return, we take all svls of origin_returned_move_id into account to calculate the price unit. However, then dropshiping, 2 svls are created for the original move, and the sum of them is 0 since there is no impact of the stock when dropshiping. So when return, the price unit will be calculated as 0. To fix, when calculate price unit for return of dropshiping, we only take non-negative svls into account. Note that we use non-negative ones instead of positive ones because when subcontract dropshiping, additional negative svls will be added for the cost of the components. opw-3283436 closes odoo/odoo#124856 X-original-commit: 1c6c163f72301cab29c2f26021bb1ae6fb20dc7f Signed-off-by: Arnold Moyaux (arm) Signed-off-by: Yuchen Huang (yhu) --- addons/stock_account/models/stock_move.py | 6 ++++- .../tests/test_stockvaluation.py | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/addons/stock_account/models/stock_move.py b/addons/stock_account/models/stock_move.py index 4c905a48d44..cea807ff740 100644 --- a/addons/stock_account/models/stock_move.py +++ b/addons/stock_account/models/stock_move.py @@ -5,7 +5,7 @@ from collections import defaultdict from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import float_is_zero, float_round, OrderedSet +from odoo.tools import float_compare, float_is_zero, float_round, OrderedSet import logging _logger = logging.getLogger(__name__) @@ -46,6 +46,10 @@ class StockMove(models.Model): # If the move is a return, use the original move's price unit. if self.origin_returned_move_id and self.origin_returned_move_id.sudo().stock_valuation_layer_ids: layers = self.origin_returned_move_id.sudo().stock_valuation_layer_ids + # dropshipping create additional positive svl to make sure there is no impact on the stock valuation + # We need to remove them from the computation of the price unit. + if self.origin_returned_move_id._is_dropshipped(): + layers = layers.filtered(lambda l: float_compare(l.value, 0, precision_rounding=l.product_id.uom_id.rounding) <= 0) layers |= layers.stock_valuation_layer_ids quantity = sum(layers.mapped("quantity")) return float_round(sum(layers.mapped("value")) / quantity, precision_digits=precision) if not float_is_zero(quantity, precision_rounding=layers.uom_id.rounding) else 0 diff --git a/addons/stock_dropshipping/tests/test_stockvaluation.py b/addons/stock_dropshipping/tests/test_stockvaluation.py index 87fd49fe113..8af3002f84c 100644 --- a/addons/stock_dropshipping/tests/test_stockvaluation.py +++ b/addons/stock_dropshipping/tests/test_stockvaluation.py @@ -297,3 +297,29 @@ class TestStockValuation(ValuationReconciliationTestCommon): } self._check_results(expected_aml, 4, all_amls_return - all_amls) + + def test_dropship_fifo_return(self): + """Test the return of a dropship order with a product set to FIFO costing + method. The unit price is correctly computed on the return picking svl. + """ + self.env.company.anglo_saxon_accounting = True + self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' + self.product1.product_tmpl_id.invoice_policy = 'order' + + self._dropship_product1() + self.assertTrue(8 in self.purchase_order1.picking_ids.move_ids.stock_valuation_layer_ids.mapped('value')) + self.assertTrue(-8 in self.purchase_order1.picking_ids.move_ids.stock_valuation_layer_ids.mapped('value')) + + # return what we've done + stock_return_picking_form = Form(self.env['stock.return.picking'] + .with_context(active_ids=self.sale_order1.picking_ids.ids, active_id=self.sale_order1.picking_ids.ids[0], + active_model='stock.picking')) + stock_return_picking = stock_return_picking_form.save() + 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 = 1.0 + return_pick._action_done() + + self.assertTrue(8 in return_pick.move_ids.stock_valuation_layer_ids.mapped('value')) + self.assertTrue(-8 in return_pick.move_ids.stock_valuation_layer_ids.mapped('value'))