[IMP] mrp_production_grouped_by_company: Context evaluation on mrp.production + tests

This commit is contained in:
Pedro M. Baeza
2018-05-10 21:03:59 +02:00
committed by Lois Rilo
parent 97c1425c8e
commit 3a3a2fac6b
5 changed files with 105 additions and 79 deletions

View File

@@ -6,11 +6,14 @@
Production Grouped By Product
=============================
Groups pending productions by product.
Configuration
=============
When you have several sales orders with make to (MTO) order products that
require to be manufactured, you end up with one manufacturing order for each of
these sales orders, which is very bad for the management.
With this module, each time an MTO manufacturing order is required to be
created, it first checks that there's no other existing order not yet started
for the same product and bill of materials, and if there's one, then the
quantity of that order is increased instead of creating a new one.
Usage
=====
@@ -19,6 +22,11 @@ Usage
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/129/11.0
Known issues / Roadmap
======================
* Add a check in the product form for excluding it from being grouped.
Bug Tracker
===========
@@ -38,7 +46,12 @@ Images
Contributors
------------
* David Vidal <david.vidal@tecnativa.com>
* Tecnativa <https://www.tecnativa.com>_
* David Vidal
* Pedro M. Baeza
Do not contact contributors directly about support or help with technical issues.
Maintainer
----------

View File

@@ -1,4 +1,5 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{

View File

@@ -1,15 +1,51 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import api, models
from odoo.tools import config
class MrpProduction(models.Model):
_inherit = 'mrp.production'
def _post_mo_merging_adjustments(self, vals):
"""Called when a new MO is merged onto existing one for adjusting the
needed values according this merging.
:param self: Single record of the target record where merging.
:param vals: Dictionary with the new record values.
"""
self.ensure_one()
new_vals = {
'origin': (self.origin or '') + ",%s" % vals['origin'],
}
if vals.get('move_dest_ids'):
new_vals['move_dest_ids'] = vals['move_dest_ids']
self.move_finished_ids.move_dest_ids = vals['move_dest_ids']
self.write(new_vals)
def _find_grouping_target(self, vals):
mo = self.env['mrp.production'].search([
('product_id', '=', vals['product_id']),
('bom_id', '=', vals.get('bom_id', False)),
('routing_id', '=', vals.get('routing_id', False)),
('company_id', '=', vals.get('company_id', False)),
('state', '=', 'confirmed'),
], limit=1)
return mo
@api.model
def create(self, vals):
if not self._context.get('merge_products_into_mo'):
context = self.env.context
if (context.get('group_mo_by_product') and
(not config['test_enable'] or context.get('test_group_mo'))):
mo = self._find_grouping_target(vals)
if mo:
self.env['change.production.qty'].create({
'mo_id': mo.id,
'product_qty': mo.product_qty + vals['product_qty'],
}).change_prod_qty()
mo._post_mo_merging_adjustments(vals)
return mo
return super(MrpProduction, self).create(vals)
# We return the MO to merge into
return self._context.get('merge_products_into_mo')

View File

@@ -1,44 +1,18 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import models
class ProcuermentRule(models.Model):
class ProcurementRule(models.Model):
_inherit = 'procurement.rule'
def _run_manufacture(self, product_id, product_qty, product_uom,
location_id, name, origin, values):
bom = self._get_matching_bom(product_id, values)
# Send to super for exception
if not bom:
return super(ProcuermentRule, self)._run_manufacture(
product_id, product_qty, product_uom, location_id,
name, origin, values)
open_mo = self._find_equal_open_mo(
product_id, bom, location_id, values)
# Create mo as usual
if not open_mo:
return super(ProcuermentRule, self)._run_manufacture(
product_id, product_qty, product_uom, location_id,
name, origin, values)
# Add product qty to mo
self.env['change.production.qty'].create({
'mo_id': open_mo.id,
'product_qty': open_mo.product_qty + product_qty,
}).change_prod_qty()
# We pass the record in the context so the chatter is correctly written
additional_context={'merge_products_into_mo': open_mo}
return super(ProcuermentRule, self.with_context(**additional_context)
)._run_manufacture(product_id, product_qty, product_uom,
location_id,name, origin, values)
def _find_equal_open_mo(self, product_id, bom, location_id, values):
"""Returns the first occurrence according to conditions"""
return self.env['mrp.production'].search([
('state', 'not in', ['progress', 'done', 'cancel']),
('product_id', '=', product_id.id),
('bom_id', '=', bom.id),
('location_dest_id', '=', location_id.id),
('company_id', '=', values.get('company_id').id),
], limit=1)
return super(
ProcurementRule, self.with_context(group_mo_by_product=True),
)._run_manufacture(
product_id, product_qty, product_uom, location_id, name, origin,
values,
)

View File

@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests import common
class TestProductionGroupedByProduct(common.SavepointCase):
at_install = False
post_install = True
@classmethod
def setUpClass(cls):
@@ -36,14 +38,6 @@ class TestProductionGroupedByProduct(common.SavepointCase):
'product_qty': 0.2,
})]
})
cls.env['stock.change.product.qty'].create({
'product_id': cls.product2.id,
'new_quantity': 100.0,
}).change_product_qty()
cls.env['stock.change.product.qty'].create({
'product_id': cls.product3.id,
'new_quantity': 100.0,
}).change_product_qty()
cls.stock_picking_type = cls.env.ref('stock.picking_type_out')
cls.procurement_rule = cls.env['stock.warehouse.orderpoint'].create({
'name': 'XXX/00000',
@@ -51,35 +45,43 @@ class TestProductionGroupedByProduct(common.SavepointCase):
'product_min_qty': 10,
'product_max_qty': 100,
})
cls.mo = cls.env['mrp.production'].create({
'bom_id': cls.bom.id,
'product_id': cls.product1.id,
'product_qty': 2,
'product_uom_id': cls.product1.uom_id.id,
})
cls.warehouse = cls.env['stock.warehouse'].search([
('company_id', '=', cls.env.user.company_id.id),
], limit=1)
cls.ProcurementGroup = cls.env['procurement.group']
cls.MrpProduction = cls.env['mrp.production']
def test_mo_by_product(self):
self.env['procurement.group'].run_scheduler()
mo = self.env['mrp.production'].search([
('product_id', '=', self.product1.id),
])
self.assertTrue(mo)
#
picking = self.env['stock.picking'].create({
'picking_type_id': self.stock_picking_type.id,
'location_id': self.env.ref('stock.stock_location_stock').id,
'location_dest_id': self.env.ref(
'stock.stock_location_customers').id,
})
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([('product_id', '=', self.product1.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 100)
# Add an MTO move
move = self.env['stock.move'].create({
'name': self.product1.name,
'product_id': self.product1.id,
'product_uom_qty': 1000,
'product_uom_qty': 10,
'product_uom': self.product1.uom_id.id,
'picking_id': picking.id,
'picking_type_id': self.stock_picking_type.id,
'location_id': picking.location_id.id,
'location_dest_id': picking.location_id.id,
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': (
self.env.ref('stock.stock_location_customers').id
),
'procure_method': 'make_to_order',
'warehouse_id': self.warehouse.id,
})
move.quantity_done = 1000
picking.action_assign()
self.product1.virtual_available = -500
self.env['procurement.group'].run_scheduler()
mo = self.env['mrp.production'].search([
('product_id', '=', self.product1.id),
])
move.with_context(test_group_mo=True)._action_confirm(merge=False)
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([('product_id', '=', self.product1.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 110)
# Run again the scheduler to see if quantities are altered
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([('product_id', '=', self.product1.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 110)