From 4ff8654bcbb2834a0049fff3d5eec5560e54ed0a Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Tue, 23 Aug 2022 11:53:55 +0000 Subject: [PATCH] [FIX] mrp_subcontracting_dropshipping: dropship from PO Confirming a PO with a customer as delivery address does not work To reproduce the issue: 1. In Settings, enable "Multi-Locations" 2. Create two products P_finished, P_compo - P_finished: - Add a vendor V 3. Create a bill of materials: - Product: P_finished - Type: Subcontract - Subcontractor: V - Components: 1 x P_compo 4. Create a PO: - Vendor: V - Products: 1 x P_finished - Deliver To: Dropship - Drop Ship Address: a customer 5. Confirm the PO Error: a validation error is displayed: "[...] a mandatory field is not set. [...] Model: Production Order (mrp.production), Field: Operation Type (picking_type_id)" When confirming the PO, we extract some values of the subcontracted SM to create a MO: https://github.com/odoo/odoo/blob/829369d3ca0530f1aad0599fbb1598810a928cc3/addons/mrp_subcontracting/models/stock_picking.py#L105-L117 However, because the SM is not created from the SO, it does not have any `sale_line_id`. And, because its a dropshipped one, neither the SM nor its picking type has a defined warehouse. As a result, `_get_warehouse` does not return anything and we can't define the `picking_type_id` of the MO. This is the reason why the error will be triggered on its creation. OPW-2922546 closes odoo/odoo#99223 X-original-commit: 28a20daab6a7097ecd26bf66eeb80b2f5ad294a8 Signed-off-by: William Henrotin (whe) Signed-off-by: Adrien Widart --- .../models/stock_picking.py | 12 ++++ .../tests/test_purchase_subcontracting.py | 58 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/addons/mrp_subcontracting_dropshipping/models/stock_picking.py b/addons/mrp_subcontracting_dropshipping/models/stock_picking.py index e4caa83bc5e..4f337a3f039 100644 --- a/addons/mrp_subcontracting_dropshipping/models/stock_picking.py +++ b/addons/mrp_subcontracting_dropshipping/models/stock_picking.py @@ -16,3 +16,15 @@ class StockPicking(models.Model): res = super()._action_done() self.move_ids.move_dest_ids._action_assign() return res + + def _prepare_subcontract_mo_vals(self, subcontract_move, bom): + res = super()._prepare_subcontract_mo_vals(subcontract_move, bom) + if not res.get('picking_type_id') and subcontract_move.location_dest_id.usage == 'customer': + # If the if-condition is respected, it means that `subcontract_move` is not + # related to a specific warehouse. This can happen if, for instance, the user + # confirms a PO with a subcontracted product that should be delivered to a + # customer (dropshipping). In that case, we can use a default warehouse to + # get the picking type + default_warehouse = self.env['stock.warehouse'].search([('company_id', '=', subcontract_move.company_id.id)], limit=1) + res['picking_type_id'] = default_warehouse.subcontracting_type_id.id, + return res diff --git a/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py b/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py index 23cf0958cff..769b9f33070 100644 --- a/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py +++ b/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py @@ -190,3 +190,61 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon): dropship_po = self.env['purchase.order'].search([('partner_id', '=', vendor.id)]) self.assertEqual(dropship_po.dest_address_id, subcontractor) + + def test_po_to_customer(self): + """ + Create and confirm a PO with a subcontracted move. The picking type of + the PO is 'Dropship' and the delivery address a customer. + """ + subcontractor, client = self.env['res.partner'].create([ + {'name': 'SuperSubcontractor'}, + {'name': 'SuperClient'}, + ]) + + p_finished, p_compo = self.env['product.product'].create([{ + 'name': 'Finished Product', + 'type': 'product', + 'seller_ids': [(0, 0, {'partner_id': subcontractor.id})], + }, { + 'name': 'Component', + 'type': 'consu', + }]) + + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': p_finished.product_tmpl_id.id, + 'product_qty': 1, + 'type': 'subcontract', + 'subcontractor_ids': [(6, 0, subcontractor.ids)], + 'bom_line_ids': [ + (0, 0, {'product_id': p_compo.id, 'product_qty': 1}), + ], + }) + + dropship_picking_type = self.env['stock.picking.type'].search([ + ('company_id', '=', self.env.company.id), + ('default_location_src_id.usage', '=', 'supplier'), + ('default_location_dest_id.usage', '=', 'customer'), + ], limit=1, order='sequence') + + po = self.env['purchase.order'].create({ + "partner_id": subcontractor.id, + "picking_type_id": dropship_picking_type.id, + "dest_address_id": client.id, + "order_line": [(0, 0, { + 'product_id': p_finished.id, + 'name': p_finished.name, + 'product_qty': 1.0, + })], + }) + po.button_confirm() + + mo = self.env['mrp.production'].search([('bom_id', '=', bom.id)]) + self.assertEqual(mo.picking_type_id, self.warehouse.subcontracting_type_id) + + delivery = po.picking_ids + delivery.move_line_ids.qty_done = 1.0 + delivery.button_validate() + + self.assertEqual(delivery.state, 'done') + self.assertEqual(mo.state, 'done') + self.assertEqual(po.order_line.qty_received, 1)