diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 2ebc800ec04..5a73ef168ec 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -20,6 +20,7 @@ ############################################################################## import time +from psycopg2 import OperationalError from openerp import SUPERUSER_ID from openerp.osv import fields, osv @@ -193,31 +194,49 @@ class procurement_order(osv.osv): def reset_to_confirmed(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'confirmed'}, context=context) - def run(self, cr, uid, ids, context=None): + def run(self, cr, uid, ids, autocommit=False, context=None): for procurement_id in ids: #we intentionnaly do the browse under the for loop to avoid caching all ids which would be ressource greedy #and useless as we'll make a refresh later that will invalidate all the cache (and thus the next iteration #will fetch all the ids again) procurement = self.browse(cr, uid, procurement_id, context=context) if procurement.state not in ("running", "done"): - if self._assign(cr, uid, procurement, context=context): - procurement.refresh() - res = self._run(cr, uid, procurement, context=context or {}) - if res: - self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context) + try: + if self._assign(cr, uid, procurement, context=context): + procurement.refresh() + res = self._run(cr, uid, procurement, context=context or {}) + if res: + self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context) + else: + self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) else: + self.message_post(cr, uid, [procurement.id], body=_('No rule matching this procurement'), context=context) self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) - else: - self.message_post(cr, uid, [procurement.id], body=_('No rule matching this procurement'), context=context) - self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) + if autocommit: + cr.commit() + except OperationalError: + if autocommit: + cr.rollback() + continue + else: + raise return True - def check(self, cr, uid, ids, context=None): + def check(self, cr, uid, ids, autocommit=False, context=None): done_ids = [] for procurement in self.browse(cr, uid, ids, context=context): - result = self._check(cr, uid, procurement, context=context) - if result: - done_ids.append(procurement.id) + try: + result = self._check(cr, uid, procurement, context=context) + if result: + done_ids.append(procurement.id) + if autocommit: + cr.commit() + except OperationalError: + if autocommit: + cr.rollback() + continue + else: + raise if done_ids: self.write(cr, uid, done_ids, {'state': 'done'}, context=context) return done_ids @@ -288,22 +307,26 @@ class procurement_order(osv.osv): cr = openerp.registry(cr.dbname).cursor() # Run confirmed procurements + prev_ids = [] while True: ids = self.search(cr, SUPERUSER_ID, [('state', '=', 'confirmed')], context=context) - if not ids: + if not ids or prev_ids == ids: break - self.run(cr, SUPERUSER_ID, ids, context=context) + else: + prev_ids = ids + self.run(cr, SUPERUSER_ID, ids, autocommit=use_new_cursor, context=context) if use_new_cursor: cr.commit() # Check if running procurements are done - offset = 0 + prev_ids = [] while True: - ids = self.search(cr, SUPERUSER_ID, [('state', '=', 'running')], offset=offset, context=context) - if not ids: + ids = self.search(cr, SUPERUSER_ID, [('state', '=', 'running')], context=context) + if not ids or prev_ids == ids: break - done = self.check(cr, SUPERUSER_ID, ids, context=context) - offset += len(ids) - len(done) + else: + prev_ids = ids + self.check(cr, SUPERUSER_ID, ids, autocommit=use_new_cursor, context=context) if use_new_cursor: cr.commit() diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py index f53776d4b9a..d8be63e47e8 100644 --- a/addons/stock/procurement.py +++ b/addons/stock/procurement.py @@ -26,6 +26,7 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FO from openerp import SUPERUSER_ID from dateutil.relativedelta import relativedelta from datetime import datetime +from psycopg2 import OperationalError import openerp class procurement_group(osv.osv): @@ -204,8 +205,8 @@ class procurement_order(osv.osv): return True return super(procurement_order, self)._run(cr, uid, procurement, context=context) - def run(self, cr, uid, ids, context=None): - res = super(procurement_order, self).run(cr, uid, ids, context=context) + def run(self, cr, uid, ids, autocommit=False, context=None): + res = super(procurement_order, self).run(cr, uid, ids, autocommit=autocommit, context=context) #after all the procurements are run, check if some created a draft stock move that needs to be confirmed #(we do that in batch because it fasts the picking assignation and the picking state computation) move_to_confirm_ids = [] @@ -345,35 +346,50 @@ class procurement_order(osv.osv): orderpoint_obj = self.pool.get('stock.warehouse.orderpoint') procurement_obj = self.pool.get('procurement.order') - offset = 0 - ids = [1] - while ids: - ids = orderpoint_obj.search(cr, uid, [('company_id', '=', company_id)], offset=offset, limit=100) + orderpoint_ids = orderpoint_obj.search(cr, uid, [('company_id', '=', company_id)]) + prev_ids = [] + while orderpoint_ids: + ids = orderpoint_ids[:100] + del orderpoint_ids[:100] for op in orderpoint_obj.browse(cr, uid, ids, context=context): - prods = self._product_virtual_get(cr, uid, op) - if prods is None: - continue - if prods < op.product_min_qty: - qty = max(op.product_min_qty, op.product_max_qty) - prods - - reste = qty % op.qty_multiple - if reste > 0: - qty += op.qty_multiple - reste - - if qty <= 0: + try: + prods = self._product_virtual_get(cr, uid, op) + if prods is None: continue + if prods < op.product_min_qty: + qty = max(op.product_min_qty, op.product_max_qty) - prods - qty -= orderpoint_obj.subtract_procurements(cr, uid, op, context=context) + reste = qty % op.qty_multiple + if reste > 0: + qty += op.qty_multiple - reste - if qty > 0: - proc_id = procurement_obj.create(cr, uid, - self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context), - context=context) - self.check(cr, uid, [proc_id]) - self.run(cr, uid, [proc_id]) - offset += len(ids) + if qty <= 0: + continue + + qty -= orderpoint_obj.subtract_procurements(cr, uid, op, context=context) + + if qty > 0: + proc_id = procurement_obj.create(cr, uid, + self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context), + context=context) + self.check(cr, uid, [proc_id]) + self.run(cr, uid, [proc_id]) + if use_new_cursor: + cr.commit() + except OperationalError: + if use_new_cursor: + orderpoint_ids.append(op.id) + cr.rollback() + continue + else: + raise if use_new_cursor: cr.commit() + if prev_ids == ids: + break + else: + prev_ids = ids + if use_new_cursor: cr.commit() cr.close()