From 5acaa73fae546ebf329ce6d49b493419c99db479 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 25 Nov 2021 18:50:47 +0100 Subject: [PATCH] sale_order_add_bom: add kit wizard now available on pickings --- sale_order_add_bom/__manifest__.py | 5 +- .../{sale_view.xml => views/sale_order.xml} | 3 +- sale_order_add_bom/views/stock_picking.xml | 24 +++++++++ .../wizard/sale_add_phantom_bom.py | 49 +++++++++++++++---- .../wizard/sale_add_phantom_bom_view.xml | 2 +- 5 files changed, 70 insertions(+), 13 deletions(-) rename sale_order_add_bom/{sale_view.xml => views/sale_order.xml} (83%) create mode 100644 sale_order_add_bom/views/stock_picking.xml diff --git a/sale_order_add_bom/__manifest__.py b/sale_order_add_bom/__manifest__.py index b5a5373..c9280e8 100644 --- a/sale_order_add_bom/__manifest__.py +++ b/sale_order_add_bom/__manifest__.py @@ -11,6 +11,8 @@ 'description': """ This module adds a wizard *Add Kit* on the form view of a quotation that allows the user to select a 'kit' BOM: Odoo will automatically add the components of the kit as sale order lines. +The wizard *Add Kit* is also available on a draft picking. + This module has been written by Alexis de Lattre from Akretion . """, @@ -19,7 +21,8 @@ This module has been written by Alexis de Lattre from Akretion 'depends': ['sale', 'mrp'], 'data': [ 'wizard/sale_add_phantom_bom_view.xml', - 'sale_view.xml', + 'views/sale_order.xml', + 'views/stock_picking.xml', ], 'installable': True, } diff --git a/sale_order_add_bom/sale_view.xml b/sale_order_add_bom/views/sale_order.xml similarity index 83% rename from sale_order_add_bom/sale_view.xml rename to sale_order_add_bom/views/sale_order.xml index d38a017..18c8861 100644 --- a/sale_order_add_bom/sale_view.xml +++ b/sale_order_add_bom/views/sale_order.xml @@ -1,6 +1,7 @@ diff --git a/sale_order_add_bom/views/stock_picking.xml b/sale_order_add_bom/views/stock_picking.xml new file mode 100644 index 0000000..a316306 --- /dev/null +++ b/sale_order_add_bom/views/stock_picking.xml @@ -0,0 +1,24 @@ + + + + + + + + add.bom.stock.picking.form + stock.picking + + + + + + + + diff --git a/sale_order_add_bom/wizard/sale_add_phantom_bom.py b/sale_order_add_bom/wizard/sale_add_phantom_bom.py index 801836b..58937b5 100644 --- a/sale_order_add_bom/wizard/sale_add_phantom_bom.py +++ b/sale_order_add_bom/wizard/sale_add_phantom_bom.py @@ -12,19 +12,26 @@ class SaleAddPhantomBom(models.TransientModel): _description = 'Add Kit to Quotation' @api.model - def _default_sale_id(self): - assert self._context.get('active_model') == 'sale.order' - return self.env['sale.order'].browse(self._context['active_id']) + def default_get(self, fields_list): + res = super(SaleAddPhantomBom, self).default_get(fields_list) + if self._context.get('active_model') == 'sale.order': + res['sale_id'] = self._context['active_id'] + elif self._context.get('active_model') == 'stock.picking': + res['picking_id'] = self._context['active_id'] + else: + raise UserError(_( + "The wizard can only be started from a sale order or a picking.")) + return res bom_id = fields.Many2one( 'mrp.bom', 'Kit', required=True, domain=[('type', '=', 'phantom'), ('sale_ok', '=', True)]) qty = fields.Integer( string='Number of Kits to Add', default=1, required=True) - # I can 't put the sale_id fields required=True because - # it may block the deletion of a sale order sale_id = fields.Many2one( - 'sale.order', string='Quotation', default=_default_sale_id) + 'sale.order', string='Quotation') + picking_id = fields.Many2one( + 'stock.picking', string='Picking') @api.model def _prepare_sale_order_line(self, bom_line, sale_order, wizard_qty): @@ -36,12 +43,30 @@ class SaleAddPhantomBom(models.TransientModel): 'product_uom_qty': qty_in_product_uom * wizard_qty, 'order_id': sale_order.id, } + # on sale.order.line, company_id is a related field + return vals + + @api.model + def _prepare_stock_move(self, bom_line, picking, wizard_qty): + product = bom_line.product_id + qty_in_product_uom = bom_line.product_uom_id._compute_quantity( + bom_line.product_qty, product.uom_id) + vals = { + 'product_id': product.id, + 'product_uom_qty': qty_in_product_uom * wizard_qty, + 'product_uom': product.uom_id.id, + 'picking_id': picking.id, + 'company_id': picking.company_id.id, + 'location_id': picking.location_id.id, + 'location_dest_id': picking.location_dest_id.id, + 'name': product.partner_ref, + } return vals @api.multi def add(self): self.ensure_one() - assert self.sale_id, 'No related sale_id' + assert self.sale_id or self.picking_id, 'No related sale_id or picking_id' if self.qty < 1: raise UserError(_( "The number of kits to add must be 1 or superior")) @@ -50,8 +75,8 @@ class SaleAddPhantomBom(models.TransientModel): raise UserError(_("The selected kit is empty !")) prec = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') - today = fields.Date.context_today(self) solo = self.env['sale.order.line'] + smo = self.env['stock.move'] for line in self.bom_id.bom_line_ids: if float_is_zero(line.product_qty, precision_digits=prec): continue @@ -59,6 +84,10 @@ class SaleAddPhantomBom(models.TransientModel): # of sale order line in the 'sale' module # TODO: if needed, we could increment existing order lines # with the same product instead of always creating new lines - vals = self._prepare_sale_order_line(line, self.sale_id, self.qty) - solo.create(vals) + if self.sale_id: + vals = self._prepare_sale_order_line(line, self.sale_id, self.qty) + solo.create(vals) + elif self.picking_id: + vals = self._prepare_stock_move(line, self.picking_id, self.qty) + smo.create(vals) return True diff --git a/sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml b/sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml index 4899d0f..82e1af3 100644 --- a/sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml +++ b/sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml @@ -18,7 +18,7 @@