[IMP] mrp: Improvement in MRP
authorHarry (Open ERP) <hmo@tinyerp.com>
Tue, 23 Feb 2010 05:34:00 +0000 (11:04 +0530)
committerHarry (Open ERP) <hmo@tinyerp.com>
Tue, 23 Feb 2010 05:34:00 +0000 (11:04 +0530)
lp bug: https://launchpad.net/bugs/506017 fixed

bzr revid: hmo@tinyerp.com-20100223053400-1nikokxmgqgvcgxd

1  2 
addons/mrp/mrp.py
addons/mrp/mrp_view.xml
addons/stock/__terp__.py
addons/stock/stock.py
addons/stock/stock_view.xml
addons/stock/stock_wizard.py
addons/stock/stock_wizard_view.xml

@@@ -544,7 -583,11 +583,7 @@@ class mrp_production(osv.osv)
  
      #TODO Review materials in function in_prod and prod_end.
      def action_production_end(self, cr, uid, ids):
--#        move_ids = []
++        move_ids = []
          for production in self.browse(cr, uid, ids):
              for res in production.move_lines:
                  for move in production.move_created_ids:
                      cr.execute('INSERT INTO stock_move_history_ids \
                              (parent_id, child_id) VALUES (%s,%s)',
                              (res.id, move.id))
--#                move_ids.append(res.id)
++                move_ids.append(res.id)
              vals= {'state':'confirmed'}
              new_moves = [x.id for x in production.move_created_ids]
              self.pool.get('stock.move').write(cr, uid, new_moves, vals)
          return amount
  
      def action_in_production(self, cr, uid, ids):
--        move_ids = []
--        for production in self.browse(cr, uid, ids):
--            for res in production.move_lines:
--                move_ids.append(res.id)
--            if not production.date_start:
--                self.write(cr, uid, [production.id],
--                        {'date_start': time.strftime('%Y-%m-%d %H:%M:%S')})
-         self.pool.get('stock.move').action_done(cr, uid, move_ids)
 -#        self.pool.get('stock.move').action_done(cr, uid, move_ids)
++        move_ids = []        
          self.write(cr, uid, ids, {'state': 'in_production'})
          return True
  
@@@ -1299,6 -1342,40 +1331,41 @@@ class StockMove(osv.osv)
                      wf_service = netsvc.LocalService("workflow")
                      wf_service.trg_validate(uid, 'mrp.procurement', m, 'button_wait_done', cr)
          return True
+     
 -    def _track_lines(self, cr, uid, ids, data, context=None):
 -        production_ids = []
 -        new_move = super(StockMove, self)._track_lines(cr, uid, ids, data, context=context)
 -        if new_move:
 -            production_obj = self.pool.get('mrp.production')
 -            move_obj = self.pool.get('stock.move')
 -            move = move_obj.browse(cr, uid, ids)
 -            production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
 -            for new in new_move:
 -                production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new)]})
 -                move_obj.action_done(cr, uid, [new])
 -        return {}
+     
+     def consume_moves(self, cr, uid, ids, product_qty, location_id, context=None):
 -        new_move = super(StockMove, self).consume_moves(cr, uid, ids, product_qty, location_id, context=context)
 -        if new_move:
 -            production_obj = self.pool.get('mrp.production')
 -            move_obj = self.pool.get('stock.move')
 -            move = move_obj.browse(cr, uid, ids)
++        res = []
++        production_obj = self.pool.get('mrp.production')
++        for move in self.browse(cr, uid, ids):
++            new_moves = super(StockMove, self).consume_moves(cr, uid, ids, product_qty, location_id, context=context)
+             production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
 -            production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
 -        return {}
++            for new_move in new_moves:
++                production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
++                res.append(new_move)
++        return res
++
++    def split_lines(self, cr, uid, ids, quantity, split_by_qty=1, prefix=False, context=None):
++        res = []
++        production_obj = self.pool.get('mrp.production')
++        for move in self.browse(cr, uid, ids):
++            new_moves = super(StockMove, self).split_lines(cr, uid, [move.id], quantity, split_by_qty, prefix, context=context)
++            production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
++            for new_move in new_moves:
++                production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
++                res.append(new_move)
++        return res
+     
 -    def scrap_moves(self, cr, uid, ids, product_qty, location_id, context=None):
 -        new_move = super(StockMove, self).scrap_moves(cr, uid, ids, product_qty, location_id, context=context)
 -        if new_move:
 -            production_obj = self.pool.get('mrp.production')
 -            move_obj = self.pool.get('stock.move')
 -            move = move_obj.browse(cr, uid, ids)
++    def scrap_moves(self, cr, uid, ids, quantity, location_dest_id, context=None):
++        res = []
++        production_obj = self.pool.get('mrp.production')
++        for move in self.browse(cr, uid, ids):
++            new_moves = super(StockMove, self).scrap_moves(cr, uid, [move.id], quantity, location_dest_id, context=context)
+             production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
 -            production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
 -        return {}
++            for new_move in new_moves:
++                production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
++                res.append(new_move)
++        return res
  StockMove()
  
  
@@@ -1326,5 -1403,5 +1393,20 @@@ class StockPicking(osv.osv)
  
  StockPicking()
  
++
++class spilt_in_production_lot(osv.osv_memory):
++    _inherit = "stock.move.spilt"
++    def split(self, cr, uid, ids, move_ids, context=None):
++        production_obj = self.pool.get('mrp.production')
++        move_obj = self.pool.get('stock.move')  
++        res = []      
++        for move in move_obj.browse(cr, uid, move_ids, context=context):
++            new_moves = super(spilt_in_production_lot, self).split(cr, uid, ids, move_ids, context=context)
++            production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
++            for new_move in new_moves:
++                production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})                
++        return res
++spilt_in_production_lot()
++
  # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
  
                                  <field name="state" select="2"/>
                                  <button name="action_compute" states="draft" string="Compute Data" type="object" icon="gtk-execute"/>
                                  <button name="button_confirm" states="draft" string="Confirm Production" icon="gtk-apply"/>
-                                 <button name="button_produce" states="ready" string="Start Production" icon="gtk-media-play"/>
-                                 <button name="button_produce_done" states="in_production" string="Production done" icon="gtk-ok"/>
 -<!--                                <button name="action_start" states="ready" string="Mark as Start" icon="gtk-media-play" type="object"/>-->
 -                                <button name="button_produce" states="ready" string="Produce" icon="gtk-execute"/>
 -                                <button name="button_produce_done" states="in_production" string="Production done" icon="gtk-ok"/>
++                                <button name="button_produce" states="ready" string="Mark as Start" icon="gtk-execute"/>
++                                <button name="button_produce_done" states="in_production" string="Production" icon="gtk-ok"/>
                                  <button name="force_production" states="confirmed,picking_except" string="Force Reservation" type="object" icon="gtk-jump-to"/>
                                  <button name="button_cancel" states="draft,ready,confirmed,in_production,picking_except" string="Cancel" icon="gtk-cancel"/>
                                  <button name="button_recreate" states="picking_except" string="Recreate Picking" icon="gtk-convert"/>
@@@ -45,6 -45,7 +45,7 @@@ Thanks to the double entry management, 
          "stock_data.xml",
          "stock_incoterms.xml",
          "stock_wizard.xml",
 -        "stock_osv_wizards.xml", 
++        "stock_wizard_view.xml", 
          "stock_view.xml",
          "stock_report.xml",
          "stock_sequence.xml",
@@@ -856,12 -857,12 +857,15 @@@ class stock_production_lot(osv.osv)
      def name_get(self, cr, uid, ids, context={}):
          if not ids:
              return []
--        reads = self.read(cr, uid, ids, ['name', 'ref'], context)
++        reads = self.read(cr, uid, ids, ['name', 'prefix', 'ref'], context)
          res = []
          for record in reads:
              name = record['name']
++            prefix = record['prefix']
++            if prefix:
++                name = prefix + '/' + name
              if record['ref']:
--                name = name + '/' + record['ref']
++                name = '%s [%s]' % (name, record['ref'])
              res.append((record['id'], name))
          return res
  
  
      _columns = {
          'name': fields.char('Serial', size=64, required=True),
--        'ref': fields.char('Internal Reference', size=64),
++        'ref': fields.char('Internal Reference', size=256),
++        'prefix': fields.char('Prefix', size=64),
          'product_id': fields.many2one('product.product', 'Product', required=True),
          'date': fields.datetime('Created Date', required=True),
          'stock_available': fields.function(_get_stock, fnct_search=_stock_search, method=True, type="float", string="Available", select="2"),
  
  stock_production_lot()
  
--class stock_split_production_lots(osv.osv_memory):
--    _name = "stock.split.production.lots"
--    _description = "Split Production Lots"
--
--    def _quantity_default_get(self, cr, uid, object=False, field=False, context=None):
--        cr.execute("select %s from %s where id=%s" %(field,object,context.get('active_id')))
--        res = cr.fetchone()[0]
--        return res
--
--    _columns = {
--        'name': fields.char('Lot Number/Prefix', size=64, required=True),
--        'qty': fields.float('Total Quantity'),
--        'action': fields.selection([('split','Split'),('keepinone','Keep in one lot')],'Action'),
--    }
--    _defaults = {
--                 'qty': lambda self,cr,uid,c: self.pool.get('stock.split.production.lots')._quantity_default_get(cr, uid, 'stock_move', 'product_qty',context=c) or 1,
--    }
--
--    def split_lines(self, cr, uid, ids, context={}):
--        data = self.read(cr, uid, ids[0])
--        prodlot_obj = self.pool.get('stock.production.lot')
--        move_obj = self.pool.get('stock.move')
--        move_browse = move_obj.browse(cr, uid, context['active_id'])
--
--        quantity = data['qty']
--        if quantity <= 0 or move_browse.product_qty == 0:
--            return {}
--        uos_qty = quantity/move_browse.product_qty*move_browse.product_uos_qty
--
--        quantity_rest = move_browse.product_qty%quantity
--        uos_qty_rest = quantity_rest/move_browse.product_qty*move_browse.product_uos_qty
--
--        update_val = {
--            'product_qty': quantity,
--            'product_uos_qty': uos_qty,
--        }
--
--        new_move = []
--        for idx in range(int(move_browse.product_qty//quantity)):
--            if idx:
--                current_move = move_obj.copy(cr, uid, move_browse.id, {'state': move_browse.state})
--                new_move.append(current_move)
--            else:
--                current_move = move_browse.id
--            new_prodlot = prodlot_obj.create(cr, uid, {'name': data['name'], 'ref': '%d'%idx}, {'product_id': move_browse.product_id.id})
--            update_val['prodlot_id'] = new_prodlot
--            move_obj.write(cr, uid, [current_move], update_val)
--
--        if quantity_rest > 0:
--            idx = int(move_browse.product_qty//quantity)
--            update_val['product_qty'] = quantity_rest
--            update_val['product_uos_qty'] = uos_qty_rest
--            if idx:
--                current_move = move_obj.copy(cr, uid, move_browse.id, {'state': move_browse.state})
--                new_move.append(current_move)
--            else:
--                current_move = move_browse.id
--            new_prodlot = prodlot_obj.create(cr, uid, {'name': data['name'], 'ref': '%d'%idx}, {'product_id': move_browse.product_id.id})
--            update_val['prodlot_id'] = new_prodlot
--            move_obj.write(cr, uid, [current_move], update_val)
--
--        return {}
--
--stock_split_production_lots()
--
--
  class stock_production_lot_revision(osv.osv):
      _name = 'stock.production.lot.revision'
      _description = 'Production lot revisions'
@@@ -1491,7 -1492,125 +1430,133 @@@ class stock_move(osv.osv)
                  raise osv.except_osv(_('UserError'),
                          _('You can only delete draft moves.'))
          return super(stock_move, self).unlink(
--            cr, uid, ids, context=context)
++            cr, uid, ids, context=context)    
 -    def _track_lines(self, cr, uid, ids, lines, context=None):
++    def split_lines(self, cr, uid, ids, quantity, split_by_qty=1, prefix=False, context=None):
+         prodlot_obj = self.pool.get('stock.production.lot')
+         ir_sequence_obj = self.pool.get('ir.sequence')
++
+         sequence = ir_sequence_obj.get(cr, uid, 'stock.lot.serial')
+         if not sequence:
 -            raise osv.except_osv(_('Error!'), _('No production sequence defined'))
++            raise wizard.except_wizard(_('Error!'), _('No production sequence defined'))
++        new_move = []      
++
++        def _create_lot(move_id, product_id):
++            prodlot_id = prodlot_obj.create(cr, uid, {'name': sequence, 'prefix': prefix}, {'product_id': product_id})
++            prodlot = prodlot_obj.browse(cr, uid, prodlot_id) 
++            ref = '%d' % (move_id)
++            if prodlot.ref:
++                ref = '%s, %s' % (prodlot.ref, ref) 
++            prodlot_obj.write(cr, uid, [prodlot_id], {'ref': ref})
++            return prodlot_id
++
++        for move in self.browse(cr, uid, ids):            
++            if split_by_qty <= 0 or quantity == 0:
++                return res
++
++            uos_qty = split_by_qty / move.product_qty * move.product_uos_qty
++
++            quantity_rest = quantity % split_by_qty
++            uos_qty_rest = split_by_qty / move.product_qty * move.product_uos_qty
++
++            update_val = {
++                'product_qty': split_by_qty,
++                'product_uos_qty': uos_qty,
++            }                
++            for idx in range(int(quantity//split_by_qty)):
++                if idx:        
++                    current_move = self.copy(cr, uid, move.id, {'state': move.state})
++                    new_move.append(current_move)
++                else:
++                    current_move = move.id
++                
 -        move = self.browse(cr, uid, [ids])[0]
 -        move_qty = move.product_qty
 -        quantity_rest = move.product_qty
 -        uos_qty_rest = move.product_uos_qty
 -        new_move = []
 -        cnt = 0
++                update_val['prodlot_id'] = _create_lot(current_move, move.product_id.id)
++                self.write(cr, uid, [current_move], update_val)
++        
++            
++            if quantity_rest > 0:
++                idx = int(quantity//split_by_qty)
++                update_val['product_qty'] = quantity_rest
++                update_val['product_uos_qty'] = uos_qty_rest
++                if idx:        
++                    current_move = self.copy(cr, uid, move.id, {'state': move.state})
++                    new_move.append(current_move)
++                else:
++                    current_move = move.id                
++                update_val['prodlot_id'] = _create_lot(current_move, move.product_id.id)
++                self.write(cr, uid, [current_move], update_val)
++        return new_move
 -        for line in lines:
 -            quantity = line['quantity']
 -            sequence = (line['tracking_num'] and line['tracking_num'] + '/' \
 -                            + sequence) or sequence
++    def consume_moves(self, cr, uid, ids, quantity, location_id, context=None):
++        new_move = []
++        if not context:
++            context = {}        
++        if quantity <= 0:
++            raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
++       
++        for move in self.browse(cr, uid, ids, context=context):
++            move_qty = move.product_qty
++            quantity_rest = move.product_qty
 -            if quantity <= 0 or move_qty == 0:
 -                continue
+             quantity_rest -= quantity
+             uos_qty = quantity / move_qty * move.product_uos_qty
+             uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
+             if quantity_rest <= 0:
+                 quantity_rest = quantity
+                 break
++
+             default_val = {
+                 'product_qty': quantity, 
 -                'product_uos_qty': uos_qty, 
 -                'state': move.state
++                'product_uos_qty': uos_qty,
++                'location_id' : location_id,                
+             }
 -            current_move = self.copy(cr, uid, move.id, default_val)
 -            new_move.append(current_move)
 -            new_prodlot = prodlot_obj.create(cr, uid, {'name': sequence, 
 -                                         'ref': '%d' % (cnt)}, 
 -                                         {'product_id': move.product_id.id})
 -            self.write(cr, uid, [current_move], {'prodlot_id': new_prodlot})
 -            cnt += 1
 -
 -        if quantity_rest > 0:
 -            new_prodlot = prodlot_obj.create(cr, uid, {'name': sequence, 
 -                                            'ref': '%d' % (cnt)}, 
 -                                            {'product_id': move.product_id.id})
 -            update_val= {'prodlot_id': new_prodlot, 
 -                                    'product_qty': quantity_rest, 
 -                                    'product_uos_qty': uos_qty_rest
 -                                    }
 -            self.write(cr, uid, [move.id], update_val)
++            if move.product_id.track_production:
++                new_move = self.split_lines(cr, uid, [move.id], quantity, split_by_qty=1, context=context)
++            else:
++                current_move = self.copy(cr, uid, move.id, default_val)
++                new_move.append(current_move)
++
++            update_val = {}
++            if quantity_rest > 0:                        
++                update_val['product_qty'] = quantity_rest
++                update_val['product_uos_qty'] = uos_qty_rest                          
++                self.write(cr, uid, [move.id], update_val)
++            
++            self.action_done(cr, uid, new_move)
+         return new_move
 -    def consume_moves(self, cr, uid, ids, product_qty, location_id, context=None):
 -        new_move = None
 -        if not context:
 -            context = {}
 -        qty = product_qty
 -        if qty <= 0:
++    def scrap_moves(self, cr, uid, ids, quantity, location_dest_id, context=None):
++        new_move = []     
++        if quantity <= 0:
+             raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
+         
 -        move = self.browse(cr, uid, ids, context=context)
 -        move_qty = move.product_qty
 -        
 -        if qty > move_qty:
 -            qty = move_qty
 -        rest = 0
 -    
 -        if qty <= move_qty:
 -            rest= move_qty - qty
 -            vals = {
 -                'product_qty' : qty, 
 -                'product_uos_qty': qty, 
 -                'location_id': location_id
 -                }
 -            track = move.product_id.track_production
 -            self.write(cr, uid, move.id, vals)
 -            if track:
 -                data = [{'tracking_num': '', 'quantity': 1}]
 -                newmoves = self._track_lines(cr, uid, ids, data*int(math.floor(qty)), context=None)
 -            self.action_done(cr, uid, [move.id])
 -
 -        if rest:
 -            defaults = {'product_qty': rest, 
 -                                'product_uos_qty': rest, 
 -                                'state': move.state}
 -            new_move = self.copy(cr, uid, move.id, default=defaults)
 -        return new_move
++        for move in self.browse(cr, uid, ids, context=context):
++            location = move.location_dest_id.id
++            move_qty = move.product_qty
++            quantity_rest = move.product_qty
 -    def scrap_moves(self, cr, uid, ids, product_qty, location_id, context=None):
 -        new_move = None
 -        qty = product_qty
 -        if qty <= 0:
 -            raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
++            quantity_rest -= quantity
++            uos_qty = quantity / move_qty * move.product_uos_qty
++            uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
++            if quantity_rest <= 0:
++                quantity_rest = quantity
++                break
+         
 -        move = self.browse(cr, uid, ids, context=context)
 -        location = move.location_dest_id.id
 -        move_qty = move.product_qty
 -
 -        if qty > move_qty:
 -            qty = move_qty
 -        rest = 0
 -    
 -        if qty <= move_qty: 
 -            rest= move_qty - qty
 -            vals = {
 -                        'product_qty': qty, 
 -                        'state': move.state, 
 -                        'location_dest_id': location_id
 -                        }
 -            self.write(cr, uid, ids, vals)
 -    
 -        if rest:
 -            defaults = {'product_qty': rest, 
 -                        'product_uos_qty': rest, 
 -                        'location_dest_id': location, 
 -                        'state': move.state}
 -            new_move = self.copy(cr, uid, move.id, default=defaults)
++            default_val = {
++                'product_qty': quantity, 
++                'product_uos_qty': uos_qty,
++                'location_dest_id' : location_dest_id,
++                'state': move.state
++            }
++            current_move = self.copy(cr, uid, move.id, default_val)
++            new_move.append(current_move)
++            update_val = {}
++            if quantity_rest > 0:                        
++                update_val['product_qty'] = quantity_rest
++                update_val['product_uos_qty'] = uos_qty_rest                          
++                self.write(cr, uid, [move.id], update_val)
+         return new_move
  
  stock_move()
  
                                <page string="Production Lot">
                                    <field name="name" select="1"/>
                                    <field name="ref" select="2"/>
++                            <field name="prefix" select="1"/>
                                    <field name="product_id" select="1"/>
                                    <field name="stock_available"/>
                                    <field name="date" select="2"/>
              <field name="auto_refresh" eval="1"/>
              <field name="target">new</field>
              <field name="context">{'action_id': active_id}</field>
--        </record>
--
--
--      <record id="view_stock_split_production_lots" model="ir.ui.view">
--            <field name="name">Split Production Lots</field>
--            <field name="model">stock.split.production.lots</field>
--            <field name="type">form</field>
--            <field name="arch" type="xml">
--                <form string="Split Production Lots">
--                      <group col="4" colspan="4">
--                         <field name="name"/>
--                         <field name="qty" attrs="{'readonly':[('action','!=','split')]}"/>
--                         <field name="action" colspan="4"/>
--                    </group>
--                    <newline/>
--                    <button name="split_lines" string="Ok" type="object" icon="gtk-go-forward"/>
--                </form>
--            </field>
--        </record>
--
--        <record id="action_view_stock_split_production_lots" model="ir.actions.act_window">
--            <field name="name">Split Production Lots</field>
--            <field name="type">ir.actions.act_window</field>
--            <field name="res_model">stock.split.production.lots</field>
--            <field name="view_type">form</field>
--            <field name="view_mode">form</field>
--            <field name="target">new</field>
--        </record>
++        </record>     
  
          <record model="ir.ui.view" id="stock_picking_calendar">
              <field name="name">stock.picking.calendar</field>
                      <notebook colspan="4">
                          <page string="General Information">
                              <field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
++                                <tree colors="grey:state in ('cancel');black:state not in ('cancel')" string="Stock Moves">
++                                    <field name="name" string="Move Name"/>
++                                    <field name="product_id"/>
++                                    <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)"/>
++                                    <field name="product_uom" string="UOM"/>
++                                    <field name="picking_id" select="1"/>
++                                    <field name="prodlot_id"/>
++                                    <field name="location_id"/>
++                                    <field name="location_dest_id"/>
++                                    <field name="date_planned"/>
++                                    <field name="state"/> 
++                                    <button
++                                                      name="%(stock.track_line)d"
++                                                      string="Split in production lots"
++                                                      type="action" icon="gtk-justify-fill"
++                                                      states="done,cancel" />
++                                              <button
++                                                      name="%(stock.move_scrap)d"
++                                                      string="D" type="action"
++                                                      icon="gtk-convert"
++                                                      states="done,cancel" />
++                                </tree>
                                  <form string="Stock Moves">
                                        <notebook colspan="4">
                                                <page string="General Information">
                                                    <newline/>
                                                    <label/>
                                                    <button name="%(track_line)d" string="Split in production lots" type="action" icon="gtk-justify-fill"/>
++                                            <button name="%(move_scrap)d" string="Scrap Move Line" type="action" icon="gtk-justify-fill"/>
                                                    <separator colspan="4" string="Move State"/>
                                                    <field name="state" select="1"/>
                                                    <group>
                          <notebook colspan="4">
                          <page string="General Information">
                              <field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
++                                <tree colors="grey:state in ('cancel');black:state not in ('cancel')" string="Stock Moves">
++                                    <field name="name" string="Move Name"/>
++                                    <field name="product_id"/>
++                                    <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)"/>
++                                    <field name="product_uom" string="UOM"/>
++                                    <field name="picking_id" select="1"/>
++                                    <field name="prodlot_id"/>
++                                    <field name="location_id"/>
++                                    <field name="location_dest_id"/>
++                                    <field name="date_planned"/>
++                                    <field name="state"/> 
++                                    <button
++                                                      name="%(stock.track_line)d"
++                                                      string="Split in production lots"
++                                                      type="action" icon="gtk-justify-fill"
++                                                      states="done,cancel" />
++                                              <button
++                                                      name="%(stock.move_scrap)d"
++                                                      string="D" type="action"
++                                                      icon="gtk-convert"
++                                                      states="done,cancel" />
++                                </tree>
                                  <form string="Stock Moves">
                                        <notebook colspan="4">
                                                <page string="General Information">
                      <notebook colspan="4">
                          <page string="General Information">
                              <field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
++                                <tree colors="grey:state in ('cancel');black:state not in ('cancel')" string="Stock Moves">
++                                    <field name="name" string="Move Name"/>
++                                    <field name="product_id"/>
++                                    <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)"/>
++                                    <field name="product_uom" string="UOM"/>
++                                    <field name="picking_id" select="1"/>
++                                    <field name="prodlot_id"/>
++                                    <field name="location_id"/>
++                                    <field name="location_dest_id"/>
++                                    <field name="date_planned"/>
++                                    <field name="state"/> 
++                                    <button
++                                                      name="%(stock.track_line)d"
++                                                      string="Split in production lots"
++                                                      type="action" icon="gtk-justify-fill"
++                                                      states="done,cancel" />
++                                              <button
++                                                      name="%(stock.move_scrap)d"
++                                                      string="D" type="action"
++                                                      icon="gtk-convert"
++                                                      states="done,cancel" />
++                                </tree>
                                  <form string="Stock Moves">
                                        <notebook colspan="4">
                                                                                <page string="General Information">
                      <notebook colspan="4">
                          <page string="General Information">
                              <field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_in_id': address_id}">
--                                <tree string="Stock Moves">
++                                <tree colors="grey:state in ('cancel');black:state not in ('cancel')" string="Stock Moves">
                                      <field name="product_id"/>
                                      <field name="product_qty"/>
                                      <field name="product_uom"/>
                                      <field name="location_dest_id"/>
                                      <field name="prodlot_id"/>
                                      <field name="state"/>
--                                </tree>
++                                    <button
++                                                      name="%(stock.track_line)d"
++                                                      string="Split in production lots"
++                                                      type="action" icon="gtk-justify-fill"
++                                                      states="done,cancel" />
++                                              <button
++                                                      name="%(stock.move_scrap)d"
++                                                      string="D" type="action"
++                                                      icon="gtk-convert"
++                                                      states="done,cancel" />
++                                </tree>                                
                                  <form string="Stock Moves">
                                        <notebook colspan="4">
                                                <page string="General Information">
                      <field name="location_id"/>
                      <field name="location_dest_id"/>
                      <field name="date_planned"/>
--                    <field name="state"/>
++                    <field name="state"/>                    
                  </tree>
              </field>
          </record>
index 0000000,204a62d..c813b85
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,149 +1,206 @@@
+ # -*- 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 osv import fields, osv
+ from tools.translate import _
+ class stock_move_track(osv.osv_memory):
+     _name = "stock.move.track"
+     _description = "Track moves"
+     
+     _columns = {
+         'tracking_prefix': fields.char('Tracking prefix', size=64), 
+         'quantity': fields.float("Quantity per lot")
+               }
+     _defaults = {
+         'quantity': lambda *x: 1
+                  }
+     
+     def track_lines(self, cr, uid, ids, context={}):
+         datas = self.read(cr, uid, ids)[0]
+         move_obj = self.pool.get('stock.move')
+         move_obj._track_lines(cr, uid, context['active_id'], datas, context=context)
+         return {}
+ stock_move_track()
+ class stock_move_consume(osv.osv_memory):
+     _name = "stock.move.consume"
+     _description = "Consume Products"
+     
+     _columns = {
+         'product_id': fields.many2one('product.product', 'Product', required=True, select=True), 
+         'product_qty': fields.float('Quantity', required=True), 
+         'product_uom': fields.many2one('product.uom', 'Product UOM', required=True), 
 -        'location_id': fields.many2one('stock.location', 'Source Location', required=True)
++        'location_id': fields.many2one('stock.location', 'Location', required=True)
+               }
+     def _get_product_id(self, cr, uid, context):
+         move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
+         return move.product_id.id
+     
+     def _get_product_qty(self, cr, uid, context):
+         move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
+         return move.product_qty
+     
+     def _get_product_uom(self, cr, uid, context):
+         move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
+         return move.product_uom.id
+     
+     def _get_location_id(self, cr, uid, context):
+         move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
+         return move.location_id.id
+     
+     _defaults = {
+                  'product_id': _get_product_id, 
+                  'product_qty': _get_product_qty, 
+                  'product_uom': _get_product_uom, 
+                  'location_id': _get_location_id
+                  }
+     def do_move_consume(self, cr, uid, ids, context={}):
 -        datas = self.read(cr, uid, ids)[0]
+         move_obj = self.pool.get('stock.move')
 -        move_obj.consume_moves(cr, uid, context['active_id'], 
 -                         datas['product_qty'], datas['location_id'], 
 -                         context=context)
++        move_ids = context['active_ids']
++        for data in self.read(cr, uid, ids):            
++            move_obj.consume_moves(cr, uid, move_ids, 
++                             data['product_qty'], data['location_id'], 
++                             context=context)
+         return {}
+ stock_move_consume()
+ class stock_move_scrap(osv.osv_memory):
+     _name = "stock.move.scrap"
+     _description = "Scrap Products"
+     _inherit = "stock.move.consume"
+     
+     _defaults = {
+                  'location_id': lambda *x: False
 -                 }
++    }
+     def move_scrap(self, cr, uid, ids, context={}):
 -        datas = self.read(cr, uid, ids)[0]
 -        move_obj = self.pool.get('stock.move')
 -        move_obj.scrap_moves(cr, uid, context['active_id'], 
 -                         datas['product_qty'], datas['location_id'], 
 -                         context=context)
++        move_obj = self.pool.get('stock.move')        
++        move_ids = context['active_ids']
++        for data in self.read(cr, uid, ids):
++            move_obj.scrap_moves(cr, uid, move_ids, 
++                             data['product_qty'], data['location_id'], 
++                             context=context)
+         return {}
+ stock_move_scrap()
 -class spilt_in_lot(osv.osv_memory):
 -    _name = "spilt.in.lot"
 -    _description = "Split in lots"
++class spilt_in_production_lot(osv.osv_memory):
++    _name = "stock.move.spilt"
++    _description = "Split in Production lots"
+     
+     _columns = {
+         'product_id': fields.many2one('product.product', 'Product', required=True, select=True),
 -        'line_ids': fields.one2many('track.lines', 'lot_id', 'Lots Number')
 -              }
++        'line_ids': fields.one2many('stock.move.spilt.lines', 'lot_id', 'Lots Number')
++     }
+     
+     def _get_product_id(self, cr, uid, context):
+         move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
+         return move.product_id.id
+     
+     _defaults = {
+                  'product_id': _get_product_id, 
+                  }
 -    
++
+     def split_lot(self, cr, uid, ids, context=None):
 -        datas = self.read(cr, uid, ids)[0]
 -        lines = []
 -        for line in self.pool.get('track.lines').browse(cr, uid, datas.get('line_ids', [])):
 -            lines.append({'tracking_num': line.name, 'quantity': line.quantity})
 -        move_obj = self.pool.get('stock.move')
 -        move_obj._track_lines(cr, uid, context['active_id'], lines, context=context)
++        self.split(cr, uid, ids, context.get('active_ids'), context=context)
+         return {}
 -spilt_in_lot()
 -
 -class track_lines(osv.osv_memory):
 -    _name = "track.lines"
 -    _description = "Track lines"
++    def split(self, cr, uid, ids, move_ids, context=None):
++        prodlot_obj = self.pool.get('stock.production.lot')
++        ir_sequence_obj = self.pool.get('ir.sequence')
++        move_obj = self.pool.get('stock.move')
++        new_move = []        
++        for data in self.browse(cr, uid, ids):
++            for move in move_obj.browse(cr, uid, move_ids):
++                move_qty = move.product_qty
++                quantity_rest = move.product_qty
++                uos_qty_rest = move.product_uos_qty
++                new_move = []                            
++                for line in data.line_ids:
++                    quantity = line.quantity
++                    
++
++                    if quantity <= 0 or move_qty == 0:
++                        continue
++                    quantity_rest -= quantity
++                    uos_qty = quantity / move_qty * move.product_uos_qty
++                    uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
++                    if quantity_rest <= 0:
++                        quantity_rest = quantity
++                        break
++                    default_val = {
++                        'product_qty': quantity, 
++                        'product_uos_qty': uos_qty, 
++                        'state': move.state
++                    }
++                    current_move = move_obj.copy(cr, uid, move.id, default_val)
++                    new_move.append(current_move)
++                    prodlot_id = False
++                    if line.use_exist and line.name:
++                        prodlot_id = prodlot_obj.search(cr, uid, [('prefix','=',line.name),('product_id','=',data.product_id.id)])
++                        if prodlot_id:
++                            prodlot_id = prodlot_id[0]                    
++                    if not prodlot_id:
++                        sequence = ir_sequence_obj.get(cr, uid, 'stock.lot.serial')
++                        prodlot_id = prodlot_obj.create(cr, uid, {'name': sequence, 'prefix' : line.name}, 
++                                                 {'product_id': move.product_id.id})                    
++                    move_obj.write(cr, uid, [current_move], {'prodlot_id': prodlot_id})
++                    prodlot = prodlot_obj.browse(cr, uid, prodlot_id) 
++                    ref = '%d' % (current_move)
++                    if prodlot.ref:
++                        ref = '%s, %s' % (prodlot.ref, ref) 
++                    prodlot_obj.write(cr, uid, [prodlot_id], {'ref': ref})
++                    
++                    update_val = {}
++                    if quantity_rest > 0:                        
++                        update_val['product_qty'] = quantity_rest
++                        update_val['product_uos_qty'] = uos_qty_rest                          
++                        move_obj.write(cr, uid, [move.id], update_val)
++
++                    
++        return new_move
++spilt_in_production_lot()
++
++class stock_move_spilt_lines(osv.osv_memory):
++    _name = "stock.move.spilt.lines"
++    _description = "Split lines"
+     
+     _columns = {
+         'name': fields.char('Tracking serial', size=64), 
+         'quantity': fields.integer('Quantity'), 
 -        'lot_id': fields.many2one('spilt.in.lot', 'Lot')
 -              }
++        'use_exist' : fields.boolean('Use Exist'),
++        'lot_id': fields.many2one('stock.move.spilt', 'Lot'),
++        'action': fields.selection([('split','Split'),('keepinone','Keep in one lot')],'Action'),
++    }
++    _defaults = {
++        'quantity': lambda *x: 1,
++        'action' : lambda *x: 'split', 
++    }
 -track_lines()
++stock_move_spilt_lines()
index 0000000,0000000..72200be
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,141 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<openerp>
++    <data>
++    
++          <record id="view_stock_move_track_wizard" model="ir.ui.view">
++                  <field name="name">Tracking a move</field>
++                  <field name="model">stock.move.track</field>
++                  <field name="type">form</field>
++                  <field name="arch" type="xml">
++                      <form string="Tracking a move">
++                              <field name="tracking_prefix" colspan="4"/>
++                              <field name="quantity" colspan="4"/>
++                              <newline/>
++                              <separator string="" colspan="4" />
++                              <button icon='gtk-cancel' special="cancel"
++                                      string="Cancel" />
++                              <button name="track_lines" string="Ok"
++                                      type="object" icon="gtk-ok" />
++                      </form>
++                  </field>
++              </record>
++      
++              <record id="track_line_old" model="ir.actions.act_window">
++                  <field name="name">Tracking a move</field>
++                  <field name="type">ir.actions.act_window</field>
++                  <field name="res_model">stock.move.track</field>
++                  <field name="view_type">form</field>
++                  <field name="view_mode">form</field>
++                  <field name="target">new</field>
++              </record>
++              
++        
++        <!--  Consume, scrap move -->
++        
++              <record id="view_stock_move_consume_wizard" model="ir.ui.view">
++            <field name="name">Consume Move</field>
++            <field name="model">stock.move.consume</field>
++            <field name="type">form</field>
++            <field name="arch" type="xml">
++                <form string="Consume Move">
++                      <separator string="Consume Products" colspan="4"/>
++                                  <field name="product_id" colspan="4" readonly="1"/>
++                                  <field name="location_id" colspan="4"/>
++                                  <field name="product_qty" colspan="2"/>
++                                  <field name="product_uom" nolabel="1" readonly="1"/>
++                      <newline/>
++                      <separator string="" colspan="4" />
++                      <label string="" colspan="2" />
++                      <group col="2" colspan="1">
++                              <button icon='gtk-cancel' special="cancel"
++                                      string="Cancel" />
++                              <button name="do_move_consume" string="Ok"
++                                      colspan="1" type="object" icon="gtk-ok" />
++                      </group>
++                </form>
++            </field>
++        </record>
++
++        <record id="move_consume" model="ir.actions.act_window">
++            <field name="name">Consume Move</field>
++            <field name="type">ir.actions.act_window</field>
++            <field name="res_model">stock.move.consume</field>
++            <field name="view_type">form</field>
++            <field name="view_mode">form</field>
++            <field name="target">new</field>
++        </record>
++        
++       <record id="view_stock_move_scrap_wizard" model="ir.ui.view">
++            <field name="name">Scrap Move</field>
++            <field name="model">stock.move.scrap</field>
++            <field name="type">form</field>
++            <field name="arch" type="xml">
++                <form string="Scrap Move">
++                      <separator string="Scrap Products" colspan="4"/>
++                                  <field name="product_id" colspan="4" readonly="1"/>
++                                  <field name="location_id" colspan="4" string="Dest. Location" domain="[('usage','&lt;&gt;','view')]"/>
++                                  <field name="product_qty" colspan="2"/>
++                                  <field name="product_uom" nolabel="1" readonly="1"/>
++                      <newline/>
++                      <separator string="" colspan="4" />
++                      <label string="" colspan="2" />
++                      <group col="2" colspan="1">
++                              <button icon='gtk-cancel' special="cancel"
++                                      string="Cancel" />
++                              <button name="move_scrap" string="Ok"
++                                      colspan="1" type="object" icon="gtk-ok" />
++                      </group>
++                </form>
++            </field>
++        </record>
++
++        <record id="move_scrap" model="ir.actions.act_window">
++            <field name="name">Scrap Move</field>
++            <field name="type">ir.actions.act_window</field>
++            <field name="res_model">stock.move.scrap</field>
++            <field name="view_type">form</field>
++            <field name="view_mode">form</field>
++            <field name="target">new</field>
++        </record>
++        
++        <record id="view_split_in_lots" model="ir.ui.view">
++                  <field name="name">Split in lots</field>
++                  <field name="model">stock.move.spilt</field>
++                  <field name="type">form</field>
++                  <field name="arch" type="xml">
++                      <form string="Split in lots">
++                              <field name="product_id" colspan="4" readonly="1"/>
++                              <newline/>
++                              <field name="line_ids" colspan="4" nolabel="1">
++                                      <tree string="Lots Number" editable="top">
++                                              <field name="name" string="Lots"/>
++                                              <field name="quantity" />
++                                <field name="use_exist" />
++                                      </tree>
++                                      <form string="Lots Number">
++                                              <field name="name" string="Lots"/>
++                                              <field name="quantity" />
++                                <field name="use_exist" />
++                                      </form>
++                              </field>
++                              <separator string="" colspan="4" />
++                              <label string="" colspan="2" />
++                              <button icon='gtk-cancel' special="cancel"
++                                      string="Cancel" />
++                              <button name="split_lot" string="Ok"
++                                      type="object" icon="gtk-ok" />
++                      </form>
++                  </field>
++              </record>
++      
++              <record id="track_line" model="ir.actions.act_window">
++                  <field name="name">Split in lots</field>
++                  <field name="type">ir.actions.act_window</field>
++                  <field name="res_model">stock.move.spilt</field>
++                  <field name="view_type">form</field>
++                  <field name="view_mode">form</field>
++                  <field name="target">new</field>
++              </record>          
++
++      </data>
++</openerp>