[IMP] mrp: add new wizard for produce product and change workflow of production order
authorHarry (Open ERP) <hmo@tinyerp.com>
Wed, 24 Feb 2010 08:17:06 +0000 (13:47 +0530)
committerHarry (Open ERP) <hmo@tinyerp.com>
Wed, 24 Feb 2010 08:17:06 +0000 (13:47 +0530)
bzr revid: hmo@tinyerp.com-20100224081706-x156eauvbp3btnwp

addons/mrp/__init__.py
addons/mrp/__terp__.py
addons/mrp/mrp.py
addons/mrp/mrp_view.xml
addons/mrp/mrp_wizard.py [new file with mode: 0644]
addons/mrp/mrp_wizard_view.xml [new file with mode: 0644]
addons/mrp/mrp_workflow.xml
addons/stock/stock.py

index 90ca012..b219d93 100644 (file)
@@ -21,6 +21,7 @@
 
 import mrp
 import installer
+import mrp_wizard
 import wizard
 import report
 import company
index 3bf2410..1d5eb98 100644 (file)
@@ -60,6 +60,7 @@
         'security/ir.model.access.csv',
         'mrp_workflow.xml',
         'mrp_data.xml',
+        'mrp_wizard_view.xml',
         'mrp_view.xml',
         'mrp_wizard.xml',
         'mrp_report.xml',
index dbcf6c9..9897e3e 100644 (file)
@@ -581,28 +581,78 @@ class mrp_production(osv.osv):
                         {'location_id':production.location_dest_id.id})
         return True
 
-    #TODO Review materials in function in_prod and prod_end.
     def action_production_end(self, cr, uid, ids):
-        move_ids = []
         for production in self.browse(cr, uid, ids):
-            for res in production.move_lines:
-                for move in production.move_created_ids:
-                    #XXX must use the orm
-                    cr.execute('INSERT INTO stock_move_history_ids \
-                            (parent_id, child_id) VALUES (%s,%s)',
-                            (res.id, move.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)
-            if not production.date_finnished:
-                self.write(cr, uid, [production.id],
-                        {'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')})
-            self.pool.get('stock.move').check_assign(cr, uid, new_moves)
-            self.pool.get('stock.move').action_done(cr, uid, new_moves)
             self._costs_generate(cr, uid, production)
-        self.pool.get('stock.move').action_done(cr, uid, move_ids)
-        self.write(cr,  uid, ids, {'state': 'done'})
+        return self.write(cr,  uid, ids, {'state': 'done', 'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')})
+
+    def test_production_done(self, cr, uid, ids):
+        res = True
+        for production in self.browse(cr, uid, ids):            
+            if production.move_lines:                
+               res = False
+
+            if production.move_created_ids:                
+               res = False        
+        return res
+
+    def do_produce(self, cr, uid, production_id, production_qty, production_mode, context=None):
+        stock_mov_obj = self.pool.get('stock.move')
+        production = self.browse(cr, uid, production_id)
+        
+        raw_product_todo = []
+        final_product_todo = []        
+        
+        if production_mode in ['consume','consume_produce']:
+            consumed_products = {}
+            produced_qty = 0
+            for consumed_product in production.move_lines2:
+                if not consumed_products.get(consumed_product.product_id.id, False):
+                    consumed_products[consumed_product.product_id.id] = 0
+                consumed_products[consumed_product.product_id.id] += consumed_product.product_qty
+            
+            for produced_product in production.move_created_ids2:
+                produced_qty += produced_product.product_qty
+
+            for raw_product in production.move_lines:                
+                consumed_qty = consumed_products.get(raw_product.product_id.id, 0)                
+                consumed_qty -= produced_qty                            
+                rest_qty = production_qty - consumed_qty 
+                if rest_qty > production.product_qty:
+                   rest_qty = production.product_qty            
+                if rest_qty > 0:
+                    stock_mov_obj.consume_moves(cr, uid, [raw_product.id], rest_qty, production.location_src_id.id, context=context)
+
+        if production_mode == 'consume_produce':
+            vals = {'state':'confirmed'}
+            final_product_todo = [x.id for x in production.move_created_ids]
+            stock_mov_obj.write(cr, uid, final_product_todo, vals)
+            produced_products = {}
+            for produced_product in production.move_created_ids2:
+                if not produced_products.get(produced_product.product_id.id, False):
+                    produced_products[produced_product.product_id.id] = 0
+                produced_products[produced_product.product_id.id] += produced_product.product_qty
+
+            for produce_product in production.move_created_ids:                
+                produced_qty = produced_products.get(produce_product.product_id.id, 0)                            
+                rest_qty = production.product_qty - produced_qty
+                if rest_qty <= production_qty:
+                   production_qty = rest_qty 
+                if rest_qty > 0 :
+                    stock_mov_obj.consume_moves(cr, uid, [produce_product.id], production_qty, production.location_dest_id.id, context=context)            
+        
+        
+        for raw_product in production.move_lines2: 
+            new_parent_ids = []           
+            parent_move_ids = [x.id for x in raw_product.move_history_ids]
+            for final_product in production.move_created_ids2:
+                if final_product.id not in parent_move_ids:
+                    new_parent_ids.append(final_product.id)
+            for new_parent_id in new_parent_ids:
+                stock_mov_obj.write(cr, uid, [raw_product.id], {'move_history_ids':[(4,new_parent_id)]})
+
+        wf_service = netsvc.LocalService("workflow")
+        wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr)
         return True
 
     def _costs_generate(self, cr, uid, production):
@@ -1285,8 +1335,7 @@ class StockMove(osv.osv):
                 state = 'confirmed'
                 if move.state=='assigned':
                     state='assigned'
-                for line in res[0]:
-                    print 'Line :',line
+                for line in res[0]:                    
                     valdef = {
                         'picking_id': move.picking_id.id,
                         'product_id': line['product_id'],
@@ -1337,7 +1386,7 @@ class StockMove(osv.osv):
         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)
+            new_moves = super(StockMove, self).consume_moves(cr, uid, [move.id], product_qty, location_id, 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)]})
index c1c7a00..d47311f 100644 (file)
                         <field name="product_qty"/>
                         <group colspan="2" col="3">
                             <field name="product_uom"/>
-                            <!-- TODO Fix change qty accroding to move_lines and move_lines2 -->
-<!--                            <button type="action" name="%(mrp.wizard_change_production_qty)d" string="Change Qty" states="ready,confirmed,in_production" icon="gtk-ok"/>-->
                         </group>
                         <label string="" colspan="2"/>                          
                         <field name="product_uos_qty" groups="product.group_uos"/>                        
                                 <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="Mark as Start" icon="gtk-execute"/>
-                                <button name="button_produce_done" states="in_production" string="Production" icon="gtk-ok"/>
+                                <button name="button_produce" states="ready" string="Mark as Start" icon="gtk-execute"/>                                
+                                <button name="%(act_mrp_product_produce)d" states="in_production" string="Produce" icon="gtk-ok" type="action"/>
                                 <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"/>
diff --git a/addons/mrp/mrp_wizard.py b/addons/mrp/mrp_wizard.py
new file mode 100644 (file)
index 0000000..40d9f2e
--- /dev/null
@@ -0,0 +1,59 @@
+# -*- 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 _
+import netsvc
+
+class mrp_product_produce(osv.osv_memory):
+    _name = "mrp.product.produce"
+    _description = "Product Produce"
+    
+    _columns = {
+        'product_qty': fields.float('Quantity', required=True), 
+        'mode': fields.selection([('consume_produce', 'Consume & Produce'), 
+                                  ('consume', 'Consume Only')], 'Mode', required=True)
+    }
+
+    def _get_product_qty(self, cr, uid, context):
+        prod = self.pool.get('mrp.production').browse(cr, uid, 
+                                context['active_id'], context=context)
+        done = 0.0
+        for move in prod.move_created_ids2:
+                done += move.product_qty
+        return (prod.product_qty - done) or prod.product_qty
+    
+    _defaults = {
+                 'product_qty': _get_product_qty, 
+                 'mode': lambda *x: 'consume_produce'
+                 }
+
+    def do_produce(self, cr, uid, ids, context={}):
+        prod_obj = self.pool.get('mrp.production')
+        move_ids = context['active_ids']
+        for data in self.read(cr, uid, ids):
+            for move_id in move_ids:
+                prod_obj.do_produce(cr, uid, move_id, 
+                                    data['product_qty'], data['mode'], context=context)
+        return {}
+
+mrp_product_produce()
+
diff --git a/addons/mrp/mrp_wizard_view.xml b/addons/mrp/mrp_wizard_view.xml
new file mode 100644 (file)
index 0000000..f730c4a
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+    
+        
+        <!--  Produce -->
+        
+               <record id="view_mrp_product_produce_wizard" model="ir.ui.view">
+            <field name="name">MRP Product Produce</field>
+            <field name="model">mrp.product.produce</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Produce">
+                       <separator string="Produce" colspan="4"/>
+                                   <field name="mode" colspan="4"/>
+                                   <field name="product_qty" colspan="2"/>
+                       <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_produce" string="Confirm"
+                                       colspan="1" type="object" icon="gtk-ok" />
+                       </group>
+                </form>
+            </field>
+        </record>
+
+        <record id="act_mrp_product_produce" model="ir.actions.act_window">
+            <field name="name">Produce</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">mrp.product.produce</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>    
+        
+        
+       </data>
+</openerp>     
index c9358a2..8be8f97 100644 (file)
@@ -43,7 +43,7 @@
             <field name="wkf_id" ref="wkf_prod"/>
             <field name="flow_stop">True</field>
             <field name="kind">function</field>
-            <field name="action">action_production_end()</field>
+            <field name="action">action_production_end()</field>            
             <field name="name">done</field>
         </record>
         <record id="prod_act_cancel" model="workflow.activity">
@@ -81,6 +81,7 @@
             <field name="act_from" ref="prod_act_in_production"/>
             <field name="act_to" ref="prod_act_done"/>
             <field name="signal">button_produce_done</field>
+            <field name="condition">test_production_done()</field>
         </record>
         <record id="prod_trans_picking_picking_exception" model="workflow.transition">
             <field name="act_from" ref="prod_act_picking"/>
index 96b57a6..27b6925 100644 (file)
@@ -1488,43 +1488,54 @@ class stock_move(osv.osv):
                 self.write(cr, uid, [current_move], update_val)
         return new_move
 
-    def consume_moves(self, cr, uid, ids, quantity, location_id, context=None):
-        new_move = []
+    def consume_moves(self, cr, uid, ids, quantity, location_id, context=None):        
         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):
+        res = []       
+        for move in self.browse(cr, uid, ids, context=context):            
             move_qty = move.product_qty
             quantity_rest = move.product_qty
 
-            quantity_rest -= quantity
-            uos_qty = quantity / move_qty * move.product_uos_qty
+            quantity_rest -= quantity            
             uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
             if quantity_rest <= 0:
-                quantity_rest = quantity
-                break
+                quantity_rest = 0 
+                uos_qty_rest = 0
+                quantity = move.product_qty
+            uos_qty = quantity / move_qty * move.product_uos_qty
 
-            default_val = {
-                'product_qty': quantity, 
-                'product_uos_qty': uos_qty,
-                'location_id' : location_id,                
-            }
-            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)
+            if quantity_rest > 0:  
+                default_val = {
+                    'product_qty': quantity, 
+                    'product_uos_qty': uos_qty,
+                    'location_id' : location_id,                
+                }
+                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 = [current_move]
 
-            update_val = {}
-            if quantity_rest > 0:                        
+                update_val = {}                                  
                 update_val['product_qty'] = quantity_rest
                 update_val['product_uos_qty'] = uos_qty_rest                          
-                self.write(cr, uid, [move.id], update_val)
+                self.write(cr, uid, [move.id], update_val) 
+
+            else: 
+                quantity_rest = quantity    
+                uos_qty_rest =  uos_qty                      
+                new_move = [move.id] 
             
+            update_val = {}                                  
+            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
+            res += new_move
+        return res
 
     def scrap_moves(self, cr, uid, ids, quantity, location_dest_id, context=None):
         new_move = []