[FIX] procurement, stock: forward port of bug fix 3609ba10f2d00a608d8f32334ae1b9a25b3...
authorDenis Ledoux <dle@odoo.com>
Wed, 13 Aug 2014 10:00:38 +0000 (12:00 +0200)
committerDenis Ledoux <dle@odoo.com>
Wed, 13 Aug 2014 10:00:38 +0000 (12:00 +0200)
addons/procurement/procurement.py
addons/stock/procurement.py

index 2ebc800..5a73ef1 100644 (file)
@@ -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()
 
index f53776d..d8be63e 100644 (file)
@@ -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
-
-                    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])
-            offset += len(ids)
+                    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:
+                            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()