[ADD] Added module with pre-commit changes only.

This commit is contained in:
Chandresh Thakkar
2020-04-03 16:51:57 +05:30
parent 2a00e31fd3
commit 6c2f6fe827
17 changed files with 885 additions and 647 deletions

View File

@@ -7,11 +7,10 @@
"planification.", "planification.",
"version": "12.0.1.0.0", "version": "12.0.1.0.0",
"development_status": "Mature", "development_status": "Mature",
"maintainers": ['lreficent'], "maintainers": ["lreficent"],
"category": "Manufacturing", "category": "Manufacturing",
"website": "https://github.com/OCA/manufacture", "website": "https://github.com/OCA/manufacture",
"author": "Eficent," "author": "Eficent," "Odoo Community Association (OCA)",
"Odoo Community Association (OCA)",
"license": "AGPL-3", "license": "AGPL-3",
"application": False, "application": False,
"installable": True, "installable": True,

View File

@@ -1,15 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo noupdate="1"> <odoo noupdate="1">
<record id="seq_mrp_production_request" model="ir.sequence"> <record id="seq_mrp_production_request" model="ir.sequence">
<field name="name">Manufacturing Request</field> <field name="name">Manufacturing Request</field>
<field name="code">mrp.production.request</field> <field name="code">mrp.production.request</field>
<field name="prefix">MR/%(range_year)s/</field> <field name="prefix">MR/%(range_year)s/</field>
<field name="padding">5</field> <field name="padding">5</field>
<field name="company_id" eval="False"/> <field name="company_id" eval="False" />
</record> </record>
</odoo> </odoo>

View File

@@ -9,7 +9,10 @@ class MrpProduction(models.Model):
mrp_production_request_id = fields.Many2one( mrp_production_request_id = fields.Many2one(
comodel_name="mrp.production.request", comodel_name="mrp.production.request",
string="Manufacturing Request", copy=False, readonly=True) string="Manufacturing Request",
copy=False,
readonly=True,
)
def _generate_finished_moves(self): def _generate_finished_moves(self):
"""`move_dest_ids` is a One2many fields in mrp.production, thus we """`move_dest_ids` is a One2many fields in mrp.production, thus we
@@ -21,7 +24,7 @@ class MrpProduction(models.Model):
move = super()._generate_finished_moves() move = super()._generate_finished_moves()
request = self.mrp_production_request_id request = self.mrp_production_request_id
if request and request.move_dest_ids: if request and request.move_dest_ids:
move.write({ move.write(
'move_dest_ids': [(4, x.id) for x in request.move_dest_ids], {"move_dest_ids": [(4, x.id) for x in request.move_dest_ids],}
}) )
return move return move

View File

@@ -1,10 +1,11 @@
# Copyright 2017-19 Eficent Business and IT Consulting Services S.L. # Copyright 2017-19 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _ from odoo import _, api, fields, models
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class MrpProductionRequest(models.Model): class MrpProductionRequest(models.Model):
_name = "mrp.production.request" _name = "mrp.production.request"
@@ -14,153 +15,239 @@ class MrpProductionRequest(models.Model):
@api.model @api.model
def _company_get(self): def _company_get(self):
company_id = self.env['res.company']._company_default_get() company_id = self.env["res.company"]._company_default_get()
return self.env['res.company'].browse(company_id.id) return self.env["res.company"].browse(company_id.id)
@api.model @api.model
def _get_default_requested_by(self): def _get_default_requested_by(self):
return self.env.user return self.env.user
name = fields.Char( name = fields.Char(
default="/", required=True, default="/",
readonly=True, states={'draft': [('readonly', False)]}) required=True,
readonly=True,
states={"draft": [("readonly", False)]},
)
origin = fields.Char( origin = fields.Char(
string='Source Document', string="Source Document", readonly=True, states={"draft": [("readonly", False)]}
readonly=True, states={'draft': [('readonly', False)]}) )
requested_by = fields.Many2one( requested_by = fields.Many2one(
comodel_name='res.users', string='Requested by', comodel_name="res.users",
string="Requested by",
default=lambda self: self._get_default_requested_by(), default=lambda self: self._get_default_requested_by(),
required=True, track_visibility='onchange', required=True,
readonly=True, states={'draft': [('readonly', False)]}) track_visibility="onchange",
readonly=True,
states={"draft": [("readonly", False)]},
)
assigned_to = fields.Many2one( assigned_to = fields.Many2one(
comodel_name='res.users', string='Approver', comodel_name="res.users",
track_visibility='onchange', string="Approver",
readonly=True, states={'draft': [('readonly', False)]}, track_visibility="onchange",
domain=lambda self: [('groups_id', 'in', self.env.ref( readonly=True,
'mrp_production_request.' states={"draft": [("readonly", False)]},
'group_mrp_production_request_manager').id)]) domain=lambda self: [
description = fields.Text('Description') (
"groups_id",
"in",
self.env.ref(
"mrp_production_request." "group_mrp_production_request_manager"
).id,
)
],
)
description = fields.Text("Description")
date_planned_start = fields.Datetime( date_planned_start = fields.Datetime(
'Deadline Start', copy=False, default=fields.Datetime.now, "Deadline Start",
index=True, required=True, copy=False,
states={'confirmed': [('readonly', False)]}, oldname="date_planned") default=fields.Datetime.now,
date_planned_finished = fields.Datetime(
'Deadline End', copy=False, default=fields.Datetime.now,
index=True, index=True,
states={'confirmed': [('readonly', False)]}) required=True,
states={"confirmed": [("readonly", False)]},
oldname="date_planned",
)
date_planned_finished = fields.Datetime(
"Deadline End",
copy=False,
default=fields.Datetime.now,
index=True,
states={"confirmed": [("readonly", False)]},
)
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', string='Company', comodel_name="res.company",
required=True, default=lambda self: self._company_get()) string="Company",
required=True,
default=lambda self: self._company_get(),
)
mrp_production_ids = fields.One2many( mrp_production_ids = fields.One2many(
comodel_name="mrp.production", string="Manufacturing Orders", comodel_name="mrp.production",
inverse_name="mrp_production_request_id", readonly=True) string="Manufacturing Orders",
inverse_name="mrp_production_request_id",
readonly=True,
)
mrp_production_count = fields.Integer( mrp_production_count = fields.Integer(
compute="_compute_mrp_production_count", compute="_compute_mrp_production_count", string="MO's Count",
string="MO's Count",
) )
state = fields.Selection( state = fields.Selection(
selection=[("draft", "Draft"), selection=[
("draft", "Draft"),
("to_approve", "To Be Approved"), ("to_approve", "To Be Approved"),
("approved", "Approved"), ("approved", "Approved"),
("done", "Done"), ("done", "Done"),
("cancel", "Cancelled")], ("cancel", "Cancelled"),
index=True, track_visibility='onchange', ],
required=True, copy=False, default='draft') index=True,
procurement_group_id = fields.Many2one(
string='Procurement Group',
comodel_name='procurement.group',
copy=False)
propagate = fields.Boolean(
'Propagate cancel and split',
help='If checked, when the previous move of the move '
'(which was generated by a next procurement) is cancelled '
'or split, the move generated by this move will too')
product_id = fields.Many2one(
comodel_name="product.product", string="Product", required=True,
domain=[('type', 'in', ['product', 'consu'])],
track_visibility="onchange", track_visibility="onchange",
readonly=True, states={'draft': [('readonly', False)]}) required=True,
copy=False,
default="draft",
)
procurement_group_id = fields.Many2one(
string="Procurement Group", comodel_name="procurement.group", copy=False
)
propagate = fields.Boolean(
"Propagate cancel and split",
help="If checked, when the previous move of the move "
"(which was generated by a next procurement) is cancelled "
"or split, the move generated by this move will too",
)
product_id = fields.Many2one(
comodel_name="product.product",
string="Product",
required=True,
domain=[("type", "in", ["product", "consu"])],
track_visibility="onchange",
readonly=True,
states={"draft": [("readonly", False)]},
)
product_tmpl_id = fields.Many2one( product_tmpl_id = fields.Many2one(
comodel_name='product.template', string='Product Template', comodel_name="product.template",
related='product_id.product_tmpl_id') string="Product Template",
related="product_id.product_tmpl_id",
)
product_qty = fields.Float( product_qty = fields.Float(
string="Required Quantity", required=True, track_visibility='onchange', string="Required Quantity",
digits=dp.get_precision('Product Unit of Measure'), default=1.0, required=True,
readonly=True, states={'draft': [('readonly', False)]}) track_visibility="onchange",
digits=dp.get_precision("Product Unit of Measure"),
default=1.0,
readonly=True,
states={"draft": [("readonly", False)]},
)
product_uom_id = fields.Many2one( product_uom_id = fields.Many2one(
comodel_name='uom.uom', string='Unit of Measure', comodel_name="uom.uom",
readonly=True, states={'draft': [('readonly', False)]}, string="Unit of Measure",
domain="[('category_id', '=', category_uom_id)]") readonly=True,
states={"draft": [("readonly", False)]},
domain="[('category_id', '=', category_uom_id)]",
)
category_uom_id = fields.Many2one(related="product_uom_id.category_id") category_uom_id = fields.Many2one(related="product_uom_id.category_id")
manufactured_qty = fields.Float( manufactured_qty = fields.Float(
string="Quantity in Manufacturing Orders", string="Quantity in Manufacturing Orders",
compute="_compute_manufactured_qty", store=True, readonly=True,
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", compute="_compute_manufactured_qty",
digits=dp.get_precision('Product Unit of Measure'), store=True,
help="Sum of the quantities in all done Manufacturing Orders.") readonly=True,
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=dp.get_precision("Product Unit of Measure"),
help="Sum of the quantities in all done Manufacturing Orders.",
)
pending_qty = fields.Float( pending_qty = fields.Float(
string="Pending Quantity", compute="_compute_manufactured_qty", string="Pending Quantity",
store=True, digits=dp.get_precision('Product Unit of Measure'), compute="_compute_manufactured_qty",
store=True,
digits=dp.get_precision("Product Unit of Measure"),
readonly=True, readonly=True,
help="Quantity pending to add to Manufacturing Orders " help="Quantity pending to add to Manufacturing Orders "
"to fulfill the Manufacturing Request requirement.") "to fulfill the Manufacturing Request requirement.",
)
bom_id = fields.Many2one( bom_id = fields.Many2one(
comodel_name="mrp.bom", string="Bill of Materials", required=True, comodel_name="mrp.bom",
readonly=True, states={'draft': [('readonly', False)]}) string="Bill of Materials",
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
)
routing_id = fields.Many2one( routing_id = fields.Many2one(
comodel_name='mrp.routing', string='Routing', comodel_name="mrp.routing",
on_delete='setnull', readonly=True, string="Routing",
states={'draft': [('readonly', False)]}, on_delete="setnull",
readonly=True,
states={"draft": [("readonly", False)]},
help="The list of operations (list of work centers) to produce " help="The list of operations (list of work centers) to produce "
"the finished product. The routing is mainly used to compute " "the finished product. The routing is mainly used to compute "
"work center costs during operations and to plan future loads " "work center costs during operations and to plan future loads "
"on work centers based on production plannification.") "on work centers based on production plannification.",
)
location_src_id = fields.Many2one( location_src_id = fields.Many2one(
comodel_name='stock.location', string='Raw Materials Location', comodel_name="stock.location",
default=lambda self: self.env['stock.location'].browse( string="Raw Materials Location",
self.env['mrp.production']._get_default_location_src_id()), default=lambda self: self.env["stock.location"].browse(
required=True, readonly=True, states={'draft': [('readonly', False)]}) self.env["mrp.production"]._get_default_location_src_id()
),
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
)
location_dest_id = fields.Many2one( location_dest_id = fields.Many2one(
comodel_name='stock.location', string='Finished Products Location', comodel_name="stock.location",
default=lambda self: self.env['stock.location'].browse( string="Finished Products Location",
self.env['mrp.production']._get_default_location_dest_id()), default=lambda self: self.env["stock.location"].browse(
required=True, readonly=True, states={'draft': [('readonly', False)]}) self.env["mrp.production"]._get_default_location_dest_id()
),
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
)
picking_type_id = fields.Many2one( picking_type_id = fields.Many2one(
comodel_name='stock.picking.type', string='Picking Type', comodel_name="stock.picking.type",
default=lambda self: self.env['stock.picking.type'].browse( string="Picking Type",
self.env['mrp.production']._get_default_picking_type()), default=lambda self: self.env["stock.picking.type"].browse(
required=True, readonly=True, states={'draft': [('readonly', False)]}) self.env["mrp.production"]._get_default_picking_type()
),
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
)
move_dest_ids = fields.One2many( move_dest_ids = fields.One2many(
comodel_name='stock.move', comodel_name="stock.move",
inverse_name='created_mrp_production_request_id', inverse_name="created_mrp_production_request_id",
string="Stock Movements of Produced Goods") string="Stock Movements of Produced Goods",
)
orderpoint_id = fields.Many2one( orderpoint_id = fields.Many2one(
comodel_name='stock.warehouse.orderpoint', comodel_name="stock.warehouse.orderpoint", string="Orderpoint"
string='Orderpoint') )
_sql_constraints = [ _sql_constraints = [
('name_uniq', 'unique(name, company_id)', (
'Reference must be unique per Company!'), "name_uniq",
"unique(name, company_id)",
"Reference must be unique per Company!",
),
] ]
@api.model @api.model
def _get_mo_valid_states(self): def _get_mo_valid_states(self):
return ['planned', 'confirmed', 'progress', 'done'] return ["planned", "confirmed", "progress", "done"]
@api.multi @api.multi
@api.depends('mrp_production_ids', 'mrp_production_ids.state', 'state') @api.depends("mrp_production_ids", "mrp_production_ids.state", "state")
def _compute_manufactured_qty(self): def _compute_manufactured_qty(self):
valid_states = self._get_mo_valid_states() valid_states = self._get_mo_valid_states()
for req in self: for req in self:
done_mo = req.mrp_production_ids.filtered( done_mo = req.mrp_production_ids.filtered(
lambda mo: mo.state in 'done').mapped('product_qty') lambda mo: mo.state in "done"
).mapped("product_qty")
req.done_qty = sum(done_mo) req.done_qty = sum(done_mo)
valid_mo = req.mrp_production_ids.filtered( valid_mo = req.mrp_production_ids.filtered(
lambda mo: mo.state in valid_states).mapped('product_qty') lambda mo: mo.state in valid_states
).mapped("product_qty")
req.manufactured_qty = sum(valid_mo) req.manufactured_qty = sum(valid_mo)
req.pending_qty = max(req.product_qty - req.manufactured_qty, 0.0) req.pending_qty = max(req.product_qty - req.manufactured_qty, 0.0)
@@ -169,25 +256,29 @@ class MrpProductionRequest(models.Model):
for rec in self: for rec in self:
rec.mrp_production_count = len(rec.mrp_production_ids) rec.mrp_production_count = len(rec.mrp_production_ids)
@api.onchange('product_id') @api.onchange("product_id")
def _onchange_product_id(self): def _onchange_product_id(self):
self.product_uom_id = self.product_id.uom_id self.product_uom_id = self.product_id.uom_id
self.bom_id = self.env['mrp.bom']._bom_find( self.bom_id = self.env["mrp.bom"]._bom_find(
product=self.product_id, company_id=self.company_id.id, product=self.product_id,
picking_type=self.picking_type_id) company_id=self.company_id.id,
picking_type=self.picking_type_id,
)
@api.multi @api.multi
def _subscribe_assigned_user(self, vals): def _subscribe_assigned_user(self, vals):
self.ensure_one() self.ensure_one()
if vals.get('assigned_to'): if vals.get("assigned_to"):
self.message_subscribe( self.message_subscribe(
partner_ids=self.assigned_to.mapped('partner_id').ids) partner_ids=self.assigned_to.mapped("partner_id").ids
)
@api.model @api.model
def _create_sequence(self, vals): def _create_sequence(self, vals):
if not vals.get('name') or vals.get('name') == '/': if not vals.get("name") or vals.get("name") == "/":
vals['name'] = self.env['ir.sequence'].next_by_code( vals["name"] = (
'mrp.production.request') or '/' self.env["ir.sequence"].next_by_code("mrp.production.request") or "/"
)
return vals return vals
@api.model @api.model
@@ -208,59 +299,70 @@ class MrpProductionRequest(models.Model):
@api.multi @api.multi
def button_to_approve(self): def button_to_approve(self):
self.write({'state': 'to_approve'}) self.write({"state": "to_approve"})
return True return True
@api.multi @api.multi
def button_approved(self): def button_approved(self):
self.write({'state': 'approved'}) self.write({"state": "approved"})
return True return True
@api.multi @api.multi
def button_done(self): def button_done(self):
self.write({'state': 'done'}) self.write({"state": "done"})
return True return True
@api.multi @api.multi
def _check_reset_allowed(self): def _check_reset_allowed(self):
if any([s in self._get_mo_valid_states() for s in self.mapped( if any(
'mrp_production_ids.state')]): [
s in self._get_mo_valid_states()
for s in self.mapped("mrp_production_ids.state")
]
):
raise UserError( raise UserError(
_("You cannot reset a manufacturing request if the related " _(
"manufacturing orders are not cancelled.")) "You cannot reset a manufacturing request if the related "
"manufacturing orders are not cancelled."
)
)
@api.multi @api.multi
def button_draft(self): def button_draft(self):
self._check_reset_allowed() self._check_reset_allowed()
self.write({'state': 'draft'}) self.write({"state": "draft"})
return True return True
@api.multi @api.multi
def _check_cancel_allowed(self): def _check_cancel_allowed(self):
if any([s == 'done' for s in self.mapped('state')]): if any([s == "done" for s in self.mapped("state")]):
raise UserError( raise UserError(
_('You cannot reject a manufacturing request related to ' _(
'done procurement orders.')) "You cannot reject a manufacturing request related to "
"done procurement orders."
)
)
@api.multi @api.multi
def button_cancel(self): def button_cancel(self):
self._check_cancel_allowed() self._check_cancel_allowed()
self.write({'state': 'cancel'}) self.write({"state": "cancel"})
self.mapped('move_dest_ids').filtered( self.mapped("move_dest_ids").filtered(
lambda r: r.state != 'cancel')._action_cancel() lambda r: r.state != "cancel"
)._action_cancel()
return True return True
@api.multi @api.multi
def action_view_mrp_productions(self): def action_view_mrp_productions(self):
action = self.env.ref('mrp.mrp_production_action') action = self.env.ref("mrp.mrp_production_action")
result = action.read()[0] result = action.read()[0]
result['context'] = {} result["context"] = {}
mos = self.mapped('mrp_production_ids') mos = self.mapped("mrp_production_ids")
# choose the view_mode accordingly # choose the view_mode accordingly
if len(mos) != 1: if len(mos) != 1:
result['domain'] = [('id', 'in', mos.ids)] result["domain"] = [("id", "in", mos.ids)]
elif len(mos) == 1: elif len(mos) == 1:
form = self.env.ref('mrp.mrp_production_form_view', False) form = self.env.ref("mrp.mrp_production_form_view", False)
result['views'] = [(form and form.id or False, 'form')] result["views"] = [(form and form.id or False, "form")]
result['res_id'] = mos[0].id result["res_id"] = mos[0].id
return result return result

View File

@@ -8,7 +8,7 @@ class ProductTemplate(models.Model):
_inherit = "product.template" _inherit = "product.template"
mrp_production_request = fields.Boolean( mrp_production_request = fields.Boolean(
string='Manufacturing Request', string="Manufacturing Request",
help="Check this box to generate manufacturing request instead of " help="Check this box to generate manufacturing request instead of "
"generating manufacturing orders from procurement.", "generating manufacturing orders from procurement.",
) )

View File

@@ -8,15 +8,13 @@ class StockMove(models.Model):
_inherit = "stock.move" _inherit = "stock.move"
created_mrp_production_request_id = fields.Many2one( created_mrp_production_request_id = fields.Many2one(
comodel_name='mrp.production.request', comodel_name="mrp.production.request", string="Created Production Request",
string='Created Production Request',
) )
@api.model @api.model
def create(self, vals): def create(self, vals):
if 'production_id' in vals: if "production_id" in vals:
production = self.env['mrp.production'].browse( production = self.env["mrp.production"].browse(vals["production_id"])
vals['production_id'])
if production.mrp_production_request_id: if production.mrp_production_request_id:
vals['propagate'] = False vals["propagate"] = False
return super().create(vals) return super().create(vals)

View File

@@ -1,7 +1,7 @@
# Copyright 2018-19 Eficent Business and IT Consulting Services S.L. # Copyright 2018-19 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, _ from odoo import _, api, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
@@ -10,74 +10,96 @@ class StockRule(models.Model):
@api.multi @api.multi
def _prepare_mrp_production_request( def _prepare_mrp_production_request(
self, product_id, product_qty, product_uom, location_id, name, self,
origin, values, bom): product_id,
product_qty,
product_uom,
location_id,
name,
origin,
values,
bom,
):
self.ensure_one() self.ensure_one()
data = self._prepare_mo_vals( data = self._prepare_mo_vals(
product_id, product_qty, product_uom, location_id, name, product_id, product_qty, product_uom, location_id, name, origin, values, bom
origin, values, bom) )
data['state'] = 'to_approve' data["state"] = "to_approve"
orderpoint = values.get('orderpoint_id') orderpoint = values.get("orderpoint_id")
if orderpoint: if orderpoint:
data['orderpoint_id'] = orderpoint.id data["orderpoint_id"] = orderpoint.id
procurement_group = values.get('group_id') procurement_group = values.get("group_id")
if procurement_group: if procurement_group:
data['procurement_group_id'] = procurement_group.id data["procurement_group_id"] = procurement_group.id
return data return data
@api.multi @api.multi
def _need_production_request(self, product_id): def _need_production_request(self, product_id):
return self.action == 'manufacture' \ return self.action == "manufacture" and product_id.mrp_production_request
and product_id.mrp_production_request
@api.multi @api.multi
def _run_production_request(self, product_id, product_qty, product_uom, def _run_production_request(
location_id, name, origin, values): self, product_id, product_qty, product_uom, location_id, name, origin, values
):
"""Trying to handle this as much similar as possible to Odoo """Trying to handle this as much similar as possible to Odoo
production orders. See `_run_manufacture` in Odoo standard.""" production orders. See `_run_manufacture` in Odoo standard."""
request_obj = self.env['mrp.production.request'] request_obj = self.env["mrp.production.request"]
request_obj_sudo = request_obj.sudo().with_context( request_obj_sudo = request_obj.sudo().with_context(
force_company=values['company_id'].id) force_company=values["company_id"].id
)
bom = self._get_matching_bom(product_id, values) bom = self._get_matching_bom(product_id, values)
if not bom: if not bom:
raise UserError(_( raise UserError(
'There is no Bill of Material found for the product %s. ' _(
'Please define a Bill of Material for this product.') % ( "There is no Bill of Material found for the product %s. "
product_id.display_name,)) "Please define a Bill of Material for this product."
)
% (product_id.display_name,)
)
# create the MR as SUPERUSER because the current user may not # create the MR as SUPERUSER because the current user may not
# have the rights to do it (mto product launched by a sale for example) # have the rights to do it (mto product launched by a sale for example)
request = request_obj_sudo.create( request = request_obj_sudo.create(
self._prepare_mrp_production_request( self._prepare_mrp_production_request(
product_id, product_qty, product_uom, location_id, name, product_id,
origin, values, bom)) product_qty,
origin_production = values.get('move_dest_ids') and \ product_uom,
values['move_dest_ids'][0].raw_material_production_id or False location_id,
orderpoint = values.get('orderpoint_id') name,
origin,
values,
bom,
)
)
origin_production = (
values.get("move_dest_ids")
and values["move_dest_ids"][0].raw_material_production_id
or False
)
orderpoint = values.get("orderpoint_id")
if orderpoint: if orderpoint:
request.message_post_with_view( request.message_post_with_view(
'mail.message_origin_link', "mail.message_origin_link",
values={'self': request, values={"self": request, "origin": orderpoint},
'origin': orderpoint}, subtype_id=self.env.ref("mail.mt_note").id,
subtype_id=self.env.ref('mail.mt_note').id,
) )
if origin_production: if origin_production:
request.message_post_with_view( request.message_post_with_view(
'mail.message_origin_link', "mail.message_origin_link",
values={'self': request, values={"self": request, "origin": origin_production},
'origin': origin_production}, subtype_id=self.env.ref("mail.mt_note").id,
subtype_id=self.env.ref('mail.mt_note').id,
) )
return True return True
@api.multi @api.multi
def _run_manufacture(self, product_id, product_qty, product_uom, def _run_manufacture(
location_id, name, origin, values): self, product_id, product_qty, product_uom, location_id, name, origin, values
):
if self._need_production_request(product_id): if self._need_production_request(product_id):
return self._run_production_request( return self._run_production_request(
product_id, product_qty, product_uom, product_id, product_qty, product_uom, location_id, name, origin, values
location_id, name, origin, values) )
return super()._run_manufacture( return super()._run_manufacture(
product_id, product_qty, product_uom, location_id, name, product_id, product_qty, product_uom, location_id, name, origin, values
origin, values) )

View File

@@ -9,11 +9,14 @@ class Orderpoint(models.Model):
def _quantity_in_progress(self): def _quantity_in_progress(self):
res = super()._quantity_in_progress() res = super()._quantity_in_progress()
mrp_requests = self.env['mrp.production.request'].search([ mrp_requests = self.env["mrp.production.request"].search(
('state', 'not in', ('done', 'cancel')), [
('orderpoint_id', 'in', self.ids), ("state", "not in", ("done", "cancel")),
]) ("orderpoint_id", "in", self.ids),
]
)
for rec in mrp_requests: for rec in mrp_requests:
res[rec.orderpoint_id.id] += rec.product_uom_id._compute_quantity( res[rec.orderpoint_id.id] += rec.product_uom_id._compute_quantity(
rec.pending_qty, rec.orderpoint_id.product_uom, round=False) rec.pending_qty, rec.orderpoint_id.product_uom, round=False
)
return res return res

View File

@@ -1,73 +1,77 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo> <odoo>
<data noupdate="0">
<data noupdate="0">
<record model="ir.module.category" id="module_category_mrp_production_request"> <record model="ir.module.category" id="module_category_mrp_production_request">
<field name="name">Manufacturing Request</field> <field name="name">Manufacturing Request</field>
<field name="parent_id" ref="base.module_category_manufacturing"/> <field name="parent_id" ref="base.module_category_manufacturing" />
<field name="sequence">20</field> <field name="sequence">20</field>
</record> </record>
<record id="group_mrp_production_request_user" model="res.groups"> <record id="group_mrp_production_request_user" model="res.groups">
<field name="name">User</field> <field name="name">User</field>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> <field name="implied_ids" eval="[(4, ref('base.group_user'))]" />
<field name="category_id" ref="module_category_mrp_production_request"/> <field name="category_id" ref="module_category_mrp_production_request" />
</record> </record>
<record id="group_mrp_production_request_manager" model="res.groups"> <record id="group_mrp_production_request_manager" model="res.groups">
<field name="name">Manager</field> <field name="name">Manager</field>
<field name="implied_ids" <field
eval="[(4, ref('mrp_production_request.group_mrp_production_request_user'))]"/> name="implied_ids"
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/> eval="[(4, ref('mrp_production_request.group_mrp_production_request_user'))]"
<field name="category_id" ref="module_category_mrp_production_request"/> />
<field
name="users"
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
/>
<field name="category_id" ref="module_category_mrp_production_request" />
</record> </record>
</data>
</data> <data noupdate="0">
<data noupdate="0">
<record model="ir.rule" id="mrp_production_request_comp_rule"> <record model="ir.rule" id="mrp_production_request_comp_rule">
<field name="name">Manufacturing Request multi-company</field> <field name="name">Manufacturing Request multi-company</field>
<field name="model_id" ref="model_mrp_production_request"/> <field name="model_id" ref="model_mrp_production_request" />
<field name="global" eval="True"/> <field name="global" eval="True" />
<field name="domain_force">['|',('company_id','=',False), <field name="domain_force">['|',('company_id','=',False),
('company_id','child_of',[user.company_id.id])]</field> ('company_id','child_of',[user.company_id.id])]</field>
</record> </record>
<record id="mrp_production_request_followers_rule" model="ir.rule"> <record id="mrp_production_request_followers_rule" model="ir.rule">
<field name="name">Follow Manufacturing Request</field> <field name="name">Follow Manufacturing Request</field>
<field name="model_id" ref="model_mrp_production_request"/> <field name="model_id" ref="model_mrp_production_request" />
<field name="groups" eval="[(6,0, [ref('group_mrp_production_request_user')])]"/> <field
<field name="perm_read" eval="True"/> name="groups"
<field name="perm_write" eval="False"/> eval="[(6,0, [ref('group_mrp_production_request_user')])]"
<field name="perm_create" eval="False"/> />
<field name="perm_unlink" eval="False"/> <field name="perm_read" eval="True" />
<field name="perm_write" eval="False" />
<field name="perm_create" eval="False" />
<field name="perm_unlink" eval="False" />
<field name="domain_force">['|',('requested_by','=',user.id), <field name="domain_force">['|',('requested_by','=',user.id),
('message_partner_ids', 'in', [user.partner_id.id])]</field> ('message_partner_ids', 'in', [user.partner_id.id])]</field>
</record> </record>
<record id="mrp_production_request_rule" model="ir.rule"> <record id="mrp_production_request_rule" model="ir.rule">
<field name="name">Manufacturing Request User</field> <field name="name">Manufacturing Request User</field>
<field name="model_id" ref="model_mrp_production_request"/> <field name="model_id" ref="model_mrp_production_request" />
<field name="groups" eval="[(6,0, [ref('group_mrp_production_request_user')])]"/> <field
<field name="perm_read" eval="True"/> name="groups"
<field name="perm_write" eval="True"/> eval="[(6,0, [ref('group_mrp_production_request_user')])]"
<field name="perm_create" eval="True"/> />
<field name="perm_unlink" eval="True"/> <field name="perm_read" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_unlink" eval="True" />
<field name="domain_force">[('requested_by','=',user.id)]</field> <field name="domain_force">[('requested_by','=',user.id)]</field>
</record> </record>
<record id="mpr_production_request_line_manager_rule" model="ir.rule"> <record id="mpr_production_request_line_manager_rule" model="ir.rule">
<field name="name">Manufacturing Request Line Manager</field> <field name="name">Manufacturing Request Line Manager</field>
<field name="model_id" ref="model_mrp_production_request"/> <field name="model_id" ref="model_mrp_production_request" />
<field name="groups" eval="[(6,0, [ref('group_mrp_production_request_manager')])]"/> <field
<field name="perm_read" eval="True"/> name="groups"
<field name="perm_write" eval="True"/> eval="[(6,0, [ref('group_mrp_production_request_manager')])]"
<field name="perm_create" eval="True"/> />
<field name="perm_unlink" eval="True"/> <field name="perm_read" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_unlink" eval="True" />
</record> </record>
</data>
</data>
</odoo> </odoo>

View File

@@ -1,101 +1,119 @@
# Copyright 2017-18 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). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo import fields from odoo import fields
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.tests.common import TransactionCase
class TestMrpProductionRequest(TransactionCase): class TestMrpProductionRequest(TransactionCase):
def setUp(self, *args, **kwargs): def setUp(self, *args, **kwargs):
super().setUp(*args, **kwargs) super().setUp(*args, **kwargs)
self.production_model = self.env['mrp.production'] self.production_model = self.env["mrp.production"]
self.request_model = self.env['mrp.production.request'] self.request_model = self.env["mrp.production.request"]
self.wiz_model = self.env['mrp.production.request.create.mo'] self.wiz_model = self.env["mrp.production.request.create.mo"]
self.bom_model = self.env['mrp.bom'] self.bom_model = self.env["mrp.bom"]
self.group_model = self.env['procurement.group'] self.group_model = self.env["procurement.group"]
self.product_model = self.env['product.product'] self.product_model = self.env["product.product"]
self.bom_model = self.env['mrp.bom'] self.bom_model = self.env["mrp.bom"]
self.boml_model = self.env['mrp.bom.line'] self.boml_model = self.env["mrp.bom.line"]
self.warehouse = self.env.ref('stock.warehouse0') self.warehouse = self.env.ref("stock.warehouse0")
self.stock_loc = self.env.ref('stock.stock_location_stock') self.stock_loc = self.env.ref("stock.stock_location_stock")
route_manuf = self.env.ref('mrp.route_warehouse0_manufacture') route_manuf = self.env.ref("mrp.route_warehouse0_manufacture")
# Prepare Products: # Prepare Products:
self.product = self.env.ref('product.product_product_3') self.product = self.env.ref("product.product_product_3")
self.product.mrp_production_request = True self.product.mrp_production_request = True
self.product.route_ids = [(4, route_manuf.id, 0)] self.product.route_ids = [(4, route_manuf.id, 0)]
self.product_no_bom = self.product_model.create({ self.product_no_bom = self.product_model.create(
'name': 'Test Product without BoM', {
'mrp_production_request': True, "name": "Test Product without BoM",
'route_ids': [(6, 0, route_manuf.ids)], "mrp_production_request": True,
}) "route_ids": [(6, 0, route_manuf.ids)],
self.product_orderpoint = self.product_model.create({ }
'name': 'Test Product for orderpoint', )
'mrp_production_request': True, self.product_orderpoint = self.product_model.create(
'route_ids': [(6, 0, route_manuf.ids)], {
}) "name": "Test Product for orderpoint",
product_component = self.product_model.create({ "mrp_production_request": True,
'name': 'Test component', "route_ids": [(6, 0, route_manuf.ids)],
'mrp_production_request': True, }
'route_ids': [(6, 0, route_manuf.ids)], )
}) product_component = self.product_model.create(
{
"name": "Test component",
"mrp_production_request": True,
"route_ids": [(6, 0, route_manuf.ids)],
}
)
# Create Bill of Materials: # Create Bill of Materials:
self.test_bom_1 = self.bom_model.create({ self.test_bom_1 = self.bom_model.create(
'product_id': self.product_orderpoint.id, {
'product_tmpl_id': self.product_orderpoint.product_tmpl_id.id, "product_id": self.product_orderpoint.id,
'product_uom_id': self.product_orderpoint.uom_id.id, "product_tmpl_id": self.product_orderpoint.product_tmpl_id.id,
'product_qty': 1.0, "product_uom_id": self.product_orderpoint.uom_id.id,
'type': 'normal', "product_qty": 1.0,
}) "type": "normal",
self.boml_model.create({ }
'bom_id': self.test_bom_1.id, )
'product_id': product_component.id, self.boml_model.create(
'product_qty': 1.0, {
}) "bom_id": self.test_bom_1.id,
"product_id": product_component.id,
"product_qty": 1.0,
}
)
# Create Orderpoint: # Create Orderpoint:
self.orderpoint = self.env['stock.warehouse.orderpoint'].create({ self.orderpoint = self.env["stock.warehouse.orderpoint"].create(
'warehouse_id': self.warehouse.id, {
'location_id': self.warehouse.lot_stock_id.id, "warehouse_id": self.warehouse.id,
'product_id': self.product_orderpoint.id, "location_id": self.warehouse.lot_stock_id.id,
'product_min_qty': 10.0, "product_id": self.product_orderpoint.id,
'product_max_qty': 50.0, "product_min_qty": 10.0,
'product_uom': self.product_orderpoint.uom_id.id, "product_max_qty": 50.0,
}) "product_uom": self.product_orderpoint.uom_id.id,
}
)
# Create Procurement Group: # Create Procurement Group:
self.test_group = self.group_model.create({ self.test_group = self.group_model.create({"name": "TEST",})
'name': 'TEST',
})
# Create User: # Create User:
self.test_user = self.env['res.users'].create({ self.test_user = self.env["res.users"].create(
'name': 'John', {"name": "John", "login": "test",}
'login': 'test', )
})
def procure(self, group, product, qty=4.0,): def procure(
self, group, product, qty=4.0,
):
values = { values = {
'date_planned': fields.Datetime.now(), "date_planned": fields.Datetime.now(),
'group_id': group, "group_id": group,
} }
self.group_model.run( self.group_model.run(
product, qty, product.uom_id, self.stock_loc, product,
group.name, group.name, values, qty,
product.uom_id,
self.stock_loc,
group.name,
group.name,
values,
) )
return True return True
def test_01_manufacture_request(self): def test_01_manufacture_request(self):
"""Tests manufacture request workflow.""" """Tests manufacture request workflow."""
self.procure(self.test_group, self.product) self.procure(self.test_group, self.product)
request = self.request_model.search([ request = self.request_model.search(
('product_id', '=', self.product.id), [
('procurement_group_id', '=', self.test_group.id), ("product_id", "=", self.product.id),
]) ("procurement_group_id", "=", self.test_group.id),
]
)
self.assertEqual(len(request), 1) self.assertEqual(len(request), 1)
request.button_to_approve() request.button_to_approve()
request.button_draft() request.button_draft()
@@ -103,13 +121,14 @@ class TestMrpProductionRequest(TransactionCase):
request.button_approved() request.button_approved()
self.assertEqual(request.pending_qty, 4.0) self.assertEqual(request.pending_qty, 4.0)
wiz = self.wiz_model.with_context( wiz = self.wiz_model.with_context(
active_ids=request.ids, active_ids=request.ids, active_model="mrp.production.request"
active_model="mrp.production.request").create({}) ).create({})
wiz.compute_product_line_ids() wiz.compute_product_line_ids()
wiz.mo_qty = 4.0 wiz.mo_qty = 4.0
wiz.create_mo() wiz.create_mo()
mo = self.production_model.search([ mo = self.production_model.search(
('mrp_production_request_id', '=', request.id)]) [("mrp_production_request_id", "=", request.id)]
)
self.assertTrue(mo, "No MO created.") self.assertTrue(mo, "No MO created.")
self.assertEqual(request.pending_qty, 0.0) self.assertEqual(request.pending_qty, 0.0)
request.button_done() request.button_done()
@@ -117,39 +136,42 @@ class TestMrpProductionRequest(TransactionCase):
def test_02_assignation(self): def test_02_assignation(self):
"""Tests assignation of manufacturing requests.""" """Tests assignation of manufacturing requests."""
randon_bom_id = self.bom_model.search([], limit=1).id randon_bom_id = self.bom_model.search([], limit=1).id
request = self.request_model.create({ request = self.request_model.create(
'assigned_to': self.test_user.id, {
'product_id': self.product.id, "assigned_to": self.test_user.id,
'product_qty': 5.0, "product_id": self.product.id,
'bom_id': randon_bom_id, "product_qty": 5.0,
}) "bom_id": randon_bom_id,
}
)
request._onchange_product_id() request._onchange_product_id()
self.assertEqual( self.assertEqual(
request.bom_id.product_tmpl_id, self.product.product_tmpl_id, request.bom_id.product_tmpl_id,
"Wrong Bill of Materials.") self.product.product_tmpl_id,
request.write({ "Wrong Bill of Materials.",
'assigned_to': self.uid, )
}) request.write(
self.assertTrue(request.message_follower_ids, {"assigned_to": self.uid,}
"Followers not added correctly.") )
self.assertTrue(request.message_follower_ids, "Followers not added correctly.")
def test_03_substract_qty_from_orderpoint(self): def test_03_substract_qty_from_orderpoint(self):
"""Quantity in Manufacturing Requests should be considered by """Quantity in Manufacturing Requests should be considered by
orderpoints.""" orderpoints."""
request = self.request_model.search([ request = self.request_model.search(
('product_id', '=', self.product_orderpoint.id), [("product_id", "=", self.product_orderpoint.id),]
]) )
self.assertFalse(request) self.assertFalse(request)
self.env['procurement.group'].run_scheduler() self.env["procurement.group"].run_scheduler()
request = self.request_model.search([ request = self.request_model.search(
('product_id', '=', self.product_orderpoint.id), [("product_id", "=", self.product_orderpoint.id),]
]) )
self.assertEqual(len(request), 1) self.assertEqual(len(request), 1)
# Running again the scheduler should not generate a new MR. # Running again the scheduler should not generate a new MR.
self.env['procurement.group'].run_scheduler() self.env["procurement.group"].run_scheduler()
request = self.request_model.search([ request = self.request_model.search(
('product_id', '=', self.product_orderpoint.id), [("product_id", "=", self.product_orderpoint.id),]
]) )
self.assertEqual(len(request), 1) self.assertEqual(len(request), 1)
def test_04_raise_errors(self): def test_04_raise_errors(self):

View File

@@ -1,201 +1,274 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017-18 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017-18 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo> <odoo>
<record model="ir.ui.view" id="view_mrp_production_request_form"> <record model="ir.ui.view" id="view_mrp_production_request_form">
<field name="name">mrp.production.request.form</field> <field name="name">mrp.production.request.form</field>
<field name="model">mrp.production.request</field> <field name="model">mrp.production.request</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Manufacturing Request"> <form string="Manufacturing Request">
<header> <header>
<button name="button_draft" <button
name="button_draft"
states="to_approve,approved,cancel,done" states="to_approve,approved,cancel,done"
string="Reset" string="Reset"
type="object" type="object"
groups="mrp_production_request.group_mrp_production_request_manager"/> groups="mrp_production_request.group_mrp_production_request_manager"
<button name="button_to_approve" states="draft" />
string="Request approval" type="object" <button
class="oe_highlight"/> name="button_to_approve"
<button name="button_approved" states="to_approve" states="draft"
string="Approve" type="object" class="oe_highlight" string="Request approval"
groups="mrp_production_request.group_mrp_production_request_manager"/> type="object"
<button name="%(mrp_production_request_create_mo_action)d" class="oe_highlight"
/>
<button
name="button_approved"
states="to_approve"
string="Approve"
type="object"
class="oe_highlight"
groups="mrp_production_request.group_mrp_production_request_manager"
/>
<button
name="%(mrp_production_request_create_mo_action)d"
states="approved" states="approved"
string="Create Manufacturing Order" type="action"/> string="Create Manufacturing Order"
<button name="button_done" states="approved" type="action"
string="Done" type="object" class="oe_highlight" />
groups="mrp_production_request.group_mrp_production_request_manager"/> <button
<button name="button_cancel" states="to_approve,approved" name="button_done"
string="Reject" type="object" states="approved"
groups="mrp_production_request.group_mrp_production_request_manager"/> string="Done"
<field name="state" widget="statusbar" type="object"
statusbar_visible="draft,approved,done"/> class="oe_highlight"
groups="mrp_production_request.group_mrp_production_request_manager"
/>
<button
name="button_cancel"
states="to_approve,approved"
string="Reject"
type="object"
groups="mrp_production_request.group_mrp_production_request_manager"
/>
<field
name="state"
widget="statusbar"
statusbar_visible="draft,approved,done"
/>
</header> </header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<button type="object" name="action_view_mrp_productions" <button
type="object"
name="action_view_mrp_productions"
class="oe_stat_button" class="oe_stat_button"
icon="fa-wrench" icon="fa-wrench"
attrs="{'invisible': [('mrp_production_count', '=', 0)]}"> attrs="{'invisible': [('mrp_production_count', '=', 0)]}"
<field name="mrp_production_count" widget="statinfo" >
string="MOs"/> <field
name="mrp_production_count"
widget="statinfo"
string="MOs"
/>
</button> </button>
</div> </div>
<label for="name" string="Manufacturing Request" />
<label for="name" string="Manufacturing Request"/>
<h1> <h1>
<field name="name"/> <field name="name" />
</h1> </h1>
<group name="request"> <group name="request">
<group> <group>
<field name="product_id" <field
domain="[('bom_ids','!=',False),('bom_ids.type','!=','phantom')]"/> name="product_id"
<field name="product_tmpl_id" invisible="1"/> domain="[('bom_ids','!=',False),('bom_ids.type','!=','phantom')]"
<field name="bom_id" />
<field name="product_tmpl_id" invisible="1" />
<field
name="bom_id"
domain="['&amp;', '|', ('product_id','=',product_id), domain="['&amp;', '|', ('product_id','=',product_id),
'&amp;', ('product_tmpl_id.product_variant_ids','=',product_id), '&amp;', ('product_tmpl_id.product_variant_ids','=',product_id),
('product_id','=',False), ('type', '=', 'normal')]"/> ('product_id','=',False), ('type', '=', 'normal')]"
/>
</group> </group>
<group> <group>
<field name="product_qty"/> <field name="product_qty" />
<field name="done_qty"/> <field name="done_qty" />
<field name="manufactured_qty"/> <field name="manufactured_qty" />
<field name="pending_qty"/> <field name="pending_qty" />
<field name="product_uom_id" groups="uom.group_uom"/> <field name="product_uom_id" groups="uom.group_uom" />
<field name="category_uom_id" invisible="1"/> <field name="category_uom_id" invisible="1" />
</group> </group>
</group> </group>
<group> <group>
<group name="users"> <group name="users">
<field name="requested_by"/> <field name="requested_by" />
<field name="assigned_to"/> <field name="assigned_to" />
</group> </group>
<group name="dates"> <group name="dates">
<field name="date_planned_start"/> <field name="date_planned_start" />
<field name="date_planned_finished"/> <field name="date_planned_finished" />
</group> </group>
</group> </group>
<notebook> <notebook>
<page name="mrp_production" string="Manufacturing Orders"> <page name="mrp_production" string="Manufacturing Orders">
<field name="mrp_production_ids"/> <field name="mrp_production_ids" />
</page> </page>
<page name="extra" string="Extra information"> <page name="extra" string="Extra information">
<group> <group>
<group> <group>
<field name="location_src_id"/> <field name="location_src_id" />
<field name="location_dest_id"/> <field name="location_dest_id" />
<field name="picking_type_id"/> <field name="picking_type_id" />
</group> </group>
<group> <group>
<field name="origin"/> <field name="origin" />
<field name="description"/> <field name="description" />
</group> </group>
</group> </group>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/> <field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread"/> <field name="message_ids" widget="mail_thread" />
</div> </div>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_mrp_production_request_tree"> <record model="ir.ui.view" id="view_mrp_production_request_tree">
<field name="name">mrp.production.request.tree</field> <field name="name">mrp.production.request.tree</field>
<field name="model">mrp.production.request</field> <field name="model">mrp.production.request</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree decoration-info="state in ('draft','to_approve')" <tree
decoration-info="state in ('draft','to_approve')"
decoration-muted="state in ('cancel')" decoration-muted="state in ('cancel')"
string="Manufacturing Requests"> string="Manufacturing Requests"
<field name="name"/> >
<field name="product_id"/> <field name="name" />
<field name="requested_by"/> <field name="product_id" />
<field name="assigned_to"/> <field name="requested_by" />
<field name="product_qty"/> <field name="assigned_to" />
<field name="pending_qty"/> <field name="product_qty" />
<field name="company_id" groups="base.group_multi_company" widget="selection"/> <field name="pending_qty" />
<field name="origin"/> <field
<field name="date_planned_start"/> name="company_id"
<field name="state"/> groups="base.group_multi_company"
widget="selection"
/>
<field name="origin" />
<field name="date_planned_start" />
<field name="state" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="view_mrp_production_request_search" model="ir.ui.view"> <record id="view_mrp_production_request_search" model="ir.ui.view">
<field name="name">mrp.production.request.search</field> <field name="name">mrp.production.request.search</field>
<field name="model">mrp.production.request</field> <field name="model">mrp.production.request</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Manufacturing Request"> <search string="Search Manufacturing Request">
<field name="name" string="Manufacturing Request"/> <field name="name" string="Manufacturing Request" />
<field name="product_id"/> <field name="product_id" />
<field name="mrp_production_ids" string="Manufacturing Orders"/> <field name="mrp_production_ids" string="Manufacturing Orders" />
<field name="bom_id"/> <field name="bom_id" />
<field name="requested_by"/> <field name="requested_by" />
<field name="assigned_to"/> <field name="assigned_to" />
<field name="origin"/> <field name="origin" />
<field name="state"/> <field name="state" />
<field name="pending_qty" invisible="1"/> <field name="pending_qty" invisible="1" />
<!--Filters:--> <!--Filters:-->
<filter name="unassigned" string="Unassigned" <filter
name="unassigned"
string="Unassigned"
domain="[('assigned_to','=', False)]" domain="[('assigned_to','=', False)]"
help="Unassigned Request"/> help="Unassigned Request"
<filter name="assigned_to_me" />
<filter
name="assigned_to_me"
domain="[('assigned_to','=', uid)]" domain="[('assigned_to','=', uid)]"
string="Assigned to me"/> string="Assigned to me"
<filter name="requested_by_me" />
<filter
name="requested_by_me"
domain="[('requested_by','=', uid)]" domain="[('requested_by','=', uid)]"
string="My requests" help="Requested by me"/> string="My requests"
<separator/> help="Requested by me"
<filter name="pending" />
<separator />
<filter
name="pending"
domain="[('pending_qty','!=', 0.0)]" domain="[('pending_qty','!=', 0.0)]"
string="Pending Qty" string="Pending Qty"
help="Request with pending quantity"/> help="Request with pending quantity"
<separator/> />
<filter name="todo" string="To Do" <separator />
<filter
name="todo"
string="To Do"
domain="[('state','in',('draft', 'to_approve','approved'))]" domain="[('state','in',('draft', 'to_approve','approved'))]"
help="Manufacturing Requests not done or cancelled."/> help="Manufacturing Requests not done or cancelled."
<separator/> />
<filter name="state_draft" string="Draft" <separator />
<filter
name="state_draft"
string="Draft"
domain="[('state','=','draft')]" domain="[('state','=','draft')]"
help="Request is to be approved"/> help="Request is to be approved"
<filter name="state_to_approve" string="To Approve" />
<filter
name="state_to_approve"
string="To Approve"
domain="[('state','=','to_approve')]" domain="[('state','=','to_approve')]"
help="Request is to be approved"/> help="Request is to be approved"
<filter name="state_approved" string="Approved" />
<filter
name="state_approved"
string="Approved"
domain="[('state','=','approved')]" domain="[('state','=','approved')]"
help="Request is approved"/> help="Request is approved"
<filter name="state_cancel" string="Cancelled" />
<filter
name="state_cancel"
string="Cancelled"
domain="[('state','=','cancel')]" domain="[('state','=','cancel')]"
help="Request is cancelled"/> help="Request is cancelled"
<filter name="state_done" string="Done" />
<filter
name="state_done"
string="Done"
domain="[('state','=','done')]" domain="[('state','=','done')]"
help="Request is done"/> help="Request is done"
<separator/> />
<filter name="message_needaction" <separator />
<filter
name="message_needaction"
string="Unread Messages" string="Unread Messages"
domain="[('message_needaction','=',True)]"/> domain="[('message_needaction','=',True)]"
/>
<!--Group by:--> <!--Group by:-->
<filter name="requested_by_group_by" <filter
string="Requested by" icon="terp-personal" name="requested_by_group_by"
string="Requested by"
icon="terp-personal"
domain="[]" domain="[]"
context="{'group_by':'requested_by'}"/> context="{'group_by':'requested_by'}"
<filter name="assign_to_group_by" />
string="Assigned to" icon="terp-personal" <filter
name="assign_to_group_by"
string="Assigned to"
icon="terp-personal"
domain="[]" domain="[]"
context="{'group_by':'assigned_to'}"/> context="{'group_by':'assigned_to'}"
<filter name="origin_group_by" />
<filter
name="origin_group_by"
string="Source" string="Source"
domain="[]" domain="[]"
context="{'group_by':'origin'}"/> context="{'group_by':'origin'}"
/>
</search> </search>
</field> </field>
</record> </record>
<record model="ir.actions.act_window" id="mrp_production_request_action"> <record model="ir.actions.act_window" id="mrp_production_request_action">
<field name="name">Manufacturing Requests</field> <field name="name">Manufacturing Requests</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@@ -206,28 +279,25 @@
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
Click to start a new manufacturing request process. Click to start a new manufacturing request process.
</p><p> </p>
<p>
A Manufacturing Request is an instruction to production to produce A Manufacturing Request is an instruction to production to produce
a certain quantity of a given product. a certain quantity of a given product.
</p> </p>
</field> </field>
</record> </record>
<menuitem <menuitem
id="menu_mrp_production_request_act" id="menu_mrp_production_request_act"
sequence="10" sequence="10"
parent="mrp.menu_mrp_manufacturing" parent="mrp.menu_mrp_manufacturing"
action="mrp_production_request_action" action="mrp_production_request_action"
/> />
<!--Sever actions--> <!--Sever actions-->
<record id="action_server_mrp_production_request_refresh" <record id="action_server_mrp_production_request_refresh" model="ir.actions.server">
model="ir.actions.server">
<field name="name">Refresh Quantities</field> <field name="name">Refresh Quantities</field>
<field name="model_id" ref="model_mrp_production_request" /> <field name="model_id" ref="model_mrp_production_request" />
<field name="binding_model_id" ref="model_mrp_production_request"/> <field name="binding_model_id" ref="model_mrp_production_request" />
<field name="state">code</field> <field name="state">code</field>
<field name="code">records._compute_manufactured_qty()</field> <field name="code">records._compute_manufactured_qty()</field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,18 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo> <odoo>
<record id="mrp_production_form_view" model="ir.ui.view"> <record id="mrp_production_form_view" model="ir.ui.view">
<field name="name">mrp.production.form - mrp_production_request</field> <field name="name">mrp.production.form - mrp_production_request</field>
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
<field name="inherit_id" <field name="inherit_id" ref="mrp.mrp_production_form_view" />
ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="availability" position="after"> <field name="availability" position="after">
<field name="mrp_production_request_id"/> <field name="mrp_production_request_id" />
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,18 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo> <odoo>
<record model="ir.ui.view" id="view_template_property_form"> <record model="ir.ui.view" id="view_template_property_form">
<field name="name">product.template.form - mrp_production_request</field> <field name="name">product.template.form - mrp_production_request</field>
<field name="model">product.template</field> <field name="model">product.template</field>
<field name="inherit_id" <field name="inherit_id" ref="stock.view_template_property_form" />
ref="stock.view_template_property_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="route_ids" position="after"> <field name="route_ids" position="after">
<field name="mrp_production_request"/> <field name="mrp_production_request" />
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,10 +1,11 @@
# Copyright 2017-19 Eficent Business and IT Consulting Services S.L. # Copyright 2017-19 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _ from odoo import _, api, fields, models
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class MrpProductionRequestCreateMo(models.TransientModel): class MrpProductionRequestCreateMo(models.TransientModel):
_name = "mrp.production.request.create.mo" _name = "mrp.production.request.create.mo"
@@ -16,14 +17,16 @@ class MrpProductionRequestCreateMo(models.TransientModel):
res = self._prepare_lines() res = self._prepare_lines()
product_lines = res[1] product_lines = res[1]
for line in product_lines: for line in product_lines:
self.env['mrp.production.request.create.mo.line'].create( self.env["mrp.production.request.create.mo.line"].create(
self._prepare_product_line(line)) self._prepare_product_line(line)
)
self._get_mo_qty() self._get_mo_qty()
# The wizard must be reloaded in order to show the new product lines # The wizard must be reloaded in order to show the new product lines
action = self.env.ref( action = self.env.ref(
'mrp_production_request.mrp_production_request_create_mo_action') "mrp_production_request.mrp_production_request_create_mo_action"
)
res = action.read()[0] res = action.read()[0]
res['res_id'] = self.id res["res_id"] = self.id
return res return res
def _prepare_lines(self): def _prepare_lines(self):
@@ -32,70 +35,71 @@ class MrpProductionRequestCreateMo(models.TransientModel):
:return: boms_done, lines_done :return: boms_done, lines_done
""" """
bom_point = self.bom_id bom_point = self.bom_id
factor = self.mrp_production_request_id.product_uom_id.\ factor = self.mrp_production_request_id.product_uom_id._compute_quantity(
_compute_quantity(self.pending_qty, bom_point.product_uom_id) self.pending_qty, bom_point.product_uom_id
)
return bom_point.explode( return bom_point.explode(
self.mrp_production_request_id.product_id, self.mrp_production_request_id.product_id, factor / bom_point.product_qty
factor / bom_point.product_qty) )
@api.multi @api.multi
def _get_mo_qty(self): def _get_mo_qty(self):
"""Propose a qty to create a MO available to produce.""" """Propose a qty to create a MO available to produce."""
for rec in self: for rec in self:
bottle_neck = min(rec.product_line_ids.mapped( bottle_neck = min(rec.product_line_ids.mapped("bottle_neck_factor"))
'bottle_neck_factor'))
bottle_neck = max(min(1, bottle_neck), 0) bottle_neck = max(min(1, bottle_neck), 0)
rec.mo_qty = rec.pending_qty * bottle_neck rec.mo_qty = rec.pending_qty * bottle_neck
mrp_production_request_id = fields.Many2one( mrp_production_request_id = fields.Many2one(
comodel_name="mrp.production.request", readonly=True) comodel_name="mrp.production.request", readonly=True
bom_id = fields.Many2one( )
related='mrp_production_request_id.bom_id', readonly=True) bom_id = fields.Many2one(related="mrp_production_request_id.bom_id", readonly=True)
mo_qty = fields.Float( mo_qty = fields.Float(
string="Quantity", string="Quantity", digits=dp.get_precision("Product Unit of Measure")
digits=dp.get_precision("Product Unit of Measure")) )
pending_qty = fields.Float( pending_qty = fields.Float(
related="mrp_production_request_id.pending_qty", related="mrp_production_request_id.pending_qty",
digits=dp.get_precision("Product Unit of Measure")) digits=dp.get_precision("Product Unit of Measure"),
product_uom_id = fields.Many2one( )
related="mrp_production_request_id.product_uom_id") product_uom_id = fields.Many2one(related="mrp_production_request_id.product_uom_id")
product_line_ids = fields.One2many( product_line_ids = fields.One2many(
comodel_name="mrp.production.request.create.mo.line", comodel_name="mrp.production.request.create.mo.line",
string="Products needed", string="Products needed",
inverse_name="mrp_production_request_create_mo_id", readonly=True) inverse_name="mrp_production_request_create_mo_id",
date_planned_start = fields.Datetime( readonly=True,
string="Deadline Start",
required=True,
)
date_planned_finished = fields.Datetime(
string="Deadline End",
required=True,
) )
date_planned_start = fields.Datetime(string="Deadline Start", required=True,)
date_planned_finished = fields.Datetime(string="Deadline End", required=True,)
@api.model @api.model
def default_get(self, fields): def default_get(self, fields):
rec = super().default_get(fields) rec = super().default_get(fields)
active_ids = self._context.get('active_ids') active_ids = self._context.get("active_ids")
active_model = self._context.get('active_model') active_model = self._context.get("active_model")
if not active_ids: if not active_ids:
raise UserError(_( raise UserError(
_(
"Programming error: wizard action executed without " "Programming error: wizard action executed without "
"active_ids in context.")) "active_ids in context."
)
)
request = self.env[active_model].browse(active_ids) request = self.env[active_model].browse(active_ids)
rec.update({ rec.update(
'mrp_production_request_id': active_ids[0], {
'date_planned_start': request[0].date_planned_start, "mrp_production_request_id": active_ids[0],
'date_planned_finished': request[0].date_planned_finished, "date_planned_start": request[0].date_planned_start,
}) "date_planned_finished": request[0].date_planned_finished,
}
)
return rec return rec
def _prepare_product_line(self, pl): def _prepare_product_line(self, pl):
return { return {
'product_id': pl[0].product_id.id, "product_id": pl[0].product_id.id,
'product_qty': pl[1]['qty'], "product_qty": pl[1]["qty"],
'product_uom_id': pl[0].product_uom_id.id, "product_uom_id": pl[0].product_uom_id.id,
'mrp_production_request_create_mo_id': self.id, "mrp_production_request_create_mo_id": self.id,
'location_id': self.mrp_production_request_id.location_src_id.id, "location_id": self.mrp_production_request_id.location_src_id.id,
} }
@api.multi @api.multi
@@ -103,35 +107,34 @@ class MrpProductionRequestCreateMo(models.TransientModel):
self.ensure_one() self.ensure_one()
request_id = self.mrp_production_request_id request_id = self.mrp_production_request_id
return { return {
'product_id': request_id.product_id.id, "product_id": request_id.product_id.id,
'bom_id': request_id.bom_id.id, "bom_id": request_id.bom_id.id,
'product_qty': self.mo_qty, "product_qty": self.mo_qty,
'product_uom_id': self.product_uom_id.id, "product_uom_id": self.product_uom_id.id,
'mrp_production_request_id': self.mrp_production_request_id.id, "mrp_production_request_id": self.mrp_production_request_id.id,
'origin': request_id.origin, "origin": request_id.origin,
'location_src_id': request_id.location_src_id.id, "location_src_id": request_id.location_src_id.id,
'location_dest_id': request_id.location_dest_id.id, "location_dest_id": request_id.location_dest_id.id,
'picking_type_id': request_id.picking_type_id.id, "picking_type_id": request_id.picking_type_id.id,
'routing_id': request_id.routing_id.id, "routing_id": request_id.routing_id.id,
'date_planned_start': self.date_planned_start, "date_planned_start": self.date_planned_start,
'date_planned_finished': self.date_planned_finished, "date_planned_finished": self.date_planned_finished,
'procurement_group_id': request_id.procurement_group_id.id, "procurement_group_id": request_id.procurement_group_id.id,
'propagate': request_id.propagate, "propagate": request_id.propagate,
'company_id': request_id.company_id.id, "company_id": request_id.company_id.id,
} }
@api.multi @api.multi
def create_mo(self): def create_mo(self):
self.ensure_one() self.ensure_one()
vals = self._prepare_manufacturing_order() vals = self._prepare_manufacturing_order()
mo = self.env['mrp.production'].create(vals) mo = self.env["mrp.production"].create(vals)
# Open resulting MO: # Open resulting MO:
action = self.env.ref('mrp.mrp_production_action').read()[0] action = self.env.ref("mrp.mrp_production_action").read()[0]
res = self.env.ref('mrp.mrp_production_form_view') res = self.env.ref("mrp.mrp_production_form_view")
action.update({ action.update(
'res_id': mo and mo.id, {"res_id": mo and mo.id, "views": [(res and res.id or False, "form")],}
'views': [(res and res.id or False, 'form')], )
})
return action return action
@@ -143,11 +146,13 @@ class MrpProductionRequestCreateMoLine(models.TransientModel):
def _compute_available_qty(self): def _compute_available_qty(self):
for rec in self: for rec in self:
product_available = rec.product_id.with_context( product_available = rec.product_id.with_context(
location=rec.location_id.id).\ location=rec.location_id.id
_compute_product_available_not_res_dict()[ )._compute_product_available_not_res_dict()[rec.product_id.id][
rec.product_id.id]['qty_available_not_res'] "qty_available_not_res"
]
res = rec.product_id.product_tmpl_id.uom_id._compute_quantity( res = rec.product_id.product_tmpl_id.uom_id._compute_quantity(
product_available, rec.product_uom_id) product_available, rec.product_uom_id
)
rec.available_qty = res rec.available_qty = res
@api.multi @api.multi
@@ -157,19 +162,23 @@ class MrpProductionRequestCreateMoLine(models.TransientModel):
rec.bottle_neck_factor = rec.available_qty / rec.product_qty rec.bottle_neck_factor = rec.available_qty / rec.product_qty
product_id = fields.Many2one( product_id = fields.Many2one(
comodel_name='product.product', string='Product', required=True) comodel_name="product.product", string="Product", required=True
)
product_qty = fields.Float( product_qty = fields.Float(
string='Quantity Required', required=True, string="Quantity Required",
digits=dp.get_precision('Product Unit of Measure')) required=True,
digits=dp.get_precision("Product Unit of Measure"),
)
product_uom_id = fields.Many2one( product_uom_id = fields.Many2one(
comodel_name='uom.uom', string='UoM', required=True) comodel_name="uom.uom", string="UoM", required=True
)
mrp_production_request_create_mo_id = fields.Many2one( mrp_production_request_create_mo_id = fields.Many2one(
comodel_name='mrp.production.request.create.mo') comodel_name="mrp.production.request.create.mo"
)
available_qty = fields.Float( available_qty = fields.Float(
string='Quantity Available', compute='_compute_available_qty', string="Quantity Available",
digits=dp.get_precision('Product Unit of Measure')) compute="_compute_available_qty",
bottle_neck_factor = fields.Float( digits=dp.get_precision("Product Unit of Measure"),
compute='_compute_bottle_neck_factor') )
location_id = fields.Many2one( bottle_neck_factor = fields.Float(compute="_compute_bottle_neck_factor")
comodel_name='stock.location', location_id = fields.Many2one(comodel_name="stock.location", required=True)
required=True)

View File

@@ -1,61 +1,70 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. <!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo> <odoo>
<record id="mrp_production_request_create_mo_view" model="ir.ui.view"> <record id="mrp_production_request_create_mo_view" model="ir.ui.view">
<field name="name">mrp.production.request.create.mo.form</field> <field name="name">mrp.production.request.create.mo.form</field>
<field name="model">mrp.production.request.create.mo</field> <field name="model">mrp.production.request.create.mo</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Select event to register"> <form string="Select event to register">
<group name="origin" string="Manufacture Request status" <group name="origin" string="Manufacture Request status" col="6">
col="6">
<group colspan="2"> <group colspan="2">
<field name="mrp_production_request_id" <field
options='{"no_open": True}'/> name="mrp_production_request_id"
<field name="pending_qty"/> options='{"no_open": True}'
<button name="compute_product_line_ids" type="object" />
string="Compute lines" colspan="2" icon="fa-cogs"/> <field name="pending_qty" />
<button
name="compute_product_line_ids"
type="object"
string="Compute lines"
colspan="2"
icon="fa-cogs"
/>
</group> </group>
<group colspan="4"> <group colspan="4">
<field name="product_line_ids" nolabel="1"> <field name="product_line_ids" nolabel="1">
<tree> <tree>
<field name="product_id"/> <field name="product_id" />
<field name="product_uom_id"/> <field name="product_uom_id" />
<field name="product_qty"/> <field name="product_qty" />
<field name="available_qty"/> <field name="available_qty" />
<field name="bottle_neck_factor"/> <field name="bottle_neck_factor" />
</tree> </tree>
</field> </field>
</group> </group>
</group> </group>
<group name="destination" string="Manufacturing Order:"> <group name="destination" string="Manufacturing Order:">
<group name="product_qty"> <group name="product_qty">
<label for="mo_qty"/> <label for="mo_qty" />
<div> <div>
<field name="mo_qty" class="oe_inline"/> <field name="mo_qty" class="oe_inline" />
<field name="product_uom_id" class="oe_inline" options="{'no_open': True}" groups="uom.group_uom"/> <field
name="product_uom_id"
class="oe_inline"
options="{'no_open': True}"
groups="uom.group_uom"
/>
</div> </div>
</group> </group>
<group name="date_planned"> <group name="date_planned">
<field name="date_planned_start"/> <field name="date_planned_start" />
<field name="date_planned_finished"/> <field name="date_planned_finished" />
</group> </group>
</group> </group>
<footer> <footer>
<button name="create_mo" <button
name="create_mo"
type="object" type="object"
string="Create MO" string="Create MO"
class="oe_highlight"/> class="oe_highlight"
/>
or or
<button special="cancel" <button special="cancel" string="Cancel" />
string="Cancel"/>
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record id="mrp_production_request_create_mo_action" model="ir.actions.act_window"> <record id="mrp_production_request_create_mo_action" model="ir.actions.act_window">
<field name="name">Create Manufacturing Order</field> <field name="name">Create Manufacturing Order</field>
<field name="res_model">mrp.production.request.create.mo</field> <field name="res_model">mrp.production.request.create.mo</field>
@@ -63,5 +72,4 @@
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
</odoo> </odoo>

View File

@@ -0,0 +1 @@
../../../../mrp_production_request

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)