# Copyright 2018-21 ForgeFlow S.L. (https://www.forgeflow.com) # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError class MrpInventoryProcure(models.TransientModel): _name = "mrp.inventory.procure" _description = "Make Procurements from MRP inventory projections" item_ids = fields.One2many( comodel_name="mrp.inventory.procure.item", inverse_name="wiz_id", string="Items" ) @api.model def _prepare_item(self, planned_order): return { "planned_order_id": planned_order.id, "qty": planned_order.mrp_qty - planned_order.qty_released, "uom_id": planned_order.mrp_inventory_id.uom_id.id, "date_planned": planned_order.due_date, "mrp_inventory_id": planned_order.mrp_inventory_id.id, "product_id": planned_order.product_id.id, "warehouse_id": planned_order.mrp_area_id.warehouse_id.id, "location_id": planned_order.product_mrp_area_id.location_proc_id.id or planned_order.mrp_area_id.location_id.id, "supply_method": planned_order.product_mrp_area_id.supply_method, } @api.model def fields_view_get( self, view_id=None, view_type="form", toolbar=False, submenu=False ): if self.user_has_groups("mrp_multi_level.group_change_mrp_procure_qty"): view_id = self.env.ref( "mrp_multi_level.view_mrp_inventory_procure_wizard" ).id else: view_id = self.env.ref( "mrp_multi_level.view_mrp_inventory_procure_without_security" ).id return super().fields_view_get( view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu ) @api.model def default_get(self, fields): res = super().default_get(fields) active_ids = self.env.context["active_ids"] or [] active_model = self.env.context["active_model"] if not active_ids or "item_ids" not in fields: return res items = item_obj = self.env["mrp.inventory.procure.item"] if active_model == "mrp.inventory": mrp_inventory_obj = self.env[active_model] for line in mrp_inventory_obj.browse(active_ids).mapped( "planned_order_ids" ): if line.qty_released < line.mrp_qty: items += item_obj.create(self._prepare_item(line)) elif active_model == "mrp.planned.order": mrp_planned_order_obj = self.env[active_model] for line in mrp_planned_order_obj.browse(active_ids): if line.qty_released < line.mrp_qty: items += item_obj.create(self._prepare_item(line)) if items: res["item_ids"] = [(6, 0, items.ids)] return res def make_procurement(self): self.ensure_one() errors = [] pg = self.env["procurement.group"] procurements = [] for item in self.item_ids: if not item.qty: raise ValidationError(_("Quantity must be positive.")) values = item._prepare_procurement_values() procurements.append( pg.Procurement( item.product_id, item.qty, item.uom_id, item.location_id, "MRP: " + (item.planned_order_id.name or self.env.user.login), "MRP: " + (item.planned_order_id.origin or self.env.user.login), item.mrp_inventory_id.company_id, values, ) ) # Run procurements try: pg.run(procurements) for item in self.item_ids: item.planned_order_id.qty_released += item.qty except UserError as error: errors.append(error.name) if errors: raise UserError("\n".join(errors)) return {"type": "ir.actions.act_window_close"} class MrpInventoryProcureItem(models.TransientModel): _name = "mrp.inventory.procure.item" _description = "MRP Inventory procure item" wiz_id = fields.Many2one( comodel_name="mrp.inventory.procure", string="Wizard", ondelete="cascade", readonly=True, ) qty = fields.Float(string="Quantity") uom_id = fields.Many2one(string="Unit of Measure", comodel_name="uom.uom") date_planned = fields.Date(string="Planned Date", required=True) mrp_inventory_id = fields.Many2one( string="Mrp Inventory", comodel_name="mrp.inventory" ) planned_order_id = fields.Many2one(comodel_name="mrp.planned.order") product_id = fields.Many2one(string="Product", comodel_name="product.product") warehouse_id = fields.Many2one(string="Warehouse", comodel_name="stock.warehouse") location_id = fields.Many2one(string="Location", comodel_name="stock.location") supply_method = fields.Selection( selection=[ ("buy", "Buy"), ("none", "Undefined"), ("manufacture", "Produce"), ("pull", "Pull From"), ("push", "Push To"), ("pull_push", "Pull & Push"), ], readonly=True, ) def _prepare_procurement_values(self, group=False): return { "date_planned": self.date_planned, "warehouse_id": self.warehouse_id, "group_id": group, "planned_order_id": self.planned_order_id.id, } @api.onchange("uom_id") def onchange_uom_id(self): for rec in self: rec.qty = rec.mrp_inventory_id.uom_id._compute_quantity( rec.mrp_inventory_id.to_procure, rec.uom_id )