[10.0][MIG] mrp_production_request

This commit is contained in:
Lois Rilo
2018-01-19 13:57:54 +01:00
parent fd87020b85
commit b1193b9056
16 changed files with 101 additions and 92 deletions

View File

@@ -53,7 +53,7 @@ to set it to *Done* state.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/129/9.0
:target: https://runbot.odoo-community.org/runbot/129/10.0
Known issues / Roadmap
======================

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models

View File

@@ -6,7 +6,7 @@
"summary": "Allows you to use Manufacturing Request as a previous "
"step to Manufacturing Orders for better manufacture "
"planification.",
"version": "9.0.1.0.0",
"version": "10.0.1.0.0",
"category": "Manufacturing",
"website": "https://github.com/OCA/manufacture",
"author": "Eficent,"

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mrp_production_request

View File

@@ -2,7 +2,7 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models
from odoo import fields, models
class MrpProduction(models.Model):
@@ -11,3 +11,9 @@ class MrpProduction(models.Model):
mrp_production_request_id = fields.Many2one(
comodel_name="mrp.production.request",
string="Manufacturing Request", copy=False, readonly=True)
def _generate_finished_moves(self):
move = super(MrpProduction, self)._generate_finished_moves()
mr_proc = self.mrp_production_request_id.procurement_id
if mr_proc and mr_proc.move_dest_id:
move.write({"move_dest_id": mr_proc.move_dest_id.id})

View File

@@ -1,16 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2017-18 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models, _
import openerp.addons.decimal_precision as dp
from openerp.exceptions import UserError
from odoo import api, fields, models, _
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError
class MrpProductionRequest(models.Model):
_name = "mrp.production.request"
_description = "Manufacturing Request"
_inherit = "mail.thread"
_order = "id DESC"
@api.model
def _company_get(self):
@@ -52,9 +53,10 @@ class MrpProductionRequest(models.Model):
@api.onchange('product_id')
def _onchange_product_id(self):
self.product_uom = self.product_id.uom_id
self.product_uom_id = self.product_id.uom_id
self.bom_id = self.env['mrp.bom']._bom_find(
product_id=self.product_id.id, properties=[])
product=self.product_id, company_id=self.company_id.id,
picking_type=self.picking_type_id)
@api.model
def _get_mo_valid_states(self):
@@ -122,26 +124,26 @@ class MrpProductionRequest(models.Model):
related='product_id.product_tmpl_id')
product_qty = fields.Float(
string="Required Quantity", required=True, track_visibility='onchange',
digits_compute=dp.get_precision('Product Unit of Measure'),
digits=dp.get_precision('Product Unit of Measure'),
readonly=True, states={'draft': [('readonly', False)]})
product_uom = fields.Many2one(
product_uom_id = fields.Many2one(
comodel_name='product.uom', string='Unit of Measure',
readonly=True, states={'draft': [('readonly', False)]},
domain="[('category_id', '=', category_uom_id)]")
category_uom_id = fields.Many2one(related="product_uom.category_id")
category_uom_id = fields.Many2one(related="product_uom_id.category_id")
manufactured_qty = fields.Float(
string="Quantity in Manufacturing Orders",
compute=_compute_manufactured_qty, store=True, readonly=True,
digits_compute=dp.get_precision('Product Unit of Measure'),
digits=dp.get_precision('Product Unit of Measure'),
help="Sum of the quantities in Manufacturing Orders (in any state).")
done_qty = fields.Float(
string="Quantity Done", store=True, readonly=True,
compute=_compute_manufactured_qty,
digits_compute=dp.get_precision('Product Unit of Measure'),
digits=dp.get_precision('Product Unit of Measure'),
help="Sum of the quantities in all done Manufacturing Orders.")
pending_qty = fields.Float(
string="Pending Quantity", compute=_compute_manufactured_qty,
store=True, digits_compute=dp.get_precision('Product Unit of Measure'),
store=True, digits=dp.get_precision('Product Unit of Measure'),
readonly=True,
help="Quantity pending to add to Manufacturing Orders "
"to fulfill the Manufacturing Request requirement.")
@@ -159,12 +161,17 @@ class MrpProductionRequest(models.Model):
location_src_id = fields.Many2one(
comodel_name='stock.location', string='Raw Materials Location',
default=lambda self: self.env['stock.location'].browse(
self.env['mrp.production']._src_id_default()),
self.env['mrp.production']._get_default_location_src_id()),
required=True, readonly=True, states={'draft': [('readonly', False)]})
location_dest_id = fields.Many2one(
comodel_name='stock.location', string='Finished Products Location',
default=lambda self: self.env['stock.location'].browse(
self.env['mrp.production']._dest_id_default()),
self.env['mrp.production']._get_default_location_dest_id()),
required=True, readonly=True, states={'draft': [('readonly', False)]})
picking_type_id = fields.Many2one(
comodel_name='stock.picking.type', string='Picking Type',
default=lambda self: self.env['stock.picking.type'].browse(
self.env['mrp.production']._get_default_picking_type()),
required=True, readonly=True, states={'draft': [('readonly', False)]})
@api.multi

View File

@@ -2,7 +2,7 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models, _
from odoo import api, fields, models, _
class ProcurementOrder(models.Model):
@@ -12,31 +12,32 @@ class ProcurementOrder(models.Model):
comodel_name="mrp.production.request", string="Manufacturing Request",
copy=False)
@api.model
def _prepare_mrp_production_request(self, procurement):
data = self._prepare_mo_vals(procurement)
data['procurement_id'] = procurement.id
@api.multi
def _prepare_mrp_production_request(self):
self.ensure_one()
data = self._prepare_mo_vals(self._get_matching_bom())
data['procurement_id'] = self.id
data['state'] = 'to_approve'
return data
@api.model
def _run(self, procurement):
if (procurement.rule_id and
procurement.rule_id.action == 'manufacture' and
procurement.product_id.mrp_production_request):
if not procurement.check_bom_exists():
procurement.message_post(
@api.multi
def _run(self):
self.ensure_one()
if (self.rule_id and
self.rule_id.action == 'manufacture' and
self.product_id.mrp_production_request):
if not self._get_matching_bom():
self.message_post(
body=_("No BoM exists for this product!"))
return False
if not self.mrp_production_request_id:
request_data = self._prepare_mrp_production_request(
procurement)
request_data = self._prepare_mrp_production_request()
req = self.env['mrp.production.request'].create(request_data)
procurement.message_post(body=_(
self.message_post(body=_(
"Manufacturing Request created"))
procurement.mrp_production_request_id = req.id
self.mrp_production_request_id = req.id
return True
return super(ProcurementOrder, self)._run(procurement)
return super(ProcurementOrder, self)._run()
@api.multi
def propagate_cancels(self):

View File

@@ -2,7 +2,7 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models
from odoo import fields, models
class ProductTemplate(models.Model):

View File

@@ -2,7 +2,7 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, models
from odoo import api, models
class StockMove(models.Model):

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_mrp_production_request

View File

@@ -2,9 +2,9 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.tests.common import TransactionCase
from openerp import fields
from openerp.exceptions import UserError
from odoo.tests.common import TransactionCase
from odoo import fields
from odoo.exceptions import UserError
class TestMrpProductionRequest(TransactionCase):
@@ -61,7 +61,6 @@ class TestMrpProductionRequest(TransactionCase):
('mrp_production_request_id', '=', request.id)])
self.assertTrue(mo, "No MO created.")
self.assertEqual(request.pending_qty, 0.0)
mo.action_confirm()
request.button_done()
def test_cancellation_from_request(self):

View File

@@ -53,7 +53,7 @@
<field name="done_qty"/>
<field name="manufactured_qty"/>
<field name="pending_qty"/>
<field name="product_uom" groups="product.group_uom"/>
<field name="product_uom_id" groups="product.group_uom"/>
<field name="category_uom_id" invisible="1"/>
</group>
</group>
@@ -80,6 +80,7 @@
<group>
<field name="location_src_id"/>
<field name="location_dest_id"/>
<field name="picking_type_id"/>
<field name="date_planned"/>
</group>
</group>

View File

@@ -9,7 +9,7 @@
<field name="inherit_id"
ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml">
<field name="move_prod_id" position="after">
<field name="availability" position="after">
<field name="mrp_production_request_id"/>
</field>
</field>

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mrp_production_request_create_mo

View File

@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2017-18 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models
import openerp.addons.decimal_precision as dp
from odoo import api, fields, models
import odoo.addons.decimal_precision as dp
class MrpProductionRequestCreateMo(models.TransientModel):
@@ -14,8 +14,7 @@ class MrpProductionRequestCreateMo(models.TransientModel):
def compute_product_line_ids(self):
self.product_line_ids.unlink()
res = self._prepare_lines()
product_lines = res[0]
# TODO: expand with workcenter_lines: they are in res[1].
product_lines = res[1]
for line in product_lines:
self.env['mrp.production.request.create.mo.line'].create(
self._prepare_product_line(line))
@@ -23,27 +22,25 @@ class MrpProductionRequestCreateMo(models.TransientModel):
return {"type": "ir.actions.do_nothing"}
def _prepare_lines(self):
"""Get the components (product_lines) and Work Centers Utilisation
(workcenter_lines) needed for manufacturing the given a BoM.
:return: product_lines, workcenter_lines
"""Get the components (product_lines) needed for manufacturing the
given a BoM.
:return: boms_done, lines_done
"""
bom_obj = self.env['mrp.bom']
uom_obj = self.env['product.uom']
bom_point = self.bom_id
factor = uom_obj._compute_qty(
self.mrp_production_request_id.product_uom.id, self.pending_qty,
bom_point.product_uom.id)
return bom_obj._bom_explode(
bom_point, self.mrp_production_request_id.product_id,
factor / bom_point.product_qty,
routing_id=self.mrp_production_request_id.routing_id.id)
factor = self.mrp_production_request_id.product_uom_id.\
_compute_quantity(self.pending_qty, bom_point.product_uom_id)
return bom_point.explode(
self.mrp_production_request_id.product_id,
factor / bom_point.product_qty)
@api.one
@api.multi
def _get_mo_qty(self):
"""Propose a qty to create a MO available to produce."""
bottle_neck = min(self.product_line_ids.mapped('bottle_neck_factor'))
bottle_neck = max(min(1, bottle_neck), 0)
self.mo_qty = self.pending_qty * bottle_neck
for rec in self:
bottle_neck = min(rec.product_line_ids.mapped(
'bottle_neck_factor'))
bottle_neck = max(min(1, bottle_neck), 0)
rec.mo_qty = rec.pending_qty * bottle_neck
mrp_production_request_id = fields.Many2one(
comodel_name="mrp.production.request", readonly=True)
@@ -51,12 +48,12 @@ class MrpProductionRequestCreateMo(models.TransientModel):
related='mrp_production_request_id.bom_id', readonly=True)
mo_qty = fields.Float(
string="Quantity",
digits_compute=dp.get_precision("Product Unit of Measure"))
digits=dp.get_precision("Product Unit of Measure"))
pending_qty = fields.Float(
related="mrp_production_request_id.pending_qty",
digits_compute=dp.get_precision("Product Unit of Measure"))
product_uom = fields.Many2one(
related="mrp_production_request_id.product_uom")
digits=dp.get_precision("Product Unit of Measure"))
product_uom_id = fields.Many2one(
related="mrp_production_request_id.product_uom_id")
product_line_ids = fields.One2many(
comodel_name="mrp.production.request.create.mo.line",
string="Products needed",
@@ -64,9 +61,9 @@ class MrpProductionRequestCreateMo(models.TransientModel):
def _prepare_product_line(self, pl):
return {
'product_id': pl['product_id'],
'product_qty': pl['product_qty'],
'product_uom': pl['product_uom'],
'product_id': pl[0].product_id.id,
'product_qty': pl[1]['qty'],
'product_uom_id': pl[0].product_uom_id.id,
'mrp_production_request_create_mo_id': self.id,
'location_id': self.mrp_production_request_id.location_src_id.id,
}
@@ -79,13 +76,13 @@ class MrpProductionRequestCreateMo(models.TransientModel):
'product_id': request_id.product_id.id,
'bom_id': request_id.bom_id.id,
'product_qty': self.mo_qty,
'product_uom': self.product_uom.id,
'product_uom_id': self.product_uom_id.id,
'mrp_production_request_id': self.mrp_production_request_id.id,
'origin': request_id.origin,
'location_src_id': request_id.location_src_id.id,
'location_dest_id': request_id.location_dest_id.id,
'picking_type_id': request_id.picking_type_id.id,
'routing_id': request_id.routing_id.id,
'move_prod_id': request_id.procurement_id.move_dest_id.id or False,
'date_planned': request_id.date_planned,
'company_id': request_id.company_id.id,
}
@@ -108,33 +105,35 @@ class MrpProductionRequestCreateMo(models.TransientModel):
class MrpProductionRequestCreateMoLine(models.TransientModel):
_name = "mrp.production.request.create.mo.line"
@api.one
@api.multi
def _compute_available_qty(self):
product_available = self.product_id.with_context(
location=self.location_id.id)._product_available()[
self.product_id.id]['qty_available_not_res']
res = self.product_uom._compute_qty(
self.product_id.product_tmpl_id.uom_id.id, product_available,
self.product_uom.id)
self.available_qty = res
for rec in self:
product_available = rec.product_id.with_context(
location=rec.location_id.id).\
_compute_product_available_not_res_dict()[
rec.product_id.id]['qty_available_not_res']
res = rec.product_id.product_tmpl_id.uom_id._compute_quantity(
product_available, rec.product_uom_id)
rec.available_qty = res
@api.one
@api.multi
def _compute_bottle_neck_factor(self):
if self.product_qty:
self.bottle_neck_factor = self.available_qty / self.product_qty
for rec in self:
if rec.product_qty:
rec.bottle_neck_factor = rec.available_qty / rec.product_qty
product_id = fields.Many2one(
comodel_name='product.product', string='Product', required=True)
product_qty = fields.Float(
string='Quantity Required', required=True,
digits_compute=dp.get_precision('Product Unit of Measure'))
product_uom = fields.Many2one(
digits=dp.get_precision('Product Unit of Measure'))
product_uom_id = fields.Many2one(
comodel_name='product.uom', string='UoM', required=True)
mrp_production_request_create_mo_id = fields.Many2one(
comodel_name='mrp.production.request.create.mo')
available_qty = fields.Float(
string='Quantity Available', compute=_compute_available_qty,
digits_compute=dp.get_precision('Product Unit of Measure'))
digits=dp.get_precision('Product Unit of Measure'))
bottle_neck_factor = fields.Float(compute=_compute_bottle_neck_factor)
location_id = fields.Many2one(comodel_name='stock.location',
required=True)

View File

@@ -21,7 +21,7 @@
<field name="product_line_ids" nolabel="1">
<tree>
<field name="product_id"/>
<field name="product_uom"/>
<field name="product_uom_id"/>
<field name="product_qty"/>
<field name="available_qty"/>
<field name="bottle_neck_factor"/>
@@ -31,7 +31,7 @@
</group>
<group name="destination" string="Manufacturing Order:" col="4">
<field name="mo_qty"/>
<field name="product_uom" options="{'no_open': True}"
<field name="product_uom_id" options="{'no_open': True}"
groups="product.group_uom"/>
</group>