[MERGE] MErged from main branch
[odoo/odoo.git] / addons / stock / stock.py
index 7012e23..a1c30a4 100644 (file)
@@ -182,6 +182,7 @@ class stock_location(osv.osv):
         'stock_real_value': fields.function(_product_value, method=True, type='float', string='Real Stock Value', multi="stock"),
         'stock_virtual_value': fields.function(_product_value, method=True, type='float', string='Virtual Stock Value', multi="stock"),
         'company_id': fields.many2one('res.company', 'Company', required=True,select=1),
+        'scrap_location': fields.boolean('Scrap Location', help='Check this box if the current location is a place for destroyed items'),
     }
     _defaults = {
         'active': lambda *a: 1,
@@ -194,6 +195,7 @@ class stock_location(osv.osv):
         'posy': lambda *a: 0,
         'posz': lambda *a: 0,
         'icon': lambda *a: False,
+        'scrap_location': lambda *a: False,
     }
 
     def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}):
@@ -348,7 +350,19 @@ stock_location()
 class stock_tracking(osv.osv):
     _name = "stock.tracking"
     _description = "Stock Tracking Lots"
-
+    
+    def get_create_tracking_lot(self, cr, uid, ids, tracking_lot):
+        tracking_lot_list = self.search(cr, uid, [('name', '=', tracking_lot)],
+                                            limit=1)
+        if tracking_lot_list:
+            tracking_lot = tracking_lot_list[0]
+        tracking_obj = self.browse(cr, uid, tracking_lot)
+        if not tracking_obj:
+            tracking_lot_vals = {
+                'name': tracking_lot
+                }
+            tracking_lot = self.create(cr, uid, tracking_lot_vals)
+        return tracking_lot
     def checksum(sscc):
         salt = '31' * 8 + '3'
         sum = 0
@@ -488,10 +502,10 @@ class stock_picking(osv.osv):
         'min_date': fields.function(get_min_max_date, fnct_inv=_set_minimum_date, multi="min_max_date",
                  method=True, store=True, type='datetime', string='Expected Date', select=1, help="Expected date for Picking. Default it takes current date"),
         'date': fields.datetime('Order Date', help="Date of Order"),
-        'date_done': fields.datetime('Date Done', help="Date of completion"),
+        'date_done': fields.datetime('Date Done', help="Date of Completion"),
         'max_date': fields.function(get_min_max_date, fnct_inv=_set_maximum_date, multi="min_max_date",
                  method=True, store=True, type='datetime', string='Max. Expected Date', select=2),
-        'move_lines': fields.one2many('stock.move', 'picking_id', 'Entry lines', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
+        'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
         'delivery_line':fields.one2many('stock.delivery', 'picking_id', 'Delivery lines', readonly=True),
         'auto_picking': fields.boolean('Auto-Picking'),
         'address_id': fields.many2one('res.partner.address', 'Partner', help="Address of partner"),
@@ -859,15 +873,23 @@ class stock_picking(osv.osv):
         return True
 
     def unlink(self, cr, uid, ids, context=None):
+        move_obj = self.pool.get('stock.move')
+        if not context:
+            context = {}
+            
         for pick in self.browse(cr, uid, ids, context=context):
             if pick.state in ['done','cancel']:
                 raise osv.except_osv(_('Error'), _('You cannot remove the picking which is in %s state !')%(pick.state,))
-            elif pick.state in ['confirmed','assigned']:
+            elif pick.state in ['confirmed','assigned', 'draft']:
                 ids2 = [move.id for move in pick.move_lines]
-                context.update({'call_unlink':True})
-                self.pool.get('stock.move').action_cancel(cr, uid, ids2, context)
-            else:
-                continue
+                ctx = context.copy()
+                ctx.update({'call_unlink':True})
+                if pick.state != 'draft':
+                    #Cancelling the move in order to affect Virtual stock of product
+                    move_obj.action_cancel(cr, uid, ids2, ctx)
+                #Removing the move
+                move_obj.unlink(cr, uid, ids2, ctx)
+                    
         return super(stock_picking, self).unlink(cr, uid, ids, context=context)
 
     def do_partial(self, cr, uid, ids, partial_datas, context={}):
@@ -1004,7 +1026,7 @@ class stock_picking(osv.osv):
 
             delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
             delivery_id = delivery_obj.create(cr, uid, {
-                'name':  delivered_pack.name,
+                'name':  delivered_pack.name or move.name,
                 'partner_id': partner_id,
                 'address_id': address_id,
                 'date': delivery_date,
@@ -1175,7 +1197,7 @@ class stock_move(osv.osv):
 
         'date': fields.datetime('Created Date'),
         'date_planned': fields.datetime('Date', required=True, help="Scheduled date for the movement of the products or real date if the move is done."),
-
+        'date_expected': fields.datetime('Date Expected', readonly=True,required=True, help="Scheduled date for the movement of the products"),
         'product_id': fields.many2one('product.product', 'Product', required=True, select=True),
 
         'product_qty': fields.float('Quantity', required=True),
@@ -1212,7 +1234,7 @@ class stock_move(osv.osv):
         'origin': fields.related('picking_id','origin',type='char', size=64, relation="stock.picking", string="Origin"),
         'move_stock_return_history': fields.many2many('stock.move', 'stock_move_return_history', 'move_id', 'return_move_id', 'Move Return History',readonly=True),
         'delivered_id': fields.many2one('stock.delivery', 'Product delivered'),
-        'scraped': fields.boolean('Scraped'),
+        'scraped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scraped'),
     }
     _constraints = [
         (_check_tracking,
@@ -1249,11 +1271,12 @@ class stock_move(osv.osv):
         'location_dest_id': _default_location_destination,
         'state': lambda *a: 'draft',
         'priority': lambda *a: '1',
-        'scraped' : lambda *a:False,
         'product_qty': lambda *a: 1.0,
+        'scraped' : lambda *a: False,
         'date_planned': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
         'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
-        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.move', context=c)
+        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.move', context=c),
+        'date_expected': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),        
     }
 
     def copy(self, cr, uid, id, default=None, context={}):
@@ -1370,8 +1393,11 @@ class stock_move(osv.osv):
             new_moves = []
             for picking, todo in self._chain_compute(cr, uid, moves, context).items():
                 ptype = self.pool.get('stock.location').picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
+                pick_name = ''
+                if ptype == 'delivery':
+                    pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.delivery')
                 pickid = self.pool.get('stock.picking').create(cr, uid, {
-                    'name': picking.name,
+                    'name': pick_name or picking.name,
                     'origin': str(picking.origin or ''),
                     'type': ptype,
                     'note': picking.note,
@@ -1489,9 +1515,12 @@ class stock_move(osv.osv):
         #self.action_cancel(cr,uid, ids2, context)
         return True
 
-    def action_done(self, cr, uid, ids, context=None):
+    def action_done(self, cr, uid, ids, context={}):
         track_flag = False
         picking_ids = []
+        product_uom_obj = self.pool.get('product.uom')
+        price_type_obj = self.pool.get('product.price.type')
+        move_obj = self.pool.get('account.move')
         for move in self.browse(cr, uid, ids):
             if move.picking_id: picking_ids.append(move.picking_id.id)
             if move.move_dest_id.id and (move.state != 'done'):
@@ -1553,7 +1582,6 @@ class stock_move(osv.osv):
                 journal_id = move.product_id.categ_id.property_stock_journal.id
                 if acc_src != acc_dest:
                     ref = move.picking_id and move.picking_id.name or False
-                    product_uom_obj = self.pool.get('product.uom')
                     default_uom = move.product_id.uom_id.id
                     date = time.strftime('%Y-%m-%d')
                     q = product_uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, default_uom)
@@ -1561,11 +1589,11 @@ class stock_move(osv.osv):
                         amount = q * move.price_unit
                     # Base computation on valuation price type
                     else:
-                        company_id=move.company_id.id
-                        context['currency_id']=move.company_id.currency_id.id
-                        pricetype=self.pool.get('product.price.type').browse(cr,uid,move.company_id.property_valuation_price_type.id)
-                        amount_unit=move.product_id.price_get(pricetype.field, context)[move.product_id.id]
-                        amount=amount_unit * q or 1.0
+                        company_id = move.company_id.id
+                        context['currency_id'] = move.company_id.currency_id.id
+                        pricetype = price_type_obj.browse(cr,uid,move.company_id.property_valuation_price_type.id)
+                        amount_unit = move.product_id.price_get(pricetype.field, context)[move.product_id.id]
+                        amount = amount_unit * q or 1.0
                         # amount = q * move.product_id.standard_price
 
                     partner_id = False
@@ -1591,16 +1619,25 @@ class stock_move(osv.osv):
                                 'date': date,
                                 'partner_id': partner_id})
                     ]
-                    self.pool.get('account.move').create(cr, uid, {
+                    move_obj.create(cr, uid, {
                         'name': move.name,
                         'journal_id': journal_id,
                         'line_id': lines,
                         'ref': ref,
                     })
-        self.write(cr, uid, ids, {'state': 'done', 'date_planned': time.strftime('%Y-%m-%d %H:%M:%S')})
-        for pick in self.pool.get('stock.picking').browse(cr, uid, picking_ids):
+        tracking_lot = False                    
+        if context:
+            tracking_lot = context.get('tracking_lot', False)
+            if tracking_lot:
+                rec_id = context and context.get('active_id', False)
+                tracking = self.pool.get('stock.tracking')
+                tracking_lot = tracking.get_create_tracking_lot(cr, uid,[rec_id], tracking_lot)        
+                 
+        self.write(cr, uid, ids, {'state': 'done', 'date_planned': time.strftime('%Y-%m-%d %H:%M:%S'), 'tracking_id': tracking_lot or False})
+        picking_obj = self.pool.get('stock.picking')
+        for pick in picking_obj.browse(cr, uid, picking_ids):
             if all(move.state == 'done' for move in pick.move_lines):
-                self.pool.get('stock.picking').action_done(cr, uid, [pick.id])
+                picking_obj.action_done(cr, uid, [pick.id])
 
         wf_service = netsvc.LocalService("workflow")
         for id in ids:
@@ -1608,6 +1645,8 @@ class stock_move(osv.osv):
         return True
 
     def unlink(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}        
         for move in self.browse(cr, uid, ids, context=context):
             if move.state != 'draft':
                 raise osv.except_osv(_('UserError'),
@@ -1738,7 +1777,7 @@ class stock_move(osv.osv):
 
         @ return: Consumed lines
         '''
-        if not context:
+        if context is None:
             context = {}
 
         if quantity <= 0:
@@ -1814,7 +1853,8 @@ class stock_move(osv.osv):
         partner_id = partial_datas.get('partner_id', False)
         address_id = partial_datas.get('address_id', False)
         delivery_date = partial_datas.get('delivery_date', False)
-
+        tracking_lot = context.get('tracking_lot', False)
+        
         new_moves = []
 
         complete, too_many, too_few = [], [], []
@@ -1830,6 +1870,10 @@ class stock_move(osv.osv):
             product_price = partial_data.get('product_price',0.0)
             product_currency = partial_data.get('product_currency',False)
             if move.product_qty == product_qty:
+                self.write(cr, uid, move.id,
+                {
+                    'tracking_id': tracking_lot
+                })
                 complete.append(move)
             elif move.product_qty > product_qty:
                 too_few.append(move)
@@ -1874,6 +1918,7 @@ class stock_move(osv.osv):
                         'state': 'assigned',
                         'move_dest_id': False,
                         'price_unit': move.price_unit,
+                        'tracking_id': tracking_lot,
                     })
                 complete.append(self.browse(cr, uid, new_move))
             self.write(cr, uid, move.id,
@@ -1886,13 +1931,14 @@ class stock_move(osv.osv):
         for move in too_many:
             self.write(cr, uid, move.id,
                     {
-                        'product_qty': product_qty,
-                        'product_uos_qty': product_qty
+                        'product_qty': move.product_qty,
+                        'product_uos_qty': move.product_qty,
+                        'tracking_id': tracking_lot
                     })
             complete.append(move)
 
         for move in complete:
-            self.action_done(cr, uid, [move.id])
+            self.action_done(cr, uid, [move.id], context)
 
             # TOCHECK : Done picking if all moves are done
             cr.execute("""
@@ -2048,9 +2094,9 @@ class stock_warehouse(osv.osv):
 #       'partner_id': fields.many2one('res.partner', 'Owner'),
         'company_id': fields.many2one('res.company','Company',required=True,select=1),
         'partner_address_id': fields.many2one('res.partner.address', 'Owner Address'),
-        'lot_input_id': fields.many2one('stock.location', 'Location Input', required=True),
-        'lot_stock_id': fields.many2one('stock.location', 'Location Stock', required=True),
-        'lot_output_id': fields.many2one('stock.location', 'Location Output', required=True),
+        'lot_input_id': fields.many2one('stock.location', 'Location Input', required=True, domain=[('usage','<>','view')]),
+        'lot_stock_id': fields.many2one('stock.location', 'Location Stock', required=True, domain=[('usage','<>','view')]),
+        'lot_output_id': fields.many2one('stock.location', 'Location Output', required=True, domain=[('usage','<>','view')]),
     }
     _defaults = {
         'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.inventory', context=c),
@@ -2096,7 +2142,6 @@ class stock_picking_move_wizard(osv.osv_memory):
                 if line.picking_id:
                     picking_obj.write(cr, uid, [line.picking_id.id], {'move_lines': [(1, line.id, {'picking_id': act['picking_id']})]})
                     picking_obj.write(cr, uid, [act['picking_id']], {'move_lines': [(1, line.id, {'picking_id': act['picking_id']})]})
-                    cr.commit()
                     old_picking = picking_obj.read(cr, uid, [line.picking_id.id])[0]
                     if not len(old_picking['move_lines']):
                         picking_obj.write(cr, uid, [old_picking['id']], {'state': 'done'})
@@ -2122,7 +2167,7 @@ class report_products_to_received_planned(osv.osv):
         tools.drop_view_if_exists(cr, 'report_products_to_received_planned')
         cr.execute("""
             create or replace view report_products_to_received_planned as (
-               select stock.date, min(stock.id), sum(stock.product_qty) as qty, 0 as planned_qty
+               select stock.date, min(stock.id) as id, sum(stock.product_qty) as qty, 0 as planned_qty
                    from stock_picking picking
                     inner join stock_move stock
                     on picking.id = stock.picking_id and picking.type = 'in'
@@ -2131,7 +2176,7 @@ class report_products_to_received_planned(osv.osv):
 
                     union
 
-               select stock.date_planned, min(stock.id), 0 as actual_qty, sum(stock.product_qty) as planned_qty
+               select stock.date_planned, min(stock.id) as id, 0 as actual_qty, sum(stock.product_qty) as planned_qty
                     from stock_picking picking
                     inner join stock_move stock
                     on picking.id = stock.picking_id and picking.type = 'in'
@@ -2156,7 +2201,7 @@ class report_delivery_products_planned(osv.osv):
         tools.drop_view_if_exists(cr, 'report_delivery_products_planned')
         cr.execute("""
             create or replace view report_delivery_products_planned as (
-                select stock.date, min(stock.id), sum(stock.product_qty) as qty, 0 as planned_qty
+                select stock.date, min(stock.id) as id, sum(stock.product_qty) as qty, 0 as planned_qty
                    from stock_picking picking
                     inner join stock_move stock
                     on picking.id = stock.picking_id and picking.type = 'out'