mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[IMP] mrp_production_grouped_by_company: Context evaluation on mrp.production + tests
This commit is contained in:
committed by
Lois Rilo
parent
97c1425c8e
commit
3a3a2fac6b
@@ -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
|
||||
----------
|
||||
|
||||
@@ -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).
|
||||
|
||||
{
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user