diff --git a/mrp_multi_level/README.rst b/mrp_multi_level/README.rst index bbbf73e0c..1b79418f4 100644 --- a/mrp_multi_level/README.rst +++ b/mrp_multi_level/README.rst @@ -50,20 +50,29 @@ Key Features Configuration ============= -* Go to *Manufacturing > MRP > MRP Area* and define or edit any existing area. - You can specify the working hours for every area. +MRP Areas +~~~~~~~~~ + +* Go to *Manufacturing > Configuration > MRP Areas* and define or edit + any existing area. You can specify the working hours for every area. + +Product MRP Area Parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Go to *Manufacturing > Master Data > Product MRP Area Parameters* and set + the MRP parameters for a given product and area. Usage ===== To manually run the MRP scheduler: -#. Go to *Manufacturing > MRP > Run MRP Multi Level*. +#. Go to *Manufacturing > Operations > Run MRP Multi Level*. #. On the wizard click *Run MRP*. To launch replenishment orders (moves, purchases, production orders...): -#. Go to *Manufacturing > MRP > MRP Inventory*. +#. Go to *Manufacturing > Operations > MRP Inventory*. #. Filter with *To procure*. #. Select multiple records and click on *Action > Procure* or click the right hand side gears in any record. @@ -78,6 +87,17 @@ Known issues / Roadmap Changelog ========= +11.0.2.0.0 (2018-11-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW] Refactor MRP Area. + (`#322 `_): + + * MRP product concept dropped in favor of *Product MRP Area Parameters*. + This allow to set different MRP parameters for the same product in + different areas. + * Menu items reordering. + 11.0.1.1.0 (2018-08-30) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/mrp_multi_level/__manifest__.py b/mrp_multi_level/__manifest__.py index 9c7b597e0..f32d72a20 100644 --- a/mrp_multi_level/__manifest__.py +++ b/mrp_multi_level/__manifest__.py @@ -38,9 +38,9 @@ 'demo': [ 'demo/product_category_demo.xml', 'demo/product_product_demo.xml', - 'demo/product_product_demo.xml', - 'demo/product_mrp_area_demo.xml', + 'demo/res_partner_demo.xml', 'demo/product_supplierinfo_demo.xml', + 'demo/product_mrp_area_demo.xml', 'demo/mrp_bom_demo.xml', 'demo/initial_on_hand_demo.xml', ], diff --git a/mrp_multi_level/models/mrp_inventory.py b/mrp_multi_level/models/mrp_inventory.py index e8a36adfb..64f472888 100644 --- a/mrp_multi_level/models/mrp_inventory.py +++ b/mrp_multi_level/models/mrp_inventory.py @@ -17,7 +17,6 @@ class MrpInventory(models.Model): # TODO: name to pass to procurements? # TODO: compute procurement_date to pass to the wizard? not needed for # PO at least. Check for MO and moves - # TODO: substract qty already procured. # TODO: show a LT based on the procure method? mrp_area_id = fields.Many2one( @@ -25,9 +24,14 @@ class MrpInventory(models.Model): related='product_mrp_area_id.mrp_area_id', store=True, ) product_mrp_area_id = fields.Many2one( - comodel_name='product.mrp.area', string='Product', + comodel_name='product.mrp.area', string='Product Parameters', index=True, ) + product_id = fields.Many2one( + comodel_name='product.product', + related='product_mrp_area_id.product_id', + store=True, + ) uom_id = fields.Many2one( comodel_name='product.uom', string='Product UoM', compute='_compute_uom_id', diff --git a/mrp_multi_level/models/product_mrp_area.py b/mrp_multi_level/models/product_mrp_area.py index 780edd4ab..682b4bd2e 100644 --- a/mrp_multi_level/models/product_mrp_area.py +++ b/mrp_multi_level/models/product_mrp_area.py @@ -11,19 +11,21 @@ class ProductMRPArea(models.Model): _description = 'Product MRP Area' active = fields.Boolean(default=True) - mrp_area_id = fields.Many2one('mrp.area', - required=True, - ) - product_id = fields.Many2one('product.product', - required=True, - string='Product', - ) - product_tmpl_id = fields.Many2one('product.template', - readonly=True, - related='product_id.product_tmpl_id', - store=True, - ) - + mrp_area_id = fields.Many2one( + comodel_name='mrp.area', + required=True, + ) + product_id = fields.Many2one( + comodel_name='product.product', + required=True, + string='Product', + ) + product_tmpl_id = fields.Many2one( + comodel_name='product.template', + readonly=True, + related='product_id.product_tmpl_id', + store=True, + ) # TODO: applicable and exclude... redundant?? mrp_applicable = fields.Boolean(string='MRP Applicable') mrp_exclude = fields.Boolean(string='Exclude from MRP') @@ -71,10 +73,11 @@ class ProductMRPArea(models.Model): qty_available = fields.Float('Quantity Available', compute='_compute_qty_available') - mrp_move_ids = fields.One2many(comodel_name='mrp.move', - inverse_name='product_mrp_area_id', - readonly=True, - ) + mrp_move_ids = fields.One2many( + comodel_name='mrp.move', + inverse_name='product_mrp_area_id', + readonly=True, + ) _sql_constraints = [ ('product_mrp_area_uniq', 'unique(product_id, mrp_area_id)', 'The product/MRP Area parameters combination must be unique.'), @@ -89,17 +92,9 @@ class ProductMRPArea(models.Model): @api.multi def _compute_qty_available(self): for rec in self: - qty_available = 0.0 - product_obj = self.env['product.product'] # TODO: move mrp_qty_available computation, maybe unreserved?? - location_ids = self.env['stock.location'].search( - [('id', 'child_of', - rec.mrp_area_id.location_id.id)]) - for location in location_ids: - product_l = product_obj.with_context( - {'location': location.id}).browse(rec.product_id.id) - qty_available += product_l.qty_available - rec.qty_available = qty_available + rec.qty_available = rec.product_id.with_context( + {'location': rec.mrp_area_id.location_id.id}).qty_available @api.multi def _compute_supply_method(self): @@ -115,7 +110,8 @@ class ProductMRPArea(models.Model): rec.supply_method = rule.action if rule else 'none' @api.multi - @api.depends('supply_method') + @api.depends('supply_method', 'product_id.route_ids', + 'product_id.seller_ids') def _compute_main_supplier(self): """Simplified and similar to procurement.rule logic.""" for rec in self.filtered(lambda r: r.supply_method == 'buy'): diff --git a/mrp_multi_level/models/product_product.py b/mrp_multi_level/models/product_product.py index f0ed768c8..e20078512 100644 --- a/mrp_multi_level/models/product_product.py +++ b/mrp_multi_level/models/product_product.py @@ -28,7 +28,8 @@ class Product(models.Model): mrp_area_count = fields.Integer( string='MRP Area Parameter Count', readonly=True, - compute='_compute_mrp_area_count') + compute='_compute_mrp_area_count', + ) @api.multi def _compute_mrp_area_count(self): @@ -40,12 +41,11 @@ class Product(models.Model): self.ensure_one() action = self.env.ref('mrp_multi_level.product_mrp_area_action') result = action.read()[0] - product_ids = self.ids - if len(product_ids) > 1: - result['domain'] = [('product_id', 'in', product_ids)] + area_ids = self.mrp_area_ids.ids + if self.mrp_area_count != 1: + result['domain'] = [('id', 'in', area_ids)] else: res = self.env.ref('mrp_multi_level.product_mrp_area_form', False) result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = product_ids[0] - result['context'] = {'default_product_id': product_ids[0]} + result['res_id'] = area_ids[0] return result diff --git a/mrp_multi_level/models/product_template.py b/mrp_multi_level/models/product_template.py index 67b8e76be..48e43ba97 100644 --- a/mrp_multi_level/models/product_template.py +++ b/mrp_multi_level/models/product_template.py @@ -15,7 +15,8 @@ class ProductTemplate(models.Model): mrp_area_count = fields.Integer( string='MRP Area Parameter Count', readonly=True, - compute='_compute_mrp_area_count') + compute='_compute_mrp_area_count', + ) @api.multi def _compute_mrp_area_count(self): @@ -29,12 +30,10 @@ class ProductTemplate(models.Model): result = action.read()[0] mrp_area_ids = self.with_context( active_test=False).mrp_area_ids.ids - if len(mrp_area_ids) > 1: + if len(mrp_area_ids) != 1: result['domain'] = [('id', 'in', mrp_area_ids)] else: res = self.env.ref('mrp_multi_level.product_mrp_area_form', False) result['views'] = [(res and res.id or False, 'form')] result['res_id'] = mrp_area_ids[0] - result['context'] = { - 'default_product_id': self.product_variant_ids[0].id} return result diff --git a/mrp_multi_level/readme/CONFIGURE.rst b/mrp_multi_level/readme/CONFIGURE.rst index 7237643b8..3825da541 100644 --- a/mrp_multi_level/readme/CONFIGURE.rst +++ b/mrp_multi_level/readme/CONFIGURE.rst @@ -1,2 +1,11 @@ -* Go to *Manufacturing > MRP > MRP Area* and define or edit any existing area. - You can specify the working hours for every area. +MRP Areas +~~~~~~~~~ + +* Go to *Manufacturing > Configuration > MRP Areas* and define or edit + any existing area. You can specify the working hours for every area. + +Product MRP Area Parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Go to *Manufacturing > Master Data > Product MRP Area Parameters* and set + the MRP parameters for a given product and area. diff --git a/mrp_multi_level/readme/HISTORY.rst b/mrp_multi_level/readme/HISTORY.rst index 01bd8c4d1..03ff5468e 100644 --- a/mrp_multi_level/readme/HISTORY.rst +++ b/mrp_multi_level/readme/HISTORY.rst @@ -1,3 +1,14 @@ +11.0.2.0.0 (2018-11-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW] Refactor MRP Area. + (`#322 `_): + + * MRP product concept dropped in favor of *Product MRP Area Parameters*. + This allow to set different MRP parameters for the same product in + different areas. + * Menu items reordering. + 11.0.1.1.0 (2018-08-30) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/mrp_multi_level/readme/USAGE.rst b/mrp_multi_level/readme/USAGE.rst index fc56ab031..6e28dce46 100644 --- a/mrp_multi_level/readme/USAGE.rst +++ b/mrp_multi_level/readme/USAGE.rst @@ -1,11 +1,11 @@ To manually run the MRP scheduler: -#. Go to *Manufacturing > MRP > Run MRP Multi Level*. +#. Go to *Manufacturing > Operations > Run MRP Multi Level*. #. On the wizard click *Run MRP*. To launch replenishment orders (moves, purchases, production orders...): -#. Go to *Manufacturing > MRP > MRP Inventory*. +#. Go to *Manufacturing > Operations > MRP Inventory*. #. Filter with *To procure*. #. Select multiple records and click on *Action > Procure* or click the right hand side gears in any record. diff --git a/mrp_multi_level/static/description/index.html b/mrp_multi_level/static/description/index.html index 284ec77a8..8fc23d952 100644 --- a/mrp_multi_level/static/description/index.html +++ b/mrp_multi_level/static/description/index.html @@ -386,41 +386,56 @@ and explodes this down to the lowest level.

Table of contents

-

Configuration

+

Configuration

+
+

MRP Areas

    -
  • Go to Manufacturing > MRP > MRP Area and define or edit any existing area. -You can specify the working hours for every area.
  • +
  • Go to Manufacturing > Configuration > MRP Areas and define or edit +any existing area. You can specify the working hours for every area.
+
+

Product MRP Area Parameters

+
    +
  • Go to Manufacturing > Master Data > Product MRP Area Parameters and set +the MRP parameters for a given product and area.
  • +
+
+
-

Usage

+

Usage

To manually run the MRP scheduler:

    -
  1. Go to Manufacturing > MRP > Run MRP Multi Level.
  2. +
  3. Go to Manufacturing > Operations > Run MRP Multi Level.
  4. On the wizard click Run MRP.

To launch replenishment orders (moves, purchases, production orders…):

    -
  1. Go to Manufacturing > MRP > MRP Inventory.
  2. +
  3. Go to Manufacturing > Operations > MRP Inventory.
  4. Filter with To procure.
  5. Select multiple records and click on Action > Procure or click the right hand side gears in any record.
  6. @@ -428,23 +443,36 @@ hand side gears in any record.
-

Known issues / Roadmap

+

Known issues / Roadmap

  • The functionality related to field Nbr. Days in products is not functional for the time being. Please, stay tuned to future updates.
-

Changelog

+

Changelog

-

11.0.1.1.0 (2018-08-30)

+

11.0.2.0.0 (2018-11-20)

+
    +
  • [REW] Refactor MRP Area. +(#322):
      +
    • MRP product concept dropped in favor of Product MRP Area Parameters. +This allow to set different MRP parameters for the same product in +different areas.
    • +
    • Menu items reordering.
    • +
    +
  • +
+
+
+

11.0.1.1.0 (2018-08-30)

  • [FIX] Consider Qty Multiple on product to propose the quantity to procure. (#297)
-
-

11.0.1.0.1 (2018-08-03)

+
+

11.0.1.0.1 (2018-08-03)

  • [FIX] User and system locales doesn’t break MRP calculation. (#290)
  • @@ -453,15 +481,15 @@ as a related on MRP Areas. (#290)
-
-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed @@ -469,16 +497,16 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Ucamco
  • Eficent
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose diff --git a/mrp_multi_level/tests/test_mrp_multi_level.py b/mrp_multi_level/tests/test_mrp_multi_level.py index 1d638fd65..c417a1fe1 100644 --- a/mrp_multi_level/tests/test_mrp_multi_level.py +++ b/mrp_multi_level/tests/test_mrp_multi_level.py @@ -23,7 +23,7 @@ class TestMrpMultiLevel(SavepointCase): cls.estimate_obj = cls.env['stock.demand.estimate'] cls.mrp_multi_level_wiz = cls.env['mrp.multi.level'] cls.mrp_inventory_procure_wiz = cls.env['mrp.inventory.procure'] - cls.mrp_inventory_obj = cls.env['mrp.inventory'] + cls.mrp_inventory_obj = cls.env['mrp.inventory'] cls.mrp_move_obj = cls.env['mrp.move'] cls.fp_1 = cls.env.ref('mrp_multi_level.product_product_fp_1') @@ -417,9 +417,9 @@ class TestMrpMultiLevel(SavepointCase): expected = [200.0, 290.0, 90.0, 0.0, 72.0, 0.0] self.assertEqual(moves.mapped('running_availability'), expected) # Actions counters for PP-1: - product_mrp_area = self.product_mrp_area_obj.search([ - ('product_id', '=', self.pp_1.id) - ]) + # product_mrp_area = self.product_mrp_area_obj.search([ + # ('product_id', '=', self.pp_1.id) + # ]) # TODO # self.assertEqual(product_mrp_area.nbr_mrp_actions, 3) # TODO # self.assertEqual(product_mrp_area.nbr_mrp_actions_4w, 3) # TODO diff --git a/mrp_multi_level/views/mrp_inventory_views.xml b/mrp_multi_level/views/mrp_inventory_views.xml index 484df5d7b..0e804683e 100644 --- a/mrp_multi_level/views/mrp_inventory_views.xml +++ b/mrp_multi_level/views/mrp_inventory_views.xml @@ -11,6 +11,7 @@ + @@ -35,7 +36,7 @@ - + @@ -84,7 +85,7 @@ - + diff --git a/mrp_multi_level/views/product_mrp_area_views.xml b/mrp_multi_level/views/product_mrp_area_views.xml index 8ab78a361..aeb2eed4d 100644 --- a/mrp_multi_level/views/product_mrp_area_views.xml +++ b/mrp_multi_level/views/product_mrp_area_views.xml @@ -59,6 +59,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -70,10 +92,8 @@ search - - - - + + diff --git a/mrp_multi_level/wizards/mrp_multi_level.py b/mrp_multi_level/wizards/mrp_multi_level.py index 16269844f..5ace1b235 100644 --- a/mrp_multi_level/wizards/mrp_multi_level.py +++ b/mrp_multi_level/wizards/mrp_multi_level.py @@ -70,12 +70,6 @@ class MultiLevelMrp(models.TransientModel): @api.model def _prepare_mrp_move_data_from_stock_move( self, product_mrp_area, move, direction='in'): - if not((move.location_id.usage == 'internal' and - move.location_dest_id.usage != 'internal') - or (move.location_id.usage != 'internal' and - move.location_dest_id.usage == 'internal')): - # TODO: not sure about this 'if'... - return {} if direction == 'out': mrp_type = 'd' product_qty = -move.product_qty @@ -416,7 +410,8 @@ class MultiLevelMrp(models.TransientModel): return True @api.model - def _prepare_mrp_move_data_from_purchase_order(self, poline, product_mrp_area): + def _prepare_mrp_move_data_from_purchase_order( + self, poline, product_mrp_area): mrp_date = date.today() if fields.Date.from_string(poline.date_planned) > date.today(): mrp_date = fields.Date.from_string(poline.date_planned) @@ -497,7 +492,8 @@ class MultiLevelMrp(models.TransientModel): for mrp_area in mrp_areas: for product_mrp_area in product_mrp_areas.filtered( lambda a: a.mrp_area_id == mrp_area): - if product_mrp_area.mrp_exclude: + if self._exclude_from_mrp( + product_mrp_area.product_id, mrp_area): continue init_counter += 1 log_msg = 'MRP INIT: %s - %s ' % ( @@ -615,7 +611,8 @@ class MultiLevelMrp(models.TransientModel): if onhand < product_mrp_area.mrp_minimum_stock and \ nbr_create == 0: - qtytoorder = product_mrp_area.mrp_minimum_stock - onhand + qtytoorder = \ + product_mrp_area.mrp_minimum_stock - onhand cm = self.create_move( product_mrp_area_id=product_mrp_area, mrp_date=date.today(),