[FIX] some fixes and cleaning
authorFabien Pinckaers <fp@openerp.com>
Mon, 29 Jul 2013 21:44:43 +0000 (23:44 +0200)
committerFabien Pinckaers <fp@openerp.com>
Mon, 29 Jul 2013 21:44:43 +0000 (23:44 +0200)
bzr revid: fp@openerp.com-20130729214443-r3t4gnlisvp8hwyk

addons/procurement/procurement.py
addons/stock/stock.py
addons/stock/stock_view.xml
addons/stock/wizard/__init__.py
addons/stock/wizard/stock_traceability.py [deleted file]

index 7ac3a91..125c04f 100644 (file)
@@ -57,11 +57,15 @@ class procurement_group(osv.osv):
     _order = "id desc"
     _columns = {
         'name': fields.char('Reference', required=True), 
+        'move_type': fields.selection([
+            ('direct', 'Partial'), ('one', 'All at once')],
+            'Delivery Method', required=True),
         'partner_id': fields.many2one('res.partner', string = 'Partner'), #Sale should pass it here 
         'procurement_ids': fields.many2one('procurement.order', 'group_id', 'Procurements'), 
     }
     _defaults = {
-        'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or ''
+        'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '',
+        'move_type': lambda self, cr, uid, c: 'one'
     }
 
 class procurement_rule(osv.osv):
index 4a7218e..867bba6 100644 (file)
@@ -44,9 +44,9 @@ class stock_incoterms(osv.osv):
     _name = "stock.incoterms"
     _description = "Incoterms"
     _columns = {
-        'name': fields.char('Name', size=64, required=True, help="Incoterms are series of sales terms.They are used to divide transaction costs and responsibilities between buyer and seller and reflect state-of-the-art transportation practices."),
-        'code': fields.char('Code', size=3, required=True, help="Code for Incoterms"),
-        'active': fields.boolean('Active', help="By unchecking the active field, you may hide an INCOTERM without deleting it."),
+        'name': fields.char('Name', size=64, required=True, help="Incoterms are series of sales terms. They are used to divide transaction costs and responsibilities between buyer and seller and reflect state-of-the-art transportation practices."),
+        'code': fields.char('Code', size=3, required=True, help="Incoterm Standard Code"),
+        'active': fields.boolean('Active', help="By unchecking the active field, you may hide an INCOTERM you will not use."),
     }
     _defaults = {
         'active': True,
@@ -126,16 +126,11 @@ class stock_location(osv.osv):
     }
     def get_removal_strategy(self, cr, uid, location, product, context=None):
         return None
-#         categ = product.categ_id
-#         while (not categ.removal_strategy_id) and categ.parent_id:
-#             categ = categ.parent_id
-#         return categ and categ.removal_strategy_id or None
 
 #----------------------------------------------------------
 # Quants
 #----------------------------------------------------------
 
-
 class stock_quant(osv.osv):
     """
     Quants are the smallest unit of stock physical instances
@@ -201,9 +196,6 @@ class stock_quant(osv.osv):
         self._quant_reconcile_negative(cr, uid, quant, context=context)
         return quant
 
-
-    # FP Note: TODO: implement domain preference that tries to retrieve first with this domain
-    # This will be used for reservation
     def quants_get(self, cr, uid, location, product, qty, domain=None, prefered_order=False, reservedcontext=None, context=None):
         """
         Use the removal strategies of product to search for the correct quants
@@ -226,12 +218,11 @@ class stock_quant(osv.osv):
                 raise osv.except_osv(_('Error!'), _('Removal strategy %s not implemented.' % (removal_strategy,)))
         return result
 
-
     #
     # Create a quant in the destination location
     # Create a negative quant in the source location if it's an internal location
     # Reconcile a positive quant with a negative is possible
-    # 
+    #
     def _quant_create(self, cr, uid, qty, move, context=None):
         # FP Note: TODO: compute the right price according to the move, with currency convert
         # QTY is normally already converted to main product's UoM
@@ -311,12 +302,10 @@ class stock_quant(osv.osv):
     def _price_update(self, cr, uid, quant, newprice, context=None):
         self.write(cr, uid, [quant.id], {'cost': newprice}, context=context)
 
-
     def quants_unreserve(self, cr, uid, move, context=None):
         cr.execute('update stock_quant set reservation_id=NULL where reservation_id=%s', (move.id,))
         return True
 
-
     #
     # Implementation of removal strategies
     # If it can not reserve, it will return a tuple (None, qty)
@@ -358,6 +347,17 @@ class stock_quant(osv.osv):
     def _location_owner(self, cr, uid, quant, location, context=None):
         return location and (location.usage == 'internal') and location.company_id or False
 
+    def _check_location(self, cr, uid, ids, context=None):
+        for record in self.browse(cr, uid, ids, context=context):
+            if record.location_id.usage == 'view':
+                raise osv.except_osv(_('Error'), _('You cannot move product %s to a location of type view %s.')% (record.product_id.name, record.location_id.name))
+        return True
+
+    _constraints = [
+        (_check_location, 'You cannot move products to a location of the type view.', ['location_id'])
+    ]
+
+
 #----------------------------------------------------------
 # Stock Picking
 #----------------------------------------------------------
@@ -392,12 +392,13 @@ class stock_picking(osv.osv):
         return res
 
     def create(self, cr, user, vals, context=None):
+        context = context or {}
         if ('name' not in vals) or (vals.get('name') in ('/', False)):
-            sequence_id = self.pool.get('stock.picking.type').browse(cr, user, vals['picking_type_id'], context=context).sequence_id.id 
+            ptype_id = vals.get('picking_type_id', context['default_picking_type_id'])
+            sequence_id = self.pool.get('stock.picking.type').browse(cr, user, ptype_id, context=context).sequence_id.id
             vals['name'] = self.pool.get('ir.sequence').get_id(cr, user, sequence_id, 'id', context=context)
         return super(stock_picking, self).create(cr, user, vals, context)
 
-
     # The state of a picking depends on the state of its related stock.move
     # draft: the picking has no line or any one of the lines is draft
     # done, draft, cancel: all lines are done / draft / cancel
@@ -422,29 +423,19 @@ class stock_picking(osv.osv):
                 res[pick.id] = order_inv[min(lst)]
             else:
                 res[pick.id] = order_inv[max(lst)]
-        print 'Returning', res
         return res
 
     def _get_pickings(self, cr, uid, ids, context=None):
         res = set()
         for move in self.browse(cr, uid, ids, context=context):
-            if move.picking_id: 
+            if move.picking_id:
                 res.add(move.picking_id.id)
         return list(res)
 
-    def _get_pack_operation_exist(self, cr, uid, ids, field_name, arg, context=None):
-        res = {}
-        for pick in self.browse(cr, uid, ids, context=context):
-            res[pick.id] = False
-            if pick.pack_operation_ids: 
-                res[pick.id] = True
-        return res
-    
     _columns = {
         'name': fields.char('Reference', size=64, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'origin': fields.char('Source Document', size=64, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Reference of the document", select=True),
         'backorder_id': fields.many2one('stock.picking', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
-        #'type': fields.selection([('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], 'Shipping Type', required=True, select=True, help="Shipping type specify, goods coming in or going out."),
         'note': fields.text('Notes', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'move_type': fields.selection([('direct', 'Partial'), ('one', 'All at once')], 'Delivery Method', required=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="It specifies goods to be deliver partially or all at once"),
         'state': fields.function(_state_get, type="selection", store = {'stock.picking': (lambda self, cr, uid, ids, ctx: ids, ['move_type', 'move_lines'], 20), 'stock.move': (_get_pickings, ['state'], 20)}, selection = [
@@ -464,37 +455,31 @@ class stock_picking(osv.osv):
         ),
         'min_date': fields.function(get_min_max_date, multi="min_max_date",
                  store={'stock.move': (_get_pickings, ['state'], 20)}, type='datetime', string='Scheduled Time', select=1, help="Scheduled time for the shipment to be processed"),
-        'date': fields.datetime('Creation Date', help="Creation date, usually the time of the order.", select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
-        'date_done': fields.datetime('Date of Transfer', help="Date of Completion", states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'max_date': fields.function(get_min_max_date, multi="min_max_date",
                  store={'stock.move': (_get_pickings, ['state'], 20)}, type='datetime', string='Max. Expected Date', select=2),
+        'date': fields.datetime('Creation Date', help="Creation date, usually the time of the order.", select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
+        'date_done': fields.datetime('Date of Transfer', help="Date of Completion", states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
         'partner_id': fields.many2one('res.partner', 'Partner', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'company_id': fields.many2one('res.company', 'Company', required=True, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
         'pack_operation_ids': fields.one2many('stock.pack.operation', 'picking_id', string='Related Packing Operations'),
-         
-        # Used to search a product on pickings
+        'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True),
+
+        # Used to search on pickings
         'product_id': fields.related('move_lines', 'product_id', type='many2one', relation='product.product', string='Product'),#?
         'location_id': fields.related('move_lines', 'location_id', type='many2one', relation='stock.location', string='Location', readonly=True),
         'location_dest_id': fields.related('move_lines', 'location_dest_id', type='many2one', relation='stock.location', string='Destination Location', readonly=True),
         'group_id': fields.related('move_lines', 'group_id', type='many2one', relation='procurement.group', string='Procurement Group', readonly=True),
-        #Picking type will be on the picking itself instead
-        'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True), 
-        #related('move_lines', 'picking_type_id', type='many2one', relation='stock.picking.type', string="Picking Type", readonly=True),
-        'rule_id': fields.related('move_lines', 'rule_id', type='many2one', relation='procurement.rule', string="Procurement Rule", readonly=True), 
-        'pack_operation_exist': fields.function(_get_pack_operation_exist, type='boolean', string='Pack Operation Exists?', help='technical field for attrs in view'),
     }
     _defaults = {
         'name': lambda self, cr, uid, context: '/',
-        #TODO: not a good solution => we need to remove the partner_id from stock move for internal moves
-        'partner_id': lambda self, cr, uid, context: self.pool.get('stock.move')._default_destination_address(cr, uid, context=context),
         'state': 'draft',
-        'move_type': 'direct',
+        'move_type': 'one',
         '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.picking', context=c)
     }
     _sql_constraints = [
-        ('name_uniq', 'unique(name, company_id)', 'Reference must be unique per Company!'),
+        ('name_uniq', 'unique(name, company_id)', 'Reference must be unique per company!'),
     ]
 
     def copy(self, cr, uid, id, default=None, context=None):
@@ -509,24 +494,12 @@ class stock_picking(osv.osv):
             default['backorder_id'] = False
         return super(stock_picking, self).copy(cr, uid, id, default, context)
 
-
     def action_confirm(self, cr, uid, ids, context=None):
-        """ Confirms picking.
-        @return: True
-        """
-        proc_group = self.pool.get("procurement.group")
-        pickings = self.browse(cr, uid, ids, context=context)
         todo = []
-        for picking in pickings:
-            #If no procurement group, create one
-            new_proc = False
-            if not picking.group_id:
-                new_proc = proc_group.create(cr, uid, {'name': picking.name}, context=context)
+        for picking in self.browse(cr, uid, ids, context=context):
             for r in picking.move_lines:
                 if r.state == 'draft':
                     todo.append(r.id)
-                if not r.group_id and new_proc:
-                    self.pool.get("stock.move").write(cr, uid, [r.id], {'group_id': new_proc}, context=context)
         if len(todo):
             self.pool.get('stock.move').action_confirm(cr, uid, todo, context=context)
         return True
@@ -540,7 +513,7 @@ class stock_picking(osv.osv):
                 self.action_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.'))
+                raise osv.except_osv(_('Warning!'),_('No product available.'))
             self.pool.get('stock.move').action_assign(cr, uid, move_ids)
         return True
 
@@ -553,19 +526,6 @@ class stock_picking(osv.osv):
             self.pool.get('stock.move').force_assign(cr, uid, move_ids)
         return True
 
-    def draft_force_assign(self, cr, uid, ids, *args):
-        """ Confirms picking directly from draft state.
-        @return: True
-        """
-        return self.action_confirm(cr, uid, ids)
-
-    def draft_validate(self, cr, uid, ids, context=None):
-        """ Validates picking directly from draft state.
-        @return: True
-        """
-        self.draft_force_assign(cr, uid, ids)
-        return self.action_done(cr, uid, ids, context=context)
-
     def cancel_assign(self, cr, uid, ids, *args):
         """ Cancels picking and moves.
         @return: True
@@ -575,22 +535,6 @@ class stock_picking(osv.osv):
             self.pool.get('stock.move').cancel_assign(cr, uid, move_ids)
         return True
 
-    def _create_backorder(self, cr, uid, picking, context=None):
-        sequence_obj = self.pool.get('ir.sequence')
-        new_picking_name = picking.name
-        #TODO back_order_name is False currently => find why
-        back_order_name = sequence_obj.get(cr, uid, 'stock.picking') #TODO: Need to have sequence for every picking type
-        self.write(cr, uid, [picking.id], {'name': back_order_name})
-        backorder_id = self.copy(cr, uid, picking.id, {
-            'name': new_picking_name,
-            'move_lines': [],  # the move_lines are linked after
-            'state': 'done'  # the backorder is already created as 'done' because it is created only after the action_done of stock moves
-        })
-        self.message_post(cr, uid, picking.id, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
-        unlink_operation_order = [(2, op.id) for op in picking.pack_operation_ids]
-        self.write(cr, uid, [picking.id], {'backorder_id': backorder_id, 'pack_operation_ids': unlink_operation_order}, context=context)
-        return backorder_id
-
     def action_cancel(self, cr, uid, ids, context=None):
         """ Changes picking state to cancel.
         @return: True
@@ -598,12 +542,11 @@ class stock_picking(osv.osv):
         for pick in self.browse(cr, uid, ids, context=context):
             ids2 = [move.id for move in pick.move_lines]
             self.pool.get('stock.move').action_cancel(cr, uid, ids2, context)
-        self.write(cr, uid, ids, {'state': 'cancel'})
         return True
 
     def action_done(self, cr, uid, ids, context=None):
         """Changes picking state to done by processing the Stock Moves of the Picking
-          
+
         Normally that happens when the button "Done" is pressed on a Picking view.
         @return: True
         """
@@ -622,24 +565,29 @@ class stock_picking(osv.osv):
 
     def unlink(self, cr, uid, ids, context=None):
         move_obj = self.pool.get('stock.move')
-        if context is None:
-            context = {}
+        context = context or {}
         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,))
-            else:
-                ids2 = [move.id for move in pick.move_lines]
-                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)
-
+            ids2 = [move.id for move in pick.move_lines]
+            move_obj.action_cancel(cr, uid, ids2, ctx)
+            move_obj.unlink(cr, uid, ids2, ctx)
         return super(stock_picking, self).unlink(cr, uid, ids, context=context)
 
-    # FP Note: review all methods aboce this line for stock.picking
+    # FP Note: review all methods above this line for stock.picking
+
+    def _create_backorder(self, cr, uid, picking, context=None):
+        sequence_obj = self.pool.get('ir.sequence')
+        new_picking_name = picking.name
+        seq_id = picking.picking_type_id.sequence_id.id
+        back_order_name = sequence_obj.get_id(cr, uid, seq_id, 'id', context=context)
+        self.write(cr, uid, [picking.id], {'name': back_order_name})
+        backorder_id = self.copy(cr, uid, picking.id, {
+            'name': new_picking_name,
+            'move_lines': [],
+        })
+        self.message_post(cr, uid, picking.id, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
+        unlink_operation_order = [(2, op.id) for op in picking.pack_operation_ids]
+        self.write(cr, uid, [picking.id], {'backorder_id': backorder_id, 'pack_operation_ids': unlink_operation_order}, context=context)
+        return backorder_id
 
     def make_packaging(self, cr, uid, picking_id, todo_move_ids, context=None):
         quant_obj = self.pool.get('stock.quant')
@@ -797,16 +745,6 @@ class stock_picking(osv.osv):
             picking_to_package = stock_move_obj.browse(cr, uid, todo_move_ids[0], context=context).picking_id
             self.make_packaging(cr, uid, picking_to_package.id, todo_move_ids, context=context)
 
-    # views associated to each picking type
-    def _get_view_id(self, cr, uid, type):
-        """Get the view id suiting the given type
-
-        @param type: the picking type as a string
-        @return: view i, or False if no view found
-        """
-        res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 
-            'stock', 'view_picking_form')
-        return res and res[1] or False
 
     def _get_picking_for_packing_ui(self, cr, uid, context=None):
         res = self.search(cr, uid, [('state', '=', 'assigned')], limit=1, context=context)
@@ -894,17 +832,6 @@ class stock_production_lot(osv.osv):
     _sql_constraints = [
         ('name_ref_uniq', 'unique (name, ref)', 'The combination of Serial Number and internal reference must be unique !'),
     ]
-    def action_traceability(self, cr, uid, ids, context=None):
-        """ It traces the information of a product
-        @param self: The object pointer.
-        @param cr: A database cursor
-        @param uid: ID of the user currently logged in
-        @param ids: List of IDs selected
-        @param context: A standard dictionary
-        @return: A dictionary of values
-        """
-        value=self.pool.get('action.traceability').action_traceability(cr,uid,ids,context)
-        return value
 
 
 # ----------------------------------------------------
@@ -917,26 +844,6 @@ class stock_move(osv.osv):
     _order = 'date_expected desc, id'
     _log_create = False
 
-    def action_partial_move(self, cr, uid, ids, context=None):
-        if context is None: context = {}
-        if context.get('active_model') != self._name:
-            context.update(active_ids=ids, active_model=self._name)
-        partial_id = self.pool.get("stock.partial.move").create(
-            cr, uid, {}, context=context)
-        return {
-            'name':_("Products to Process"),
-            'view_mode': 'form',
-            'view_id': False,
-            'view_type': 'form',
-            'res_model': 'stock.partial.move',
-            'res_id': partial_id,
-            'type': 'ir.actions.act_window',
-            'nodestroy': True,
-            'target': 'new',
-            'domain': '[]',
-            'context': context
-        }
-
     def name_get(self, cr, uid, ids, context=None):
         res = []
         for line in self.browse(cr, uid, ids, context=context):
@@ -1020,7 +927,7 @@ class stock_move(osv.osv):
 
         # FP Note: should we remove this?
         'partner_id': fields.many2one('res.partner', 'Destination Address ', states={'done': [('readonly', True)]}, help="Optional address where goods are to be delivered, specifically used for allotment"),
-        
+
 
         'move_dest_id': fields.many2one('stock.move', 'Destination Move', help="Optional: next stock move when chaining them", select=True),
         'move_orig_ids': fields.one2many('stock.move', 'move_dest_id', 'Original Move', help="Optional: previous stock move when chaining them", select=True),
@@ -1050,54 +957,37 @@ class stock_move(osv.osv):
 
         # used for colors in tree views:
         'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
-        
-        'picking_type_id': fields.related('picking_id', 'picking_type_id', type='many2one', relation='stock.picking.type', string="Picking type" ,readonly=True), 
+
+        'picking_type_id': fields.related('picking_id', 'picking_type_id', type='many2one', relation='stock.picking.type', string="Picking type" ,readonly=True),
         'quant_ids': fields.many2many('stock.quant',  'stock_quant_move_rel', 'move_id', 'quant_id', 'Quants'),
         'reserved_quant_ids': fields.one2many('stock.quant', 'reservation_id', 'Reserved quants'),
         'remaining_qty': fields.function(_get_remaining_qty, type='float', string='Remaining Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}),
         'group_id': fields.many2one('procurement.group', 'Procurement Group'),
         'rule_id': fields.many2one('procurement.rule', 'Procurement Rule'),
         'propagate': fields.boolean('Propagate cancel and split', help='If checked, when this move is cancelled, cancel the linked move too'),
+        'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True),
     }
 
-    def _check_location(self, cr, uid, ids, context=None):
-        for record in self.browse(cr, uid, ids, context=context):
-            if (record.state=='done') and (record.location_id.usage == 'view'):
-                raise osv.except_osv(_('Error'), _('You cannot move product %s from a location of type view %s.')% (record.product_id.name, record.location_id.name))
-            if (record.state=='done') and (record.location_dest_id.usage == 'view' ):
-                raise osv.except_osv(_('Error'), _('You cannot move product %s to a location of type view %s.')% (record.product_id.name, record.location_dest_id.name))
-        return True
-
-    _constraints = [
-        (_check_location, 'You cannot move products from or to a location of the type view.',
-            ['location_id','location_dest_id'])
-    ]
-
-
     def copy(self, cr, uid, id, default=None, context=None):
         if default is None:
             default = {}
         default = default.copy()
-        default['procurement_group'] = False
+        default['move_orig_ids'] = []
+        default['quant_ids'] = []
+        default['reserved_quant_ids'] = []
+        default['state'] = 'draft'
         return super(stock_move, self).copy(cr, uid, id, default, context)
-    
-    
+
     def _default_location_destination(self, cr, uid, context=None):
-        """ Gets default address of partner for destination location
-        @return: Address id or False
-        """
         context = context or {}
-        if 'picking_type_id' in context and context['picking_type_id']:
+        if context.get('picking_type_id', False):
             pick_type = self.pool.get('stock.picking.type').browse(cr, uid, context['picking_type_id'], context=context)
             return pick_type.location_dest_id and pick_type.location_dest_id.id or False
         return False
 
     def _default_location_source(self, cr, uid, context=None):
-        """ Gets default address of partner for source location
-        @return: Address id or False
-        """
         context = context or {}
-        if 'picking_type_id' in context and context['picking_type_id']:
+        if context.get('picking_type_id', False):
             pick_type = self.pool.get('stock.picking.type').browse(cr, uid, context['picking_type_id'], context=context)
             return pick_type.location_src_id and pick_type.location_src_id.id or False
         return False
@@ -1107,9 +997,6 @@ class stock_move(osv.osv):
         return user.company_id.partner_id.id
 
     def _default_picking_type(self, cr, uid, context=None):
-        """ Gets default type of move
-        @return: type
-        """
         context = context or {}
         return context.get('picking_type_id', False)
 
@@ -1147,7 +1034,7 @@ class stock_move(osv.osv):
                 'product_uos': (move.product_uos and move.product_uos.id) or move.product_uom.id,
                 'location_id': move.location_id.id,
                 'move_dest_id': move.id,
-                'group_id': move.group_id and move.group_id.id or False, 
+                'group_id': move.group_id and move.group_id.id or False,
             })
 
     # Check that we do not modify a stock.move which is done
@@ -1163,18 +1050,6 @@ class stock_move(osv.osv):
         result = super(stock_move, self).write(cr, uid, ids, vals, context=context)
         return result
 
-
-
-    def _auto_init(self, cursor, context=None):
-        res = super(stock_move, self)._auto_init(cursor, context=context)
-        cursor.execute('SELECT indexname \
-                FROM pg_indexes \
-                WHERE indexname = \'stock_move_location_id_location_dest_id_product_id_state\'')
-        if not cursor.fetchone():
-            cursor.execute('CREATE INDEX stock_move_location_id_location_dest_id_product_id_state \
-                    ON stock_move (product_id, state, location_id, location_dest_id)')
-        return res
-
     def onchange_quantity(self, cr, uid, ids, product_id, product_qty,
                           product_uom, product_uos):
         """ On change of product quantity finds UoM and UoS quantities
@@ -1185,8 +1060,8 @@ class stock_move(osv.osv):
         @return: Dictionary of values
         """
         result = {
-                  'product_uos_qty': 0.00
-          }
+            'product_uos_qty': 0.00
+        }
         warning = {}
 
         if (not product_id) or (product_qty <=0.0):
@@ -1195,8 +1070,8 @@ class stock_move(osv.osv):
 
         product_obj = self.pool.get('product.product')
         uos_coeff = product_obj.read(cr, uid, product_id, ['uos_coeff'])
-        
-        # Warn if the quantity was decreased 
+
+        # Warn if the quantity was decreased
         if ids:
             for move in self.read(cr, uid, ids, ['product_qty']):
                 if product_qty < move['product_qty']:
@@ -1234,8 +1109,8 @@ class stock_move(osv.osv):
 
         product_obj = self.pool.get('product.product')
         uos_coeff = product_obj.read(cr, uid, product_id, ['uos_coeff'])
-        
-        # Warn if the quantity was decreased 
+
+        # Warn if the quantity was decreased
         for move in self.read(cr, uid, ids, ['product_uos_qty']):
             if product_uos_qty < move['product_uos_qty']:
                 warning.update({
@@ -1285,58 +1160,34 @@ class stock_move(osv.osv):
             result['location_dest_id'] = loc_dest_id
         return {'value': result}
 
-    def onchange_move_type(self, cr, uid, ids, picking_type_id, context=None):
-        """ On change of move type gives sorce and destination location.
-        @param type: Move Type
-        @return: Dictionary of values
-        """
-        mod_obj = self.pool.get('ir.model.data')
-        location_source_id = 'stock_location_stock'
-        location_dest_id = 'stock_location_stock'
-        type="internal"
-        if type == 'in':
-            location_source_id = 'stock_location_suppliers'
-            location_dest_id = 'stock_location_stock'
-        elif type == 'out':
-            location_source_id = 'stock_location_stock'
-            location_dest_id = 'stock_location_customers'
-        source_location = mod_obj.get_object_reference(cr, uid, 'stock', location_source_id)
-        dest_location = mod_obj.get_object_reference(cr, uid, 'stock', location_dest_id)
-        #Check companies
-        user_company = self.pool.get("res.users").browse(cr, uid, uid, context=context).company_id.id
-        if source_location:
-            location_company = self.pool.get("stock.location").browse(cr, uid, source_location[1], context=context).company_id
-            if location_company and location_company.id != user_company:
-                source_location = False
-        if dest_location:
-            location_company = self.pool.get("stock.location").browse(cr, uid, dest_location[1], context=context).company_id
-            if location_company and location_company.id != user_company:
-                dest_location = False
-        return {'value': {'location_id': source_location and source_location[1] or False, 'location_dest_id': dest_location and dest_location[1] or False}}
-
-    def _find_or_create_picking(self, cr, uid, move, context=None):
-        if context is None:
-            context = {}
-        # TODO: Put the move in the right picking according to group_id -> should be more elaborated (draft is nok) and picking should be confirmed
+    def _picking_assign(self, cr, uid, move, context=None):
+        if move.picking_id or \
+          move.location_id.usage in ['production', 'inventory'] or \
+          move.location_dest_id.usage in ['production', 'inventory']:
+            return False
+        context = context or {}
         pick_obj = self.pool.get("stock.picking")
-        picks = pick_obj.search(cr, uid, [('group_id', '=', move.group_id.id), ('location_id', '=', move.location_id.id),
-                                          ('location_dest_id', '=', move.location_dest_id.id), ('state', 'in', ['confirmed', 'waiting', 'draft'])], context=context)
+        picks = pick_obj.search(cr, uid, [
+            ('group_id', '=', move.group_id and move.group_id.id or False),
+            ('location_id', '=', move.location_id.id),
+            ('location_dest_id', '=', move.location_dest_id.id),
+            ('state', 'in', ['confirmed', 'auto'])], context=context)
         if picks:
             pick = picks[0]
         else:
-            #a picking doesn't exist yet, create a new one
-            values = {'origin': move.origin,
-                      'company_id': move.company_id and move.company_id.id or False,
-                      'move_type': 'one',
-                      'partner_id': move.partner_id and move.partner_id.id or False,
-                      'date_done': move.date_expected,
-                      #'invoice_state': move.invoice_state
-                      'state': 'confirmed',
-                      'group_id': move.group_id and move.group_id.id or False,
-                      'picking_type_id': move.rule_id and move.rule_id.picking_type_id.id or False,
+            values = {
+                'origin': move.origin,
+                'company_id': move.company_id and move.company_id.id or False,
+                'move_type': move.group_id and move.group_id.move_type or 'one',
+                'partner_id': move.partner_id and move.partner_id.id or False,
+                'date_done': move.date_expected,
+                'state': 'confirmed',
+                'group_id': move.group_id and move.group_id.id or False,
+                'picking_type_id': move.picking_type_id and move.picking_type_id.id or False,
             }
             pick = pick_obj.create(cr, uid, values, context=context)
-        return pick
+        move.write({'picking_id': pick})
+        return True
 
     def onchange_date(self, cr, uid, ids, date, date_expected, context=None):
         """ On change of Scheduled Date gives a Move date.
@@ -1363,9 +1214,7 @@ class stock_move(osv.osv):
                     state = 'waiting'
             states[state].append(move.id)
 
-            if not move.picking_id and move.location_id.usage not in ['production', 'inventory'] and move.location_dest_id.usage not in ['production', 'inventory']:
-                pick = self._find_or_create_picking(cr, uid, move, context=context)
-                move.write({'picking_id': pick})
+            self._picking_assign(cr, uid, move, context=context)
 
 
         for state, write_ids in states.items():
@@ -1382,9 +1231,9 @@ class stock_move(osv.osv):
         @return: True
         """
         done = self.action_assign(cr, uid, ids, context=context)
-        self.write(cr, uid, list(set(ids) - set(done)), {'state': 'assigned'})        
+        self.write(cr, uid, list(set(ids) - set(done)), {'state': 'assigned'})
         return True
-    
+
 
     def cancel_assign(self, cr, uid, ids, context=None):
         """ Changes the state to confirmed.
@@ -1414,7 +1263,7 @@ class stock_move(osv.osv):
                         dp.append(str(q.id))
                 domain = ['|', ('reservation_id', '=', False), ('reservation_id', '=', move.id)]
                 quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, qty, domain=domain, prefered_order = dp and ('id not in ('+','.join(dp)+')') or False, context=context)
-                #Will only reserve physical quants, no negative 
+                #Will only reserve physical quants, no negative
                 quant_obj.quants_reserve(cr, uid, quants, move, context=context)
                 # the total quantity is provided by existing quants
                 if all(map(lambda x:x[0], quants)):
@@ -1469,7 +1318,7 @@ class stock_move(osv.osv):
             if move.picking_id:
                 pickings.add(move.picking_id.id)
             qty = move.product_uom_qty
-            
+
             # for qty, location_id in move_id.prefered_location_ids:
             #    quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, qty, context=context)
             #    quant_obj.quants_move(cr, uid, quants, move, location_dest_id, context=context)
@@ -1479,7 +1328,7 @@ class stock_move(osv.osv):
             #Will move all quants_get and as such create negative quants
             quant_obj.quants_move(cr, uid, quants, move, context=context)
             quant_obj.quants_unreserve(cr, uid, move, context=context)
-            
+
             #
             #Check moves that were pushed
             if move.move_dest_id.state in ('waiting', 'confirmed'):
@@ -1499,14 +1348,11 @@ class stock_move(osv.osv):
         return True
 
     def unlink(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        ctx = context.copy()
+        context = context or {}
         for move in self.browse(cr, uid, ids, context=context):
-            if move.state != 'draft' and not ctx.get('call_unlink', False):
+            if move.state not in ('draft', 'cancel'):
                 raise osv.except_osv(_('User Error!'), _('You can only delete draft moves.'))
-        return super(stock_move, self).unlink(
-            cr, uid, ids, context=ctx)
+        return super(stock_move, self).unlink(cr, uid, ids, context=context)
 
     def action_scrap(self, cr, uid, ids, quantity, location_id, context=None):
         """ Move the scrap/damaged product into scrap location
@@ -1613,12 +1459,12 @@ class stock_move(osv.osv):
 
 #    def price_calculation(self, cr, uid, ids, quants, context=None):
 #        '''
-#        This method puts the right price on the stock move, 
+#        This method puts the right price on the stock move,
 #        adapts the price on the product when necessary
 #        and creates the necessary stock move matchings
 #        :param quants: are quants to be reconciled and needs to be done when IN move reconciles out move
-#        
-#        It returns a list of tuples with (move_id, match_id) 
+#
+#        It returns a list of tuples with (move_id, match_id)
 #        which is used for generating the accounting entries when FIFO/LIFO
 #        '''
 #        product_obj = self.pool.get('product.product')
@@ -1626,7 +1472,7 @@ class stock_move(osv.osv):
 #        matching_obj = self.pool.get('stock.move.matching')
 #        uom_obj = self.pool.get('product.uom')
 #        quant_obj = self.pool.get('stock.quant')
-#        
+#
 #        product_avail = {}
 #        res = {}
 #        for move in self.browse(cr, uid, ids, context=context):
@@ -1643,9 +1489,9 @@ class stock_move(osv.osv):
 #            product_uom_qty = uom_obj._compute_qty(cr, uid, move_uom, move_qty, product.uom_id.id, round=False)
 #            if not product.id in product_avail:
 #                product_avail[product.id] = product.qty_available
-#            
+#
 #            # Check if out -> do stock move matchings and if fifo/lifo -> update price
-#            # only update the cost price on the product form on stock moves of type == 'out' because if a valuation has to be made without PO, 
+#            # only update the cost price on the product form on stock moves of type == 'out' because if a valuation has to be made without PO,
 #            # for inventories for example we want to use the last value used for an outgoing move
 #            if move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal':
 #                fifo = (cost_method != 'lifo')
@@ -1658,14 +1504,14 @@ class stock_move(osv.osv):
 #                for quant in quant_obj.browse(cr, uid, quants_move, context=context):
 #                    price_amount += quant.qty * quant.price_unit
 #                    amount += quant.qty
-#                
-##                 tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], move_qty, fifo, 
+#
+##                 tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], move_qty, fifo,
 ##                                                                   move_uom, move.company_id.currency_id.id, context=ctx) #TODO Would be better to use price_currency_id for migration?
 ##                 price_amount = 0.0
 ##                 amount = 0.0
 ##                 #Write stock matchings
-##                 for match in tuples: 
-##                     matchvals = {'move_in_id': match[0], 'qty': match[1], 
+##                 for match in tuples:
+##                     matchvals = {'move_in_id': match[0], 'qty': match[1],
 ##                                  'move_out_id': move.id}
 ##                     match_id = matching_obj.create(cr, uid, matchvals, context=context)
 ##                     res[move.id].append(match_id)
@@ -1675,11 +1521,11 @@ class stock_move(osv.osv):
 #                if product_avail[product.id] >= product_uom_qty and product.cost_method in ['real']:
 #                    if amount > 0:
 #                        self.write(cr, uid, move.id, {'price_unit': price_amount / move_qty}, context=context) #Should be converted
-#                        product_obj.write(cr, uid, product.id, {'standard_price': price_amount / amount}, context=ctx) 
+#                        product_obj.write(cr, uid, product.id, {'standard_price': price_amount / amount}, context=ctx)
 #                    else:
 #                        pass
-##                         raise osv.except_osv(_('Error'), _("Something went wrong finding quants ")  + str(self.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'), 
-##                                              ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal'), ('product_id', '=', product.id)], 
+##                         raise osv.except_osv(_('Error'), _("Something went wrong finding quants ")  + str(self.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'),
+##                                              ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal'), ('product_id', '=', product.id)],
 ##                                        order = 'date, id', context=context)) + str(move_qty) + str(move_uom) + str(move.company_id.currency_id.id))
 #                else:
 #                    new_price = uom_obj._compute_price(cr, uid, product.uom_id.id, product.standard_price, move_uom)
@@ -1687,7 +1533,7 @@ class stock_move(osv.osv):
 #                #Adjust product_avail when not average and move returned from
 #                if product.cost_method != 'average':
 #                    product_avail[product.id] -= product_uom_qty
-#            
+#
 #            #Check if in => if price 0.0, take standard price / Update price when average price and price on move != standard price
 #            if move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal':
 #                if move.price_unit == 0.0:
@@ -1859,7 +1705,7 @@ class stock_inventory(osv.osv):
                         'product_id': line.product_id.id,
                         'product_uom': line.product_uom.id,
                         'date': inv.date,
-                        'company_id': line.location_id.company_id.id,  
+                        'company_id': line.location_id.company_id.id,
                     }
 
                     if change > 0:
@@ -2276,7 +2122,7 @@ class stock_picking_code(osv.osv):
     _name = "stock.picking.code"
     _description = "Will group picking types for kanban view"
     _columns = {
-        'name': fields.char("Picking Type", translate=True), 
+        'name': fields.char("Picking Type", translate=True),
     }
 
 class stock_picking_type(osv.osv):
@@ -2337,7 +2183,7 @@ class stock_picking_type(osv.osv):
         }
         result = {}
         for field in domains:
-            data = obj.read_group(cr, uid, domains[field] + 
+            data = obj.read_group(cr, uid, domains[field] +
                 [('state', 'not in',('done','cancel','draft')), ('picking_type_id', 'in', ids)],
                 ['picking_type_id'], ['picking_type_id'], context=context)
             count = dict(map(lambda x: (x['picking_type_id'], x['__count']), data))
@@ -2379,7 +2225,7 @@ class stock_picking_type(osv.osv):
 
         # Statistics for the kanban view
         'weekly_picking': fields.function(_get_picking_data,
-            type='string', 
+            type='string',
             string='Scheduled pickings per week'),
 
         'count_picking': fields.function(_get_picking_count,
index 4b22896..9771ce0 100644 (file)
             <field eval="12" name="priority"/>
             <field name="arch" type="xml">
                 <form string="Internal Picking List" version="7.0">
-                <field name='pack_operation_exist' invisible="1"/>
                 <header>
-                    <button name="draft_force_assign" states="draft" string="Confirm" type="object" class="oe_highlight" groups="base.group_user"/>
-                    <button name="draft_validate" states="draft" string="Confirm &amp; Total Transfer" type="object" class="oe_highlight" groups="base.group_user"/>
+                    <button name="force_assign" states="draft" string="Confirm" type="object" class="oe_highlight" groups="base.group_user"/>
                     <!-- <button name="check_assign" states="confirmed" string="Check Availability" type="object"/> -->
                     <button name="force_assign" states="confirmed" string="Force Availability" type="object" class="oe_highlight" groups="base.group_user"/>
                     <button name="action_done" states="assigned" string="Total Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
-                    <button name="do_prepare_partial" states="assigned" string="(prepare) Partial Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': [('pack_operation_exist','=',True)]}"/>
-                    <button name="do_partial" states="assigned" string="Partial Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': [('pack_operation_exist','=',False)]}"/>
+                    <button name="do_prepare_partial" states="assigned" string="(prepare) Partial Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': [('pack_operation_ids','&lt;&gt;',False)]}"/>
+                    <button name="do_partial" states="assigned" string="Partial Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': [('pack_operation_ids','=',False)]}"/>
                     <button name="%(act_stock_return_picking)d" string="Reverse Transfer" states="done" type="action" groups="base.group_user"/>
                     <button name="button_cancel" states="assigned,confirmed,draft" string="Cancel Transfer" groups="base.group_user"/>
                     <field name="state" widget="statusbar" statusbar_visible="draft,assigned,done" statusbar_colors='{"shipping_except":"red","invoice_except":"red","waiting_date":"blue"}'/>
                         </group>
                     </group>
                     <notebook>
-                        <page string="Partial/Packing Operations" attrs="{'invisible': [('pack_operation_exist','=',False)]}">
+                        <page string="Partial/Packing Operations" attrs="{'invisible': [('pack_operation_ids','=',False)]}">
                             <field name="pack_operation_ids">
                                 <tree editable="top">
                                     <field name="product_id"/>
index adb89ea..4979707 100644 (file)
@@ -19,7 +19,6 @@
 #
 ##############################################################################
 
-import stock_traceability
 import stock_move
 import stock_inventory_merge
 import stock_fill_inventory
diff --git a/addons/stock/wizard/stock_traceability.py b/addons/stock/wizard/stock_traceability.py
deleted file mode 100644 (file)
index c13fc1c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-from openerp.tools.translate import _
-
-class action_traceability(osv.osv_memory):
-    """
-    This class defines a function action_traceability for wizard
-
-    """
-    _name = "action.traceability"
-    _description = "Action traceability "
-     
-    def action_traceability(self, cr, uid, ids, context=None):
-        """ It traces the information of a product
-        @param self: The object pointer.
-        @param cr: A database cursor
-        @param uid: ID of the user currently logged in
-        @param ids: List of IDs selected
-        @param context: A standard dictionary
-        @return: A dictionary of values
-        """
-        lot_id = ids
-        if context is None:
-            context = {}
-        type1 = context.get('type', 'move_history_ids2')
-        field = context.get('field', 'tracking_id')
-        obj = self.pool.get('stock.move')
-        ids = obj.search(cr, uid, [(field, 'in',lot_id)])
-        cr.execute('select id from ir_ui_view where model=%s and field_parent=%s and type=%s', ('stock.move', type1, 'tree'))
-        view_ids = cr.fetchone()
-        view_id = view_ids and view_ids[0] or False
-        value = {
-            'domain': "[('id','in',["+','.join(map(str, ids))+"])]",
-            'name': ((type1=='move_history_ids2') and _('Upstream Traceability')) or _('Downstream Traceability'),
-            'view_mode': 'tree',
-            'view_type': 'tree',
-            'res_model': 'stock.move',
-            'field_parent': type1,
-            'view_id': (view_id,'View'),
-            'type': 'ir.actions.act_window',
-            'nodestroy':True,
-        }
-        return value
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-