From c9b1f1c9329fc9d52b1eebcba07ce3506c82883d Mon Sep 17 00:00:00 2001 From: MerlinGuillaume Date: Fri, 9 Dec 2022 10:59:45 +0000 Subject: [PATCH] [FIX] (purchase_)stock(_dropshipping): move partner depends on picking partner Stock moves don't have a `partner_id` if they are created before setting the picking's `partner_id` Steps to reproduce (from v15): 1. Create a new transfer with operation type 'Delivery Orders' 2. Add a move, then a delivery address and save 3. Mark as todo and validate 4. Print the delivery slip 5. The warehouse address is printed but it should be the delivery address Solution: Replace `onchange_partner_id` of `stock.picking` by a compute method in `stock.move`. It assigns the partner_id of the `stock.move` to its picking's partner_id if the move is part of the picking's `move_ids_without_package` (in purchase_stock, also check that it is not a dropshipping) Problem: When creating a picking, its moves' `partner_id` is only set if the picking's `partner_id` was already set in the form opw-3091139 closes odoo/odoo#107625 Signed-off-by: Tiffany Chang --- addons/purchase_stock/models/stock_move.py | 5 ++ addons/stock/models/stock_move.py | 8 ++- addons/stock/models/stock_picking.py | 9 ---- .../stock_dropshipping/tests/test_dropship.py | 52 +++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/addons/purchase_stock/models/stock_move.py b/addons/purchase_stock/models/stock_move.py index 0bad8336972..b2ca8785ffc 100644 --- a/addons/purchase_stock/models/stock_move.py +++ b/addons/purchase_stock/models/stock_move.py @@ -26,6 +26,11 @@ class StockMove(models.Model): def _prepare_merge_negative_moves_excluded_distinct_fields(self): return super()._prepare_merge_negative_moves_excluded_distinct_fields() + ['created_purchase_line_id'] + def _compute_partner_id(self): + # dropshipped moves should have their partner_ids directly set + not_dropshipped_moves = self.filtered(lambda m: not m._is_dropshipped()) + super(StockMove, not_dropshipped_moves)._compute_partner_id() + def _get_price_unit(self): """ Returns the unit price for the move""" self.ensure_one() diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index e6f9cd6c901..454924dba55 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -85,7 +85,8 @@ class StockMove(models.Model): partner_id = fields.Many2one( 'res.partner', 'Destination Address ', states={'done': [('readonly', True)]}, - help="Optional address where goods are to be delivered, specifically used for allotment") + help="Optional address where goods are to be delivered, specifically used for allotment", + compute='_compute_partner_id', store=True, readonly=False) move_dest_ids = fields.Many2many( 'stock.move', 'stock_move_move_rel', 'move_orig_id', 'move_dest_id', 'Destination Moves', copy=False, @@ -299,6 +300,11 @@ class StockMove(models.Model): move.product_qty = move.product_uom._compute_quantity( move.product_uom_qty, move.product_id.uom_id, rounding_method='HALF-UP') + @api.depends('picking_id.partner_id') + def _compute_partner_id(self): + for move in self.filtered(lambda m: m.picking_id): + move.partner_id = move.picking_id.partner_id + def _get_move_lines(self): """ This will return the move lines to consider when applying _quantity_done_compute on a stock.move. In some context, such as MRP, it is necessary to compute quantity_done on filtered sock.move.line.""" diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 79d67ffb4ba..79730a6ab77 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -709,15 +709,6 @@ class Picking(models.Model): late_stock_moves = self.env['stock.move'].search([('delay_alert_date', operator, value)]) return [('move_ids', 'in', late_stock_moves.ids)] - @api.onchange('partner_id') - def onchange_partner_id(self): - for picking in self: - picking_id = isinstance(picking.id, int) and picking.id or getattr(picking, '_origin', False) and picking._origin.id - if picking_id: - moves = self.env['stock.move'].search([('picking_id', '=', picking_id)]) - for move in moves: - move.write({'partner_id': picking.partner_id.id}) - @api.onchange('picking_type_id', 'partner_id') def _onchange_picking_type(self): if self.picking_type_id and self.state == 'draft': diff --git a/addons/stock_dropshipping/tests/test_dropship.py b/addons/stock_dropshipping/tests/test_dropship.py index 26fdd077d3c..645fa43a748 100644 --- a/addons/stock_dropshipping/tests/test_dropship.py +++ b/addons/stock_dropshipping/tests/test_dropship.py @@ -130,3 +130,55 @@ class TestDropship(common.TransactionCase): ('location_dest_id', '=', self.env.ref('stock.stock_location_customers').id), ('product_id', '=', drop_shop_product.id)]) self.assertEqual(len(move_line.ids), 1, 'There should be exactly one move line') + + def test_sale_order_picking_partner(self): + """ Test that the partner is correctly set on the picking and the move when the product is dropshipped or not.""" + + # Create a vendor and a customer + supplier_dropship = self.env['res.partner'].create({'name': 'Vendor'}) + customer = self.env['res.partner'].create({'name': 'Customer'}) + + # Create new product without any routes + super_product = self.env['product.product'].create({ + 'name': "Super product", + 'seller_ids': [(0, 0, { + 'partner_id': supplier_dropship.id, + })], + }) + + # Create a sale order + so_form = Form(self.env['sale.order']) + so_form.partner_id = customer + with so_form.order_line.new() as line: + line.product_id = super_product + sale_order = so_form.save() + + # Confirm sale order + sale_order.action_confirm() + + # Check the partner of the related picking and move + self.assertEqual(sale_order.picking_ids.partner_id, customer) + self.assertEqual(sale_order.picking_ids.move_ids.partner_id, customer) + + # Add a dropship route to the product + super_product.route_ids = [self.env.ref('stock_dropshipping.route_drop_shipping').id] + + # Create a sale order + so_form = Form(self.env['sale.order']) + so_form.partner_id = customer + with so_form.order_line.new() as line: + line.product_id = super_product + sale_order = so_form.save() + + # Confirm sale order + sale_order.action_confirm() + + # Check a quotation was created to a certain vendor and confirm it, so it becomes a confirmed purchase order + purchase = self.env['purchase.order'].search([('partner_id', '=', supplier_dropship.id)]) + self.assertTrue(purchase, "an RFQ should have been created by the scheduler") + purchase.button_confirm() + self.assertEqual(purchase.state, 'purchase', 'Purchase order should be in the approved state') + + # Check the partner of the related picking and move + self.assertEqual(sale_order.picking_ids.partner_id, supplier_dropship) + self.assertEqual(sale_order.picking_ids.move_ids.partner_id, customer)