[WIP] Move back packaging from sale to sale_stock, add module sale_stock_location...
authorJosse Colpaert <jco@openerp.com>
Tue, 16 Jul 2013 15:33:36 +0000 (17:33 +0200)
committerJosse Colpaert <jco@openerp.com>
Tue, 16 Jul 2013 15:33:36 +0000 (17:33 +0200)
bzr revid: jco@openerp.com-20130716153336-irauxby6fd7gs0w2

addons/sale/sale.py
addons/sale_stock/sale_stock.py
addons/sale_stock_location/__init__.py [new file with mode: 0644]
addons/sale_stock_location/__openerp__.py [new file with mode: 0644]
addons/sale_stock_location/sale_stock_location.py [new file with mode: 0644]
addons/sale_stock_location/sale_stock_location_view.xml [new file with mode: 0644]
addons/stock/procurement.py
addons/stock/stock.py
addons/stock_location/stock_location.py
addons/stock_location/stock_location_view.xml

index 1e2ae10..4b99362 100644 (file)
@@ -736,14 +736,6 @@ class sale_order_line(osv.osv):
                                     WHERE rel.invoice_id = ANY(%s)""", (list(ids),))
         return [i[0] for i in cr.fetchall()]
 
-    def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
-        res = {}
-        for line in self.browse(cr, uid, ids, context=context):
-            try:
-                res[line.id] = int((line.product_uom_qty+line.product_packaging.qty-0.0001) / line.product_packaging.qty)
-            except:
-                res[line.id] = 1
-        return res
 
     _name = 'sale.order.line'
     _description = 'Sales Order Line'
@@ -781,8 +773,7 @@ class sale_order_line(osv.osv):
         'delay': fields.float('Delivery Lead Time', required=True, help="Number of days between the order confirmation and the shipping of the products to the customer", readonly=True, states={'draft': [('readonly', False)]}),
         'procurement_id': fields.many2one('procurement.order', 'Procurement'),
         #'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
-        'product_packaging': fields.many2one('product.packaging', 'Packaging'),
-        'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
+
         
     }
     _order = 'order_id desc, sequence, id'
@@ -796,7 +787,6 @@ class sale_order_line(osv.osv):
         'type': 'make_to_stock',
         'price_unit': 0.0,
         'delay': 0.0,
-        'product_packaging': False,
     }
 
     def _get_line_qty(self, cr, uid, line, context=None):
@@ -867,106 +857,6 @@ class sale_order_line(osv.osv):
 
 
     
-    def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
-                                   partner_id=False, packaging=False, flag=False, context=None):
-        if not product:
-            return {'value': {'product_packaging': False}}
-        product_obj = self.pool.get('product.product')
-        product_uom_obj = self.pool.get('product.uom')
-        pack_obj = self.pool.get('product.packaging')
-        warning = {}
-        result = {}
-        warning_msgs = ''
-        if flag:
-            res = self.product_id_change(cr, uid, ids, pricelist=pricelist,
-                    product=product, qty=qty, uom=uom, partner_id=partner_id,
-                    packaging=packaging, flag=False, context=context)
-            warning_msgs = res.get('warning') and res['warning']['message']
-
-        products = product_obj.browse(cr, uid, product, context=context)
-        if not products.packaging:
-            packaging = result['product_packaging'] = False
-        elif not packaging and products.packaging and not flag:
-            packaging = products.packaging[0].id
-            result['product_packaging'] = packaging
-
-        if packaging:
-            default_uom = products.uom_id and products.uom_id.id
-            pack = pack_obj.browse(cr, uid, packaging, context=context)
-            q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
-#            qty = qty - qty % q + q
-            if qty and (q and not (qty % q) == 0):
-                ean = pack.ean or _('(n/a)')
-                qty_pack = pack.qty
-                type_ul = pack.ul
-                if not warning_msgs:
-                    warn_msg = _("You selected a quantity of %d Units.\n"
-                                "But it's not compatible with the selected packaging.\n"
-                                "Here is a proposition of quantities according to the packaging:\n"
-                                "EAN: %s Quantity: %s Type of ul: %s") % \
-                                    (qty, ean, qty_pack, type_ul.name)
-                    warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
-                warning = {
-                       'title': _('Configuration Error!'),
-                       'message': warning_msgs
-                }
-            result['product_uom_qty'] = qty
-
-        return {'value': result, 'warning': warning}
-
-    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
-            uom=False, qty_uos=0, uos=False, name='', partner_id=False,
-            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
-        context = context or {}
-        product_uom_obj = self.pool.get('product.uom')
-        partner_obj = self.pool.get('res.partner')
-        product_obj = self.pool.get('product.product')
-        warning = {}
-        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
-            uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
-            lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
-
-        if not product:
-            res['value'].update({'product_packaging': False})
-            return res
-
-        #update of result obtained in super function
-        product_obj = product_obj.browse(cr, uid, product, context=context)
-        res['value']['delay'] = (product_obj.sale_delay or 0.0)
-        #res['value']['type'] = product_obj.procure_method
-
-        #check if product is available, and if not: raise an error
-        uom2 = False
-        if uom:
-            uom2 = product_uom_obj.browse(cr, uid, uom)
-            if product_obj.uom_id.category_id.id != uom2.category_id.id:
-                uom = False
-        if not uom2:
-            uom2 = product_obj.uom_id
-
-        # Calling product_packaging_change function after updating UoM
-        res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
-        res['value'].update(res_packing.get('value', {}))
-        warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
-        compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
-        if (product_obj.type=='product') and int(compare_qty) == -1:
-          #and (product_obj.procure_method=='make_to_stock'): --> need to find alternative for procure_method
-            warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
-                    (qty, uom2 and uom2.name or product_obj.uom_id.name,
-                     max(0,product_obj.virtual_available), product_obj.uom_id.name,
-                     max(0,product_obj.qty_available), product_obj.uom_id.name)
-            warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
-
-        #update of warning messages
-        if warning_msgs:
-            warning = {
-                       'title': _('Configuration Error!'),
-                       'message' : warning_msgs
-                    }
-        res.update({'warning': warning})
-        return res
-
-
 
 
 
index 6bb174c..0abc1fc 100644 (file)
@@ -293,14 +293,30 @@ class stock_move(osv.osv):
 
 
 class sale_order_line(osv.osv):
-
-
-
     _inherit = 'sale.order.line'
+    
+    
+    def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
+        res = {}
+        for line in self.browse(cr, uid, ids, context=context):
+            try:
+                res[line.id] = int((line.product_uom_qty+line.product_packaging.qty-0.0001) / line.product_packaging.qty)
+            except:
+                res[line.id] = 1
+        return res
+
+    
     _columns = { 
         'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
+        'product_packaging': fields.many2one('product.packaging', 'Packaging'),
+        'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
     }
 
+    _defaults = {
+        'product_packaging': False,
+    }
+
+
     def button_cancel(self, cr, uid, ids, context=None):
         res = super(sale_order_line, self).button_cancel(cr, uid, ids, context=context)
         for line in self.browse(cr, uid, ids, context=context):
@@ -316,6 +332,108 @@ class sale_order_line(osv.osv):
             default = {}
         default.update({'move_ids': []})
         return super(sale_order_line, self).copy_data(cr, uid, id, default, context=context)
+    
+    
+    def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
+                                   partner_id=False, packaging=False, flag=False, context=None):
+        if not product:
+            return {'value': {'product_packaging': False}}
+        product_obj = self.pool.get('product.product')
+        product_uom_obj = self.pool.get('product.uom')
+        pack_obj = self.pool.get('product.packaging')
+        warning = {}
+        result = {}
+        warning_msgs = ''
+        if flag:
+            res = self.product_id_change(cr, uid, ids, pricelist=pricelist,
+                    product=product, qty=qty, uom=uom, partner_id=partner_id,
+                    packaging=packaging, flag=False, context=context)
+            warning_msgs = res.get('warning') and res['warning']['message']
+
+        products = product_obj.browse(cr, uid, product, context=context)
+        if not products.packaging:
+            packaging = result['product_packaging'] = False
+        elif not packaging and products.packaging and not flag:
+            packaging = products.packaging[0].id
+            result['product_packaging'] = packaging
+
+        if packaging:
+            default_uom = products.uom_id and products.uom_id.id
+            pack = pack_obj.browse(cr, uid, packaging, context=context)
+            q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
+#            qty = qty - qty % q + q
+            if qty and (q and not (qty % q) == 0):
+                ean = pack.ean or _('(n/a)')
+                qty_pack = pack.qty
+                type_ul = pack.ul
+                if not warning_msgs:
+                    warn_msg = _("You selected a quantity of %d Units.\n"
+                                "But it's not compatible with the selected packaging.\n"
+                                "Here is a proposition of quantities according to the packaging:\n"
+                                "EAN: %s Quantity: %s Type of ul: %s") % \
+                                    (qty, ean, qty_pack, type_ul.name)
+                    warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
+                warning = {
+                       'title': _('Configuration Error!'),
+                       'message': warning_msgs
+                }
+            result['product_uom_qty'] = qty
+
+        return {'value': result, 'warning': warning}
+
+
+    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
+            uom=False, qty_uos=0, uos=False, name='', partner_id=False,
+            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
+        context = context or {}
+        product_uom_obj = self.pool.get('product.uom')
+        partner_obj = self.pool.get('res.partner')
+        product_obj = self.pool.get('product.product')
+        warning = {}
+        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
+            uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
+            lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
+
+        if not product:
+            res['value'].update({'product_packaging': False})
+            return res
+
+        #update of result obtained in super function
+        product_obj = product_obj.browse(cr, uid, product, context=context)
+        res['value']['delay'] = (product_obj.sale_delay or 0.0)
+        #res['value']['type'] = product_obj.procure_method
+
+        #check if product is available, and if not: raise an error
+        uom2 = False
+        if uom:
+            uom2 = product_uom_obj.browse(cr, uid, uom)
+            if product_obj.uom_id.category_id.id != uom2.category_id.id:
+                uom = False
+        if not uom2:
+            uom2 = product_obj.uom_id
+
+        # Calling product_packaging_change function after updating UoM
+        res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
+        res['value'].update(res_packing.get('value', {}))
+        warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
+        compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
+        if (product_obj.type=='product') and int(compare_qty) == -1:
+          #and (product_obj.procure_method=='make_to_stock'): --> need to find alternative for procure_method
+            warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
+                    (qty, uom2 and uom2.name or product_obj.uom_id.name,
+                     max(0,product_obj.virtual_available), product_obj.uom_id.name,
+                     max(0,product_obj.qty_available), product_obj.uom_id.name)
+            warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
+
+        #update of warning messages
+        if warning_msgs:
+            warning = {
+                       'title': _('Configuration Error!'),
+                       'message' : warning_msgs
+                    }
+        res.update({'warning': warning})
+        return res
+
 
 
 class sale_advance_payment_inv(osv.osv_memory):
diff --git a/addons/sale_stock_location/__init__.py b/addons/sale_stock_location/__init__.py
new file mode 100644 (file)
index 0000000..9f83e59
--- /dev/null
@@ -0,0 +1,24 @@
+# -*- 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/>.
+#
+##############################################################################
+
+import sale_stock_location
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/sale_stock_location/__openerp__.py b/addons/sale_stock_location/__openerp__.py
new file mode 100644 (file)
index 0000000..daa12d9
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- 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/>.
+#
+##############################################################################
+
+{
+    'name': 'Sales and Warehouse Management',
+    'version': '1.0',
+    'category': 'Hidden',
+    'summary': 'Quotation, Sale Orders, Delivery & Invoicing Control',
+    'description': """
+Manage sales quotations and stock_location
+==========================================
+
+This adds a route on the sales order and sales order line (mini module)
+
+""",
+    'author': 'OpenERP SA',
+    'website': 'http://www.openerp.com',
+    'images': [],
+    'depends': ['sale', 'stock_location'],
+    'init_xml': [],
+    'update_xml': ['sale_stock_location_view.xml'],
+    'demo_xml': [],
+    'test': [],
+    'installable': True,
+    'auto_install': True,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/sale_stock_location/sale_stock_location.py b/addons/sale_stock_location/sale_stock_location.py
new file mode 100644 (file)
index 0000000..343de1c
--- /dev/null
@@ -0,0 +1,56 @@
+# -*- 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 datetime import datetime, timedelta
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, DATETIME_FORMATS_MAP, float_compare
+from dateutil.relativedelta import relativedelta
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+
+class sale_order(osv.osv):
+    _inherit = "sale.order"
+    
+    
+    def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None):
+        '''
+            Add route_ids to the procurement.  As such, people should choose between them. 
+        '''
+        res = super(sale_order, self)._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context)
+        routes = []
+        route_id = order.warehouse_id and order.warehouse_id.route_id and order.warehouse_id.route_id.id or False
+        routes += route_id and [(4, route_id)] or []
+        route_id = line.route_id and line.route_id.id or False
+        routes += route_id and [(4, route_id)] or []
+        res.update({
+                'route_ids': routes
+                })
+
+class sale_order_line(osv.osv):
+    _inherit = 'sale.order.line'
+    _columns = { 
+        'route_id': fields.many2one('stock.location.route', 'Route'),
+    }
+
+
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/sale_stock_location/sale_stock_location_view.xml b/addons/sale_stock_location/sale_stock_location_view.xml
new file mode 100644 (file)
index 0000000..4870657
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<openerp>
+    <data>
+
+        <record id="view_order_form_inherit2" model="ir.ui.view">
+            <field name="name">sale.order.line.form.sale.stock.location</field>
+            <field name="model">sale.order.line</field>
+            <field name="inherit_id" ref="sale.view_order_line_form2"/>
+            <field name="arch" type="xml">
+                <data>
+                   <xpath expr="//field[@name='price_unit']" position="before">
+                       <field name="route_id"/>
+                   </xpath>
+                </data>
+           </field>
+        </record>
+        <record id="view_order_line_tree_inherit" model="ir.ui.view">
+            <field name="name">sale.order.line.tree.sale.stock.location</field>
+            <field name="inherit_id" ref="sale.view_order_line_tree"/>
+            <field name="model">sale.order.line</field>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='price_subtotal']" position="before">
+                    <field name="route_id"/>
+                </xpath>
+            </field>
+        </record>
+        <record id="view_order_form_inherit" model="ir.ui.view">
+            <field name="name">sale.order.form</field>
+            <field name="inherit_id" ref="sale.view_order_form"/>
+            <field name="model">sale.order</field>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='price_unit']" position="before">
+                    <field name="route_id"/>
+                </xpath>
+            </field>
+        </record>
+    </data>
+</openerp>
index b5f785d..41e88d9 100644 (file)
@@ -47,7 +47,7 @@ class procurement_order(osv.osv):
     _columns = {
         'location_id': fields.many2one('stock.location', 'Destination Location'),
         'move_id': fields.many2one('stock.move', 'Move', help="Move created by the procurement"),
-        'move_dest_id': fields.many2one('stock.move', 'Destination Move', help="Move which caused (created) the procurement")
+        'move_dest_id': fields.many2one('stock.move', 'Destination Move', help="Move which caused (created) the procurement"),
     }
 
     def _search_suitable_rule(self, cr, uid, procurement, domain, context=None):
index cff7efd..23bf55d 100644 (file)
@@ -31,7 +31,6 @@ from openerp import netsvc
 from openerp import tools
 from openerp.tools import float_compare, DEFAULT_SERVER_DATETIME_FORMAT
 import openerp.addons.decimal_precision as dp
-from openerp.tools.float_utils import float_compare
 import logging
 _logger = logging.getLogger(__name__)
 
@@ -441,8 +440,6 @@ class stock_picking(osv.osv):
     }
     _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',
         'type': 'internal',
@@ -735,157 +732,155 @@ class stock_picking(osv.osv):
                 #pack existing packs
                 self.pool.get('stock.quant.package').write(cr, uid, op.package_id.id, {'parent_id': op.result_package_id.id}, context=context)
 
+    def do_partial(self, cr, uid, ids, partial_datas, context=None):
+        """ Makes partial picking and moves done.
+        @param partial_datas : Dictionary containing details of partial picking
+                          like partner_id, partner_id, delivery_date,
+                          delivery moves with product_id, product_qty, uom
+        @return: Dictionary of values
+        """
+        if context is None:
+            context = {}
+        else:
+            context = dict(context)
+        res = {}
+        move_obj = self.pool.get('stock.move')
+        product_obj = self.pool.get('product.product')
+        currency_obj = self.pool.get('res.currency')
+        uom_obj = self.pool.get('product.uom')
+        sequence_obj = self.pool.get('ir.sequence')
+        for pick in self.browse(cr, uid, ids, context=context):
+            new_picking = None
+            complete, too_many, too_few = [], [], []
+            move_product_qty, lot_ids, partial_qty, product_uoms = {}, {}, {}, {}
 
-#TODO: check more in depth that the partial picking is working, then remove this bunch of code
-#    def do_partial(self, cr, uid, ids, partial_datas, context=None):
-#        """ Makes partial picking and moves done.
-#        @param partial_datas : Dictionary containing details of partial picking
-#                          like partner_id, partner_id, delivery_date,
-#                          delivery moves with product_id, product_qty, uom
-#        @return: Dictionary of values
-#        """
-#        if context is None:
-#            context = {}
-#        else:
-#            context = dict(context)
-#        res = {}
-#        move_obj = self.pool.get('stock.move')
-#        product_obj = self.pool.get('product.product')
-#        currency_obj = self.pool.get('res.currency')
-#        uom_obj = self.pool.get('product.uom')
-#        sequence_obj = self.pool.get('ir.sequence')
-#        for pick in self.browse(cr, uid, ids, context=context):
-#            new_picking = None
-#            complete, too_many, too_few = [], [], []
-#            move_product_qty, lot_ids, partial_qty, product_uoms = {}, {}, {}, {}
-#
-#            
-#            for move in pick.move_lines:
-#                if move.state in ('done', 'cancel'):
-#                    continue
-#                partial_data = partial_datas.get('move%s'%(move.id), {})
-#                product_qty = partial_data.get('product_qty',0.0)
-#                move_product_qty[move.id] = product_qty
-#                product_uom = partial_data.get('product_uom',False)
-#                product_price = partial_data.get('product_price',0.0)
-#                lot_id = partial_data.get('lot_id')
-#                lot_ids[move.id] = lot_id
-#                product_uoms[move.id] = product_uom
-#                partial_qty[move.id] = uom_obj._compute_qty(cr, uid, product_uoms[move.id], product_qty, move.product_uom.id)
-#                if move.product_qty == partial_qty[move.id]:
-#                    complete.append(move)
-#                elif move.product_qty > partial_qty[move.id]:
-#                    too_few.append(move)
-#                else:
-#                    too_many.append(move)
-#
-#
-#            for move in too_few:
-#                #create a backorder stock move with the remaining quantity
-#                product_qty = move_product_qty[move.id]
-#                if not new_picking:
-#                    #a backorder picking doesn't exist yet, create a new one
-#                    new_picking_name = pick.name
-#                    self.write(cr, uid, [pick.id], 
-#                               {'name': sequence_obj.get(cr, uid,
-#                                            'stock.picking.%s'%(pick.type)),
-#                               })
-#                    new_picking = self.copy(cr, uid, pick.id,
-#                            {
-#                                'name': new_picking_name,
-#                                'move_lines' : [],
-#                                'state':'draft',
-#                            })
-#                    #modify the existing picking (this trick is needed to keep the eventual workflows pointing on the first picking)
-#                    unlink_operation_order = [(2, op.id) for op in pick.pack_operation_ids]
-#                    self.write(cr, uid, [pick.id], 
-#                               {
-#                                'pack_operation_ids': unlink_operation_order
-#                               })
-#                done_reserved_quants = set()
-#                if product_qty != 0:
-#                    #take care of partial picking in reserved quants
-#                    done_reserved_quants = self.get_done_reserved_quants(cr, uid, pick.id, move, context=context)
-#                    #copy the stock move
-#                    new_picking_record = self.browse(cr, uid, new_picking, context=context)
-#
-#                    defaults = {
-#                            'product_qty' : product_qty,
-#                            'product_uos_qty': product_qty, #TODO: put correct uos_qty
-#                            'picking_id' : new_picking,
-#                            'state': 'assigned',
-#                            'move_dest_id': False,
-#                            'price_unit': product_price,
-#                            'product_uom': product_uoms[move.id],
-#                            'reserved_quant_ids': [(4,x) for x in list(done_reserved_quants)]
-#                    }
-#                    lot_id = lot_ids[move.id]
-#                    if lot_id:
-#                        defaults.update(lot_id=lot_id)
-#                    backorder_move_id = move_obj.copy(cr, uid, move.id, defaults)
-#                    self.make_packaging(cr, uid, pick.id, move_obj.browse(cr, uid, backorder_move_id, context=context), list(done_reserved_quants), context=context)
-#                #modify the existing stock move    
-#                possible_quants = [x.id for x in move.reserved_quant_ids]
-#                move_obj.write(cr, uid, [move.id],
-#                        {
-#                            'product_qty': move.product_qty - partial_qty[move.id],
-#                            'product_uos_qty': move.product_qty - partial_qty[move.id], #TODO: put correct uos_qty
-#                            'lot_id': False,
-#                            'tracking_id': False,
-#                            'reserved_quant_ids': [(4,x) for x in list(set(possible_quants) - done_reserved_quants)],
-#                        })
-#
-#            if new_picking:
-#                move_obj.write(cr, uid, [c.id for c in complete], {'picking_id': new_picking})
-#            for move in complete:
-#                defaults = {'product_uom': product_uoms[move.id], 'product_qty': move_product_qty[move.id]}
-#                if lot_ids.get(move.id):
-#                    defaults.update({'lot_id': lot_ids[move.id]})
-#                move_obj.write(cr, uid, [move.id], defaults)
-#
-#
-#                #take care of packaging for completed moves
-#                possible_quants = [x.id for x in move.reserved_quant_ids]
-#
-#                self.make_packaging(cr, uid, new_picking, move, possible_quants, context=context)
-#
-#
-#
-#            for move in too_many:
-#                product_qty = move_product_qty[move.id]
-#                defaults = {
-#                    'product_qty' : product_qty,
-#                    'product_uos_qty': product_qty, #TODO: put correct uos_qty
-#                    'product_uom': product_uoms[move.id]
-#                }
-#                lot_id = lot_ids.get(move.id)
-#                if lot_ids.get(move.id):
-#                    defaults.update(lot_id=lot_id)
-#                if new_picking:
-#                    defaults.update(picking_id=new_picking)
-#                move_obj.write(cr, uid, [move.id], defaults)
-#
-#                possible_quants = [x.id for x in move.reserved_quant_ids]
-#                self.make_packaging(cr, uid, new_picking, move, possible_quants, context=context)
-#            # At first we confirm the new picking (if necessary)
-#            if new_picking:
-#                self.signal_button_confirm(cr, uid, [new_picking])
-#                # Then we finish the good picking
-#                self.write(cr, uid, [pick.id], {'backorder_id': new_picking})
-#                self.action_move(cr, uid, [new_picking], context=context)
-#                self.signal_button_done(cr, uid, [new_picking])
-#                delivered_pack_id = new_picking
-#                back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
-#                self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
-#            else:
-#                self.action_move(cr, uid, [pick.id], context=context)
-#                self.signal_button_done(cr, uid, [pick.id])
-#                delivered_pack_id = pick.id
-#
-#            delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
-#            res[pick.id] = {'delivered_picking': delivered_pack.id}
-#
-#        return res
+            
+            for move in pick.move_lines:
+                if move.state in ('done', 'cancel'):
+                    continue
+                partial_data = partial_datas.get('move%s'%(move.id), {})
+                product_qty = partial_data.get('product_qty',0.0)
+                move_product_qty[move.id] = product_qty
+                product_uom = partial_data.get('product_uom',False)
+                product_price = partial_data.get('product_price',0.0)
+                lot_id = partial_data.get('lot_id')
+                lot_ids[move.id] = lot_id
+                product_uoms[move.id] = product_uom
+                partial_qty[move.id] = uom_obj._compute_qty(cr, uid, product_uoms[move.id], product_qty, move.product_uom.id)
+                if move.product_qty == partial_qty[move.id]:
+                    complete.append(move)
+                elif move.product_qty > partial_qty[move.id]:
+                    too_few.append(move)
+                else:
+                    too_many.append(move)
+
+
+            for move in too_few:
+                #create a backorder stock move with the remaining quantity
+                product_qty = move_product_qty[move.id]
+                if not new_picking:
+                    #a backorder picking doesn't exist yet, create a new one
+                    new_picking_name = pick.name
+                    self.write(cr, uid, [pick.id], 
+                               {'name': sequence_obj.get(cr, uid,
+                                            'stock.picking.%s'%(pick.type)),
+                               })
+                    new_picking = self.copy(cr, uid, pick.id,
+                            {
+                                'name': new_picking_name,
+                                'move_lines' : [],
+                                'state':'draft',
+                            })
+                    #modify the existing picking (this trick is needed to keep the eventual workflows pointing on the first picking)
+                    unlink_operation_order = [(2, op.id) for op in pick.pack_operation_ids]
+                    self.write(cr, uid, [pick.id], 
+                               {
+                                'pack_operation_ids': unlink_operation_order
+                               })
+                done_reserved_quants = set()
+                if product_qty != 0:
+                    #take care of partial picking in reserved quants
+                    done_reserved_quants = self.get_done_reserved_quants(cr, uid, pick.id, move, context=context)
+                    #copy the stock move
+                    new_picking_record = self.browse(cr, uid, new_picking, context=context)
+
+                    defaults = {
+                            'product_qty' : product_qty,
+                            'product_uos_qty': product_qty, #TODO: put correct uos_qty
+                            'picking_id' : new_picking,
+                            'state': 'assigned',
+                            'move_dest_id': False,
+                            'price_unit': product_price,
+                            'product_uom': product_uoms[move.id],
+                            'reserved_quant_ids': [(4,x) for x in list(done_reserved_quants)]
+                    }
+                    lot_id = lot_ids[move.id]
+                    if lot_id:
+                        defaults.update(lot_id=lot_id)
+                    backorder_move_id = move_obj.copy(cr, uid, move.id, defaults)
+                    self.make_packaging(cr, uid, pick.id, move_obj.browse(cr, uid, backorder_move_id, context=context), list(done_reserved_quants), context=context)
+                #modify the existing stock move    
+                possible_quants = [x.id for x in move.reserved_quant_ids]
+                move_obj.write(cr, uid, [move.id],
+                        {
+                            'product_qty': move.product_qty - partial_qty[move.id],
+                            'product_uos_qty': move.product_qty - partial_qty[move.id], #TODO: put correct uos_qty
+                            'lot_id': False,
+                            'tracking_id': False,
+                            'reserved_quant_ids': [(4,x) for x in list(set(possible_quants) - done_reserved_quants)],
+                        })
+
+            if new_picking:
+                move_obj.write(cr, uid, [c.id for c in complete], {'picking_id': new_picking})
+            for move in complete:
+                defaults = {'product_uom': product_uoms[move.id], 'product_qty': move_product_qty[move.id]}
+                if lot_ids.get(move.id):
+                    defaults.update({'lot_id': lot_ids[move.id]})
+                move_obj.write(cr, uid, [move.id], defaults)
+
+
+                #take care of packaging for completed moves
+                possible_quants = [x.id for x in move.reserved_quant_ids]
+
+                self.make_packaging(cr, uid, new_picking, move, possible_quants, context=context)
+
+
+
+            for move in too_many:
+                product_qty = move_product_qty[move.id]
+                defaults = {
+                    'product_qty' : product_qty,
+                    'product_uos_qty': product_qty, #TODO: put correct uos_qty
+                    'product_uom': product_uoms[move.id]
+                }
+                lot_id = lot_ids.get(move.id)
+                if lot_ids.get(move.id):
+                    defaults.update(lot_id=lot_id)
+                if new_picking:
+                    defaults.update(picking_id=new_picking)
+                move_obj.write(cr, uid, [move.id], defaults)
+
+                possible_quants = [x.id for x in move.reserved_quant_ids]
+                self.make_packaging(cr, uid, new_picking, move, possible_quants, context=context)
+            # At first we confirm the new picking (if necessary)
+            if new_picking:
+                self.signal_button_confirm(cr, uid, [new_picking])
+                # Then we finish the good picking
+                self.write(cr, uid, [pick.id], {'backorder_id': new_picking})
+                self.action_move(cr, uid, [new_picking], context=context)
+                self.signal_button_done(cr, uid, [new_picking])
+                delivered_pack_id = new_picking
+                back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
+                self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
+            else:
+                self.action_move(cr, uid, [pick.id], context=context)
+                self.signal_button_done(cr, uid, [pick.id])
+                delivered_pack_id = pick.id
+
+            delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
+            res[pick.id] = {'delivered_picking': delivered_pack.id}
+
+        return res
     
     # views associated to each picking type
     _VIEW_LIST = {
@@ -1518,41 +1513,7 @@ class stock_move(osv.osv):
             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
-        pick_obj = self.pool.get("stock.picking")
-        sequence_obj = self.pool.get('ir.sequence')
-        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']), ('partner_id', '=', move.partner_id.id)], context=context)
-        if picks:
-            pick = picks[0]
-        else:
-            if context.get('backorder_of'):
-                original_picking = pick_obj.browse(cr, uid, context.get('backorder_of'), context=context)
-                new_picking_name = original_picking.name
-                back_order_name = sequence_obj.get(cr, uid, 'stock.picking.%s' % (original_picking.type))
-                pick_obj.write(cr, uid, [original_picking.id], {'name': back_order_name})
-                pick = pick_obj.copy(cr, uid, original_picking.id, {'name': new_picking_name,
-                                                    'move_lines': [],
-                                                    'state': 'draft'})
-                pick_obj.message_post(cr, uid, original_picking.id, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
-                pick_obj.write(cr, uid, [original_picking.id], {'backorder_id': pick})
-            else:
-                #a backorder 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,
-                          'type': 'internal',
-                          'move_type': 'one',
-                          'partner_id': move.partner_id and move.partner_id.id or False,
-                          #'invoice_state': move.invoice_state
-                          'state': 'confirmed',
-                          'group_id': move.group_id and move.group_id.id or False}
-                pick = pick_obj.create(cr, uid, values, context=context)
-        return pick
+        return {'value':{'location_id': source_location and source_location[1] or False, 'location_dest_id': dest_location and dest_location[1] or False}}
 
     def onchange_date(self, cr, uid, ids, date, date_expected, context=None):
         """ On change of Scheduled Date gives a Move date.
@@ -1575,12 +1536,28 @@ class stock_move(osv.osv):
         for move in self.browse(cr, uid, ids, context=context):
             state = 'confirmed'
             for m in move.move_orig_ids:
-                if m.state not in ('done', 'cancel'):
+                if m.state not in ('done','cancel'):
                     state = 'waiting'
             states[state].append(move.id)
 
             if not move.picking_id:
-                pick = self._find_or_create_picking(cr, uid, move, context=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
+                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)
+                if picks:
+                    pick=picks[0]
+                else:
+                    # Create new picking
+                    pick = pick_obj.create(cr, uid, {'origin': move.origin,
+                                              'company_id': move.company_id and move.company_id.id or False,
+                                              'type': 'internal',
+                                              'move_type': 'one',
+                                              'partner_id': move.partner_id and move.partner_id.id or False,
+                                              #'invoice_state': move.invoice_state
+                                              'state' : 'confirmed', 
+                                              'group_id': move.group_id and move.group_id.id or False, 
+                                              }, context=context)
                 move.write({'picking_id': pick})
 
 
@@ -1642,7 +1619,7 @@ class stock_move(osv.osv):
         pick_obj = self.pool.get("stock.picking")
         for pick in list(pickings):
             if pick_obj.test_assigned(cr, uid, [pick]):
-             pick_obj.write(cr, uid, [pick], {'state': 'assigned'})
+                pick_obj.write(cr, uid, [pick], {'state': 'assigned'})
         return done
 
 
@@ -1681,9 +1658,12 @@ class stock_move(osv.osv):
         """
         context = context or {}
         quant_obj = self.pool.get("stock.quant")
-        picking_obj = self.pool.get('stock.picking')
+        uom_obj = self.pool.get("product.uom")
 
-        todo = [move.id for move in self.browse(cr, uid, ids, context=context) if move.state == "draft"]
+        todo = []
+        for move in self.browse(cr, uid, ids, context=context):
+            if move.state=="draft":
+                todo.append(move.id)
         if todo:
             self.action_confirm(cr, uid, todo, context=context)
 
@@ -1716,12 +1696,6 @@ class stock_move(osv.osv):
                         self.action_done(cr, uid, [move.move_dest_id.id], context=context)
 
         self.write(cr, uid, ids, {'state': 'done', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
-
-        if move.picking_id:
-            move.picking_id.refresh()
-            if all([m.state in ('done', 'cancel') for m in move.picking_id.move_lines]):
-                #finish the picking if it was the last move (we exclude the move we just set to done because we know the value and the browse record cache isn't up to date
-                picking_obj.action_done(cr, uid, [move.picking_id.id], context=context)
         return True
 
     def unlink(self, cr, uid, ids, context=None):
@@ -1791,7 +1765,6 @@ class stock_move(osv.osv):
         @return: Consumed lines
         """
         #quantity should in MOVE UOM
-        print "BOoommmB OOM  boOOOM"
         if context is None:
             context = {}
         if quantity <= 0:
@@ -1937,12 +1910,16 @@ class stock_move(osv.osv):
 #        return res
 
     # FIXME: needs refactoring, this code is partially duplicated in stock_picking.do_partial()!
-    def do_partial(self, cr, uid, move_id, partial_data, move_group_id, context=None):
-        """ Partially (or not) moves  a stock.move.
+    def do_partial(self, cr, uid, ids, partial_datas, context=None):
+        """ Makes partial pickings and moves done.
         @param partial_datas: Dictionary containing details of partial picking
                           like partner_id, delivery_date, delivery
                           moves with product_id, product_qty, uom
         """
+        res = {}
+        picking_obj = self.pool.get('stock.picking')
+        product_obj = self.pool.get('product.product')
+        currency_obj = self.pool.get('res.currency')
         uom_obj = self.pool.get('product.uom')
 
         if context is None:
@@ -1950,59 +1927,80 @@ class stock_move(osv.osv):
 
         complete, too_many, too_few = [], [], []
         move_product_qty, lot_ids, partial_qty, product_uoms = {}, {}, {}, {}
+        
+
+        for move in self.browse(cr, uid, ids, context=context):
+            if move.state in ('done', 'cancel'):
+                continue
+            partial_data = partial_datas.get('move%s'%(move.id), {})
+            product_qty = partial_data.get('product_qty',0.0)
+            move_product_qty[move.id] = product_qty
+            product_uom = partial_data.get('product_uom',False)
+            product_price = partial_data.get('product_price',0.0)
+            product_currency = partial_data.get('product_currency',False)
+            lot_id = partial_data.get('lot_id')
+            lot_ids[move.id] = lot_id
+            product_uoms[move.id] = product_uom
+            partial_qty[move.id] = uom_obj._compute_qty(cr, uid, product_uoms[move.id], product_qty, move.product_uom.id)
+            if move.product_qty == partial_qty[move.id]:
+                complete.append(move)
+            elif move.product_qty > partial_qty[move.id]:
+                too_few.append(move)
+            else:
+                too_many.append(move)
+
+        for move in too_few:
+            product_qty = move_product_qty[move.id]
+            if product_qty != 0:
+                defaults = {
+                            'product_qty' : product_qty,
+                            'product_uos_qty': product_qty,
+                            'picking_id' : move.picking_id.id,
+                            'state': 'assigned',
+                            'move_dest_id': False,
+                            'price_unit': product_price,
+                            }
+                lot_id = lot_ids[move.id]
+                if lot_id:
+                    defaults.update(lot_id=lot_id)
+                new_move = self.copy(cr, uid, move.id, defaults)
+                complete.append(self.browse(cr, uid, new_move))
+            self.write(cr, uid, [move.id],
+                    {
+                        'product_qty': move.product_qty - product_qty,
+                        'product_uos_qty': move.product_qty - product_qty,
+                        'lot_id': False,
+                        'tracking_id': False,
+                    })
+
+
+        for move in too_many:
+            self.write(cr, uid, [move.id],
+                    {
+                        'product_qty': move.product_qty,
+                        'product_uos_qty': move.product_qty,
+                    })
+            complete.append(move)
+
+        for move in complete:
+            if lot_ids.get(move.id):
+                self.write(cr, uid, [move.id],{'lot_id': lot_ids.get(move.id)})
+            self.action_done(cr, uid, [move.id], context=context)
+            if  move.picking_id.id :
+                # TOCHECK : Done picking if all moves are done
+                cr.execute("""
+                    SELECT move.id FROM stock_picking pick
+                    RIGHT JOIN stock_move move ON move.picking_id = pick.id AND move.state = %s
+                    WHERE pick.id = %s""",
+                            ('done', move.picking_id.id))
+                res = cr.fetchall()
+                if len(res) == len(move.picking_id.move_lines):
+                    picking_obj.action_move(cr, uid, [move.picking_id.id])
+                    picking_obj.signal_button_done(cr, uid, [move.picking_id.id])
+
+        return [move.id for move in complete]
 
-        move = self.browse(cr, uid, move_id, context=context)
-        product_uom_qty = partial_data.get('product_uom_qty', 0.0)
-        product_uom = partial_data.get('product_uom', False)
-        #lot_id = partial_data.get('lot_id')
-        if move.state in ('done', 'cancel') or product_uom_qty == 0:
-            return
-        #TODO add back these constraint checks
-        ##Compute the quantity for respective wizard_line in the line uom (this jsut do the rounding if necessary)
-        #qty_in_line_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, line_uom.id)
-
-        #if line_uom.factor and line_uom.factor <> 0:
-        #    if float_compare(qty_in_line_uom, wizard_line.quantity, precision_rounding=line_uom.rounding) != 0:
-        #        raise osv.except_osv(_('Warning!'), _('The unit of measure rounding does not allow you to ship "%s %s", only rounding of "%s %s" is accepted by the Unit of Measure.') % (wizard_line.quantity, line_uom.name, line_uom.rounding, line_uom.name))
-        ##Check rounding Quantity.ex.
-        ##picking: 1kg, uom kg rounding = 0.01 (rounding to 10g),
-        ##partial delivery: 253g
-        ##=> result= refused, as the qty left on picking would be 0.747kg and only 0.75 is accepted by the uom.
-        #initial_uom = wizard_line.move_id.product_uom
-        ##Compute the quantity for respective wizard_line in the initial uom
-        #qty_in_initial_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, initial_uom.id)
-        #without_rounding_qty = (wizard_line.quantity / line_uom.factor) * initial_uom.factor
-        #if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0:
-        #    raise osv.except_osv(_('Warning!'), _('The rounding of the initial uom does not allow you to ship "%s %s", as it would let a quantity of "%s %s" to ship and only roundings of "%s %s" are accepted by the uom.') % (wizard_line.quantity, line_uom.name, wizard_line.move_id.product_qty - without_rounding_qty, initial_uom.name, initial_uom.rounding, initial_uom.name))
-
-
-        #partial_qty is the quantity processed in the normalized product uom
-        partial_qty = uom_obj._compute_qty(cr, uid, product_uom, product_uom_qty, move.product_id.uom_id.id)
-        if move.product_qty == partial_qty:
-            todo_move_id = move.id
-        elif move.product_qty > partial_qty:
-            defaults = {
-                        'product_uom_qty': product_uom_qty,
-                        'product_uos_qty': product_uom_qty,
-                        'picking_id': False,
-                        'group_id': move_group_id,
-                        'state': 'assigned',
-                        'move_dest_id': False,
-                        'price_unit': partial_data.get('price_unit', 0.0),
-                        }
-            new_move = self.copy(cr, uid, move.id, defaults)
-            todo_move_id = new_move
-            self.write(cr, uid, [move.id], {'product_uom_qty': move.product_qty - product_uom_qty,
-                                            'product_uos_qty': move.product_qty - product_uom_qty,
-                                            'lot_id': False,
-                                            'tracking_id': False})
-        else:
-            self.write(cr, uid, [move.id], {'product_uom_qty': move.product_uom_qty, 'product_uos_qty': move.product_uom_qty})
-            todo_move_id = move.id
 
-        #TODO LOT management
-        #self.write(cr, uid, [todo_move_id], {'prefered_lot_ids': })
-        return todo_move_id
 
     def get_type_from_usage(self, cr, uid, location, location_dest, context=None):
         '''
index 841b7e6..60f838f 100644 (file)
@@ -38,6 +38,13 @@ class stock_location_route(osv.osv):
         'sequence': lambda self,cr,uid,ctx: 0,
     }
 
+class stock_warehouse(osv.osv):
+    _inherit = 'stock.warehouse'
+    _columns = {
+        'route_id': fields.many2one('stock.location.route', help='Default route through the warehouse'), 
+    }
+
+
 class stock_location_path(osv.osv):
     _name = "stock.location.path"
     _description = "Pushed Flows"
@@ -130,10 +137,13 @@ class procurement_rule(osv.osv):
 
 
 
-
 class procurement_order(osv.osv):
     _inherit = 'procurement.order'
     
+    _columns = {
+        'route_ids': fields.many2many('stock.location.route', 'stock_location_route_procurement', 'procurement_id', 'route_id', 'Destination route', help="Preferred route to be followed by the procurement order"),
+        }
+    
     def _run_move_create(self, cr, uid, procurement, context=None):
         d = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context)
         if procurement.move_dest_id:
@@ -150,11 +160,13 @@ class procurement_order(osv.osv):
 
     def _search_suitable_rule(self, cr, uid, procurement, domain, context=None):
         '''we try to first find a rule among the ones defined on the procurement order group and if none is found, we try on the routes defined for the product, and finally we fallback on the default behavior'''
-        #TODO check first on procurement order group
-        route_ids = [x.id for x in procurement.product_id.route_ids]
+        route_ids = [x.id for x in procurement.route_ids]
         res = super(procurement_order, self)._search_suitable_rule(cr, uid, procurement, domain + [('route_id', 'in', route_ids)], context=context)
         if not res:
-            return super(procurement_order, self)._search_suitable_rule(cr, uid, procurement, domain, context=context)
+            route_ids = [x.id for x in procurement.product_id.route_ids]
+            res = super(procurement_order, self)._search_suitable_rule(cr, uid, procurement, domain + [('route_id', 'in', route_ids)], context=context)
+            if not res:
+                return super(procurement_order, self)._search_suitable_rule(cr, uid, procurement, domain, context=context)
         return res
 
 
index 5b99368..7f09f0b 100644 (file)
                        </field>
                </record>
 
+        <record id="view_warehouse_inherit" model="ir.ui.view">
+            <field name="name">stock.warehouse</field>
+            <field name="model">stock.warehouse</field>
+            <field name="inherit_id" ref="stock.view_warehouse"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='partner_id']" position="after">
+                    <field name="route_id"/>
+                </xpath>
+            </field>
+        </record>
+
                <record id="stock_location_route_tree" model="ir.ui.view">
                        <field name="name">stock.location.route.tree</field>
                        <field name="model">stock.location.route</field>