[MERGE] Sync with trunk, until revision 8927
[odoo/odoo.git] / addons / stock / stock.py
index f3efd8a..77c1eae 100644 (file)
@@ -49,7 +49,6 @@ class stock_incoterms(osv.osv):
         'active': True,
     }
 
-stock_incoterms()
 
 class stock_journal(osv.osv):
     _name = "stock.journal"
@@ -62,7 +61,6 @@ class stock_journal(osv.osv):
         'user_id': lambda s, c, u, ctx: u
     }
 
-stock_journal()
 
 #----------------------------------------------------------
 # Stock Location
@@ -75,8 +73,6 @@ class stock_location(osv.osv):
     _parent_order = 'posz,name'
     _order = 'parent_left'
 
-    # TODO: implement name_search() in a way that matches the results of name_get!
-
     def name_get(self, cr, uid, ids, context=None):
         # always return the full hierarchical name
         res = self._complete_name(cr, uid, ids, 'complete_name', None, context=context)
@@ -401,19 +397,7 @@ class stock_location(osv.osv):
         uom_rounding = self.pool.get('product.product').browse(cr, uid, product_id, context=context).uom_id.rounding
         if context.get('uom'):
             uom_rounding = uom_obj.browse(cr, uid, context.get('uom'), context=context).rounding
-        prodlot_id = context.get('prodlot_id', False)
-
-        locations_ids = self.search(cr, uid, [('location_id', 'child_of', ids)])
-        if locations_ids:
-            # Fetch only the locations in which this product has ever been processed (in or out)
-            cr.execute("""SELECT l.id FROM stock_location l WHERE l.id in %s AND
-                        EXISTS (SELECT 1 FROM stock_move m WHERE m.product_id = %s
-                                AND (NOT BOOL(%s) OR m.prodlot_id=%s)
-                                AND ((state = 'done' AND m.location_dest_id = l.id)
-                                    OR (state in ('done','assigned') AND m.location_id = l.id)))
-                       """, (tuple(locations_ids), product_id, prodlot_id, prodlot_id or None))
-            locations_ids = [i for (i,) in cr.fetchall()]
-        for id in locations_ids:
+        for id in self.search(cr, uid, [('location_id', 'child_of', ids)]):
             if lock:
                 try:
                     # Must lock with a separate select query because FOR UPDATE can't be used with
@@ -423,7 +407,6 @@ class stock_location(osv.osv):
                     cr.execute("SAVEPOINT stock_location_product_reserve")
                     cr.execute("""SELECT id FROM stock_move
                                   WHERE product_id=%s AND
-                                        (NOT BOOL(%s) OR prodlot_id=%s) AND
                                           (
                                             (location_dest_id=%s AND
                                              location_id<>%s AND
@@ -433,7 +416,7 @@ class stock_location(osv.osv):
                                              location_dest_id<>%s AND
                                              state in ('done', 'assigned'))
                                           )
-                                  FOR UPDATE of stock_move NOWAIT""", (product_id, prodlot_id, prodlot_id or None, id, id, id, id), log_exceptions=False)
+                                  FOR UPDATE of stock_move NOWAIT""", (product_id, id, id, id, id), log_exceptions=False)
                 except Exception:
                     # Here it's likely that the FOR UPDATE NOWAIT failed to get the LOCK,
                     # so we ROLLBACK to the SAVEPOINT to restore the transaction to its earlier
@@ -449,22 +432,20 @@ class stock_location(osv.osv):
                           WHERE location_dest_id=%s AND
                                 location_id<>%s AND
                                 product_id=%s AND
-                                (NOT BOOL(%s) OR prodlot_id=%s) AND
                                 state='done'
                           GROUP BY product_uom
                        """,
-                       (id, id, product_id, prodlot_id, prodlot_id or None))
+                       (id, id, product_id))
             results = cr.dictfetchall()
             cr.execute("""SELECT product_uom,-sum(product_qty) AS product_qty
                           FROM stock_move
                           WHERE location_id=%s AND
                                 location_dest_id<>%s AND
                                 product_id=%s AND
-                                (NOT BOOL(%s) OR prodlot_id=%s) AND
                                 state in ('done', 'assigned')
                           GROUP BY product_uom
                        """,
-                       (id, id, product_id, prodlot_id, prodlot_id or None))
+                       (id, id, product_id))
             results += cr.dictfetchall()
             total = 0.0
             results2 = 0.0
@@ -489,7 +470,6 @@ class stock_location(osv.osv):
                     continue
         return False
 
-stock_location()
 
 
 class stock_tracking(osv.osv):
@@ -555,7 +535,6 @@ class stock_tracking(osv.osv):
         """
         return self.pool.get('action.traceability').action_traceability(cr,uid,ids,context)
 
-stock_tracking()
 
 #----------------------------------------------------------
 # Stock Picking
@@ -633,7 +612,7 @@ class stock_picking(osv.osv):
         return res
 
     def create(self, cr, user, vals, context=None):
-        if ('name' not in vals) or (vals.get('name')=='/'):
+        if ('name' not in vals) or (vals.get('name')=='/') or (vals.get('name') == False):
             seq_obj_name =  self._name
             vals['name'] = self.pool.get('ir.sequence').get(cr, user, seq_obj_name)
         new_id = super(stock_picking, self).create(cr, user, vals, context)
@@ -775,10 +754,9 @@ class stock_picking(osv.osv):
         """ Changes state of picking to available if all moves are confirmed.
         @return: True
         """
-        wf_service = netsvc.LocalService("workflow")
         for pick in self.browse(cr, uid, ids):
             if pick.state == 'draft':
-                wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_confirm', cr)
+                self.signal_button_confirm(cr, uid, [pick.id])
             move_ids = [x.id for x in pick.move_lines if x.state == 'confirmed']
             if not move_ids:
                 raise osv.except_osv(_('Warning!'),_('Not enough stock, unable to reserve the products.'))
@@ -800,12 +778,10 @@ class stock_picking(osv.osv):
         """ Confirms picking directly from draft state.
         @return: True
         """
-        wf_service = netsvc.LocalService("workflow")
         for pick in self.browse(cr, uid, ids):
             if not pick.move_lines:
                 raise osv.except_osv(_('Error!'),_('You cannot process picking without stock moves.'))
-            wf_service.trg_validate(uid, 'stock.picking', pick.id,
-                'button_confirm', cr)
+            self.signal_button_confirm(cr, uid, [pick.id])
         return True
 
     def draft_validate(self, cr, uid, ids, context=None):
@@ -1275,17 +1251,17 @@ class stock_picking(osv.osv):
                     context['currency_id'] = move_currency_id
                     qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
 
-                    if product.id not in product_avail:
-                        # keep track of stock on hand including processed lines not yet marked as done
+                    if product.id in product_avail:
+                        product_avail[product.id] += qty
+                    else:
                         product_avail[product.id] = product.qty_available
 
                     if qty > 0:
                         new_price = currency_obj.compute(cr, uid, product_currency,
-                                move_currency_id, product_price, round=False)
+                                move_currency_id, product_price)
                         new_price = uom_obj._compute_price(cr, uid, product_uom, new_price,
                                 product.uom_id.id)
-                        if product_avail[product.id] <= 0:
-                            product_avail[product.id] = 0
+                        if product.qty_available <= 0:
                             new_std_price = new_price
                         else:
                             # Get the standard price
@@ -1301,9 +1277,6 @@ class stock_picking(osv.osv):
                                 {'price_unit': product_price,
                                  'price_currency_id': product_currency})
 
-                        product_avail[product.id] += qty
-
-
 
             for move in too_few:
                 product_qty = move_product_qty[move.id]
@@ -1364,18 +1337,18 @@ class stock_picking(osv.osv):
 
             # At first we confirm the new picking (if necessary)
             if new_picking:
-                wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_confirm', cr)
+                self.signal_button_confirm(cr, uid, [new_picking])
                 # Then we finish the good picking
                 self.write(cr, uid, [pick.id], {'backorder_id': new_picking})
                 self.action_move(cr, uid, [new_picking], context=context)
-                wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr)
+                self.signal_button_done(cr, uid, [new_picking])
                 wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
                 delivered_pack_id = new_picking
                 back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
                 self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
             else:
                 self.action_move(cr, uid, [pick.id], context=context)
-                wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
+                self.signal_button_done(cr, uid, [pick.id])
                 delivered_pack_id = pick.id
 
             delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
@@ -1514,7 +1487,6 @@ class stock_production_lot(osv.osv):
         default.update(date=time.strftime('%Y-%m-%d %H:%M:%S'), move_ids=[])
         return super(stock_production_lot, self).copy(cr, uid, id, default=default, context=context)
 
-stock_production_lot()
 
 class stock_production_lot_revision(osv.osv):
     _name = 'stock.production.lot.revision'
@@ -1535,7 +1507,6 @@ class stock_production_lot_revision(osv.osv):
         'date': fields.date.context_today,
     }
 
-stock_production_lot_revision()
 
 # ----------------------------------------------------
 # Move
@@ -1939,8 +1910,7 @@ class stock_move(osv.osv):
         """
         if not prod_id:
             return {}
-        user = self.pool.get('res.users').browse(cr, uid, uid)
-        lang = user and user.lang or False
+        lang = False
         if partner_id:
             addr_rec = self.pool.get('res.partner').browse(cr, uid, partner_id)
             if addr_rec:
@@ -2075,7 +2045,6 @@ class stock_move(osv.osv):
         res_obj = self.pool.get('res.company')
         location_obj = self.pool.get('stock.location')
         move_obj = self.pool.get('stock.move')
-        wf_service = netsvc.LocalService("workflow")
         new_moves = []
         if context is None:
             context = {}
@@ -2114,7 +2083,7 @@ class stock_move(osv.osv):
                 })
                 new_moves.append(self.browse(cr, uid, [new_id])[0])
             if pickid:
-                wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
+                self.signal_button_confirm(cr, uid, [pickid])
         if new_moves:
             new_moves += self.create_chained_picking(cr, uid, new_moves, context)
         return new_moves
@@ -2184,12 +2153,8 @@ class stock_move(osv.osv):
                 pickings[move.picking_id.id] = 1
                 continue
             if move.state in ('confirmed', 'waiting'):
-                ctx = context.copy()
-                ctx.update({'uom': move.product_uom.id})
-                if move.prodlot_id:
-                    ctx.update({'prodlot_id': move.prodlot_id.id})
                 # Important: we must pass lock=True to _product_reserve() to avoid race conditions and double reservations
-                res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, context=ctx, lock=True)
+                res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True)
                 if res:
                     #_product_available_test depends on the next status for correct functioning
                     #the test does not work correctly if the same product occurs multiple times
@@ -2240,6 +2205,7 @@ class stock_move(osv.osv):
             return True
         if context is None:
             context = {}
+        wf_service = netsvc.LocalService("workflow")
         pickings = set()
         for move in self.browse(cr, uid, ids, context=context):
             if move.state in ('confirmed', 'waiting', 'assigned', 'draft'):
@@ -2248,7 +2214,6 @@ class stock_move(osv.osv):
             if move.move_dest_id and move.move_dest_id.state == 'waiting':
                 self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'})
                 if context.get('call_unlink',False) and move.move_dest_id.picking_id:
-                    wf_service = netsvc.LocalService("workflow")
                     wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
         self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False})
         if not context.get('call_unlink',False):
@@ -2256,7 +2221,6 @@ class stock_move(osv.osv):
                 if all(move.state == 'cancel' for move in pick.move_lines):
                     self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'})
 
-        wf_service = netsvc.LocalService("workflow")
         for id in ids:
             wf_service.trg_trigger(uid, 'stock.move', id, cr)
         return True
@@ -2683,7 +2647,6 @@ class stock_move(osv.osv):
         product_obj = self.pool.get('product.product')
         currency_obj = self.pool.get('res.currency')
         uom_obj = self.pool.get('product.uom')
-        wf_service = netsvc.LocalService("workflow")
 
         if context is None:
             context = {}
@@ -2717,7 +2680,7 @@ class stock_move(osv.osv):
                 qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
                 if qty > 0:
                     new_price = currency_obj.compute(cr, uid, product_currency,
-                            move_currency_id, product_price, round=False)
+                            move_currency_id, product_price)
                     new_price = uom_obj._compute_price(cr, uid, product_uom, new_price,
                             product.uom_id.id)
                     if product.qty_available <= 0:
@@ -2784,11 +2747,10 @@ class stock_move(osv.osv):
                 res = cr.fetchall()
                 if len(res) == len(move.picking_id.move_lines):
                     picking_obj.action_move(cr, uid, [move.picking_id.id])
-                    wf_service.trg_validate(uid, 'stock.picking', move.picking_id.id, 'button_done', cr)
+                    picking_obj.signal_button_done(cr, uid, [move.picking_id.id])
 
         return [move.id for move in complete]
 
-stock_move()
 
 class stock_inventory(osv.osv):
     _name = "stock.inventory"
@@ -2911,7 +2873,6 @@ class stock_inventory(osv.osv):
             self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
         return True
 
-stock_inventory()
 
 class stock_inventory_line(osv.osv):
     _name = "stock.inventory.line"
@@ -2955,7 +2916,6 @@ class stock_inventory_line(osv.osv):
         result = {'product_qty': amount, 'product_uom': uom, 'prod_lot_id': False}
         return {'value': result}
 
-stock_inventory_line()
 
 #----------------------------------------------------------
 # Stock Warehouse
@@ -2997,7 +2957,6 @@ class stock_warehouse(osv.osv):
         'lot_output_id': _default_lot_output_id,
     }
 
-stock_warehouse()
 
 #----------------------------------------------------------
 # "Empty" Classes that are used to vary from the original stock.picking  (that are dedicated to the internal pickings)
@@ -3023,15 +2982,25 @@ class stock_picking_in(osv.osv):
         #override in order to redirect the check of acces rules on the stock.picking object
         return self.pool.get('stock.picking').check_access_rule(cr, uid, ids, operation, context=context)
 
-    def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
-        #override in order to trigger the workflow of stock.picking at the end of create, write and unlink operation
-        #instead of it's own workflow (which is not existing)
-        return self.pool.get('stock.picking')._workflow_trigger(cr, uid, ids, trigger, context=context)
+    def create_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').create_workflow(cr, uid, ids, context=context)
+
+    def delete_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').delete_workflow(cr, uid, ids, context=context)
 
-    def _workflow_signal(self, cr, uid, ids, signal, context=None):
-        #override in order to fire the workflow signal on given stock.picking workflow instance
-        #instead of it's own workflow (which is not existing)
-        return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+    def step_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').step_workflow(cr, uid, ids, context=context)
+
+    def signal_workflow(self, cr, uid, ids, signal, context=None):
+        # overridden in order to fire the workflow signal on given stock.picking workflow instance
+        # instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').signal_workflow(cr, uid, ids, signal, context=context)
 
     def message_post(self, *args, **kwargs):
         """Post the message on stock.picking to be able to see it in the form view when using the chatter"""
@@ -3086,15 +3055,25 @@ class stock_picking_out(osv.osv):
         #override in order to redirect the check of acces rules on the stock.picking object
         return self.pool.get('stock.picking').check_access_rule(cr, uid, ids, operation, context=context)
 
-    def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
-        #override in order to trigger the workflow of stock.picking at the end of create, write and unlink operation
-        #instead of it's own workflow (which is not existing)
-        return self.pool.get('stock.picking')._workflow_trigger(cr, uid, ids, trigger, context=context)
-
-    def _workflow_signal(self, cr, uid, ids, signal, context=None):
-        #override in order to fire the workflow signal on given stock.picking workflow instance
-        #instead of it's own workflow (which is not existing)
-        return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+    def create_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').create_workflow(cr, uid, ids, context=context)
+
+    def delete_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').delete_workflow(cr, uid, ids, context=context)
+
+    def step_workflow(self, cr, uid, ids, context=None):
+        # overridden in order to trigger the workflow of stock.picking at the end of create,
+        # write and unlink operation instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').step_workflow(cr, uid, ids, context=context)
+
+    def signal_workflow(self, cr, uid, ids, signal, context=None):
+        # overridden in order to fire the workflow signal on given stock.picking workflow instance
+        # instead of its own workflow (which is not existing)
+        return self.pool.get('stock.picking').signal_workflow(cr, uid, ids, signal, context=context)
 
     def message_post(self, *args, **kwargs):
         """Post the message on stock.picking to be able to see it in the form view when using the chatter"""