diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index a7adae93ebf..67271810c0a 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -139,6 +139,13 @@ class procurement_order(osv.osv): raise UserError(_('Cannot delete Procurement Order(s) which are in %s state.') % s['state']) return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) + def create(self, cr, uid, vals, context=None): + context = context or {} + procurement_id = super(procurement_order, self).create(cr, uid, vals, context=context) + if not context.get('procurement_autorun_defer'): + self.run(cr, uid, [procurement_id], context=context) + return procurement_id + def do_view_procurements(self, cr, uid, ids, context=None): ''' This function returns an action that display existing procurement orders diff --git a/addons/procurement/test/procurement.yml b/addons/procurement/test/procurement.yml index f9774f70e7b..1f89e28bbdb 100644 --- a/addons/procurement/test/procurement.yml +++ b/addons/procurement/test/procurement.yml @@ -7,11 +7,6 @@ product_id: product.product_product_32 product_qty: 15.0 product_uom: product.product_uom_unit -- - I run the scheduler. -- - !python {model: procurement.order}: | - self.run_scheduler(cr, uid) - I check that procurement order is in exception, as at first there isn't any suitable rule - diff --git a/addons/procurement_jit/__init__.py b/addons/procurement_jit/__init__.py index 93f0b78639b..1047b552da3 100644 --- a/addons/procurement_jit/__init__.py +++ b/addons/procurement_jit/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import procurement_jit import sale diff --git a/addons/procurement_jit/__openerp__.py b/addons/procurement_jit/__openerp__.py index a6faf73dd69..740bc457aa3 100644 --- a/addons/procurement_jit/__openerp__.py +++ b/addons/procurement_jit/__openerp__.py @@ -7,24 +7,25 @@ 'version': '1.0', 'category': 'Base', 'description': """ -This module allows Just In Time computation of procurement orders. -================================================================== +This module will automatically reserve the picking from stock when a sale order is confirmed +============================================================================================ +Upon confirmation of a sale order or when quantities are added, +the picking that reserves from stock will be reserved if the +necessary quantities are available. -If you install this module, you will not have to run the regular procurement -scheduler anymore (but you still need to run the minimum order point rule -scheduler, or for example let it run daily). -All procurement orders will be processed immediately, which could in some -cases entail a small performance impact. +In the simplest configurations, this is an easy way of working: +first come, first served. However, when not installed, you can +use manual reservation or run the schedulers where the system +will take into account the expected date and the priority. -It may also increase your stock size because products are reserved as soon -as possible and the scheduler time range is not taken into account anymore. -In that case, you can not use priorities any more on the different picking. +If this automatic reservation would reserve too much, you can +still unreserve a picking. """, 'website': 'https://www.odoo.com/page/manufacturing', 'depends': ['sale_stock'], 'data': [], 'demo': [], - 'test': ['test/procurement_jit.yml'], + 'test': [], 'installable': True, 'auto_install': True, } diff --git a/addons/procurement_jit/procurement_jit.py b/addons/procurement_jit/procurement_jit.py deleted file mode 100644 index b48ad5f937b..00000000000 --- a/addons/procurement_jit/procurement_jit.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - - -from openerp.osv import osv - -class procurement_order(osv.osv): - _inherit = "procurement.order" - - def create(self, cr, uid, vals, context=None): - context = context or {} - procurement_id = super(procurement_order, self).create(cr, uid, vals, context=context) - self.run(cr, uid, [procurement_id], context=context) - return procurement_id - - def run(self, cr, uid, ids, autocommit=False, context=None): - res = super(procurement_order, self).run(cr, uid, ids, autocommit=autocommit, context=context) - procurement_ids = self.search(cr, uid, [('move_dest_id.procurement_id', 'in', ids)], order='id', context=context) - if procurement_ids: - result = self.run(cr, uid, procurement_ids, autocommit=autocommit, context=context) - return result - return res - diff --git a/addons/procurement_jit/sale.py b/addons/procurement_jit/sale.py index bff11a5524e..d4708e00f5c 100644 --- a/addons/procurement_jit/sale.py +++ b/addons/procurement_jit/sale.py @@ -10,8 +10,5 @@ class SaleOrder(models.Model): def action_confirm(self): res = super(SaleOrder, self).action_confirm() for order in self: - for pick in order.picking_ids: - print pick.state order.picking_ids.filtered(lambda x: x.state=='confirmed').action_assign() - return res - + return res \ No newline at end of file diff --git a/addons/procurement_jit/test/procurement_jit.yml b/addons/procurement_jit/test/procurement_jit.yml deleted file mode 100644 index 1be88c6a7dd..00000000000 --- a/addons/procurement_jit/test/procurement_jit.yml +++ /dev/null @@ -1,16 +0,0 @@ -- - In order to test procurement_jit module with OpenERP, I create procurement order for - Computer Case product and check whether it runs without scheduler or not. -- - !record {model: procurement.order, id: procurement_order_test1}: - company_id: base.main_company - date_planned: !eval datetime.today().strftime("%Y-%m-%d %H:%M:%S") - name: PROC/TEST/0001 - product_id: product.product_product_16 - product_qty: 10.0 - product_uom: product.product_uom_unit -- - I check that the procurement is automatically in exception because nothing is configured to handle this procurement. -- - !assert {model: procurement.order, id: procurement_order_test1, string: procstate}: - - state == 'exception' diff --git a/addons/sale/sale.py b/addons/sale/sale.py index ec00f26a8a6..72380c4786e 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -468,6 +468,7 @@ class SaleOrderLine(models.Model): @api.multi def _action_procurement_create(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + new_procs = self.env['procurement.order'] #Empty recordset for line in self: if line.state != 'sale': continue @@ -484,8 +485,9 @@ class SaleOrderLine(models.Model): vals = line._prepare_order_line_procurement(group_id=line.order_id.procurement_group_id.id) vals['product_qty'] = line.product_uom_qty - qty new_proc = self.env["procurement.order"].create(vals) - new_proc.run() - return True + new_procs += new_proc + new_procs.run() + return new_procs @api.model def _get_analytic_invoice_policy(self): diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py index 03ad7ccda6c..c2aac6a75a8 100644 --- a/addons/stock/procurement.py +++ b/addons/stock/procurement.py @@ -321,6 +321,7 @@ class procurement_order(osv.osv): def run(self, cr, uid, ids, autocommit=False, context=None): new_ids = [x.id for x in self.browse(cr, uid, ids, context=context) if x.state not in ('running', 'done', 'cancel')] + context = dict(context or {}, procurement_auto_defer=True) #When creating res = super(procurement_order, self).run(cr, uid, new_ids, autocommit=autocommit, context=context) #after all the procurements are run, check if some created a draft stock move that needs to be confirmed @@ -331,6 +332,10 @@ class procurement_order(osv.osv): move_to_confirm_ids += [m.id for m in procurement.move_ids if m.state == 'draft'] if move_to_confirm_ids: self.pool.get('stock.move').action_confirm(cr, uid, move_to_confirm_ids, context=context) + # If procurements created other procurements, run the created in batch + procurement_ids = self.search(cr, uid, [('move_dest_id.procurement_id', 'in', new_ids)], order='id', context=context) + if procurement_ids: + res = res and self.run(cr, uid, procurement_ids, autocommit=autocommit, context=context) return res def _check(self, cr, uid, procurement, context=None): diff --git a/addons/stock/res_config.py b/addons/stock/res_config.py index 8fdb56cc8f2..533f11a0bf0 100644 --- a/addons/stock/res_config.py +++ b/addons/stock/res_config.py @@ -79,12 +79,11 @@ class stock_config_settings(osv.osv_memory): implied_group='product.group_product_variant'), 'company_id': fields.many2one('res.company', 'Company', required=True), 'module_procurement_jit': fields.selection([ - (1, 'Schedule orders in real time'), - (0, 'Run scheduler once a day') + (1, 'Reserve Sale Orders Immediately On Confirmation'), + (0, 'Reserve Sale Orders Manually or by Running the Schedulers') ], "Procurements", - help="""This allows Just In Time computation of procurement orders. - All procurement orders will be processed immediately, which could in some - cases entail a small performance impact. + help="""Allows you to automatically reserve the available + products when confirming a sale order. This installs the module procurement_jit."""), 'module_claim_from_delivery': fields.selection([ (0, 'Do not manage claims'), diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 387d12c528d..cfa2dfd51dd 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2055,8 +2055,8 @@ class stock_move(osv.osv): wh_route_ids = [] if move.warehouse_id: wh_route_ids = [x.id for x in move.warehouse_id.route_ids] - elif move.picking_type_id and move.picking_type_id.warehouse_id: - wh_route_ids = [x.id for x in move.picking_type_id.warehouse_id.route_ids] + elif move.picking_id.picking_type_id.warehouse_id: + wh_route_ids = [x.id for x in move.picking_id.picking_type_id.warehouse_id.route_ids] if wh_route_ids: rules = push_obj.search(cr, uid, domain + [('route_id', 'in', wh_route_ids)], order='route_sequence, sequence', context=context) if not rules: @@ -2077,6 +2077,8 @@ class stock_move(osv.osv): res = [] for move in moves: res.append(self._create_procurement(cr, uid, move, context=context)) + # Run procurements immediately when generated from multiple moves + self.pool['procurement.order'].run(cr, uid, res, context=context) return res def write(self, cr, uid, ids, vals, context=None):