From a37043009c25ef2a05f60931cf7de21c0c776186 Mon Sep 17 00:00:00 2001
From: Josse Colpaert <jco@odoo.com>
Date: Wed, 29 Jul 2015 16:57:50 +0200
Subject: [PATCH] [IMP] stock: usability of routes configuration

It makes it clear which warehouses, products, product categories
are applied to a certain route (also add inverse many2many field)
in the route form.

The push/procurement rules forms are also a little bit uncluttered
to make a clear distinction between where it is applied and what it creates.
---
 addons/procurement/procurement_view.xml | 16 +++---
 addons/sale_stock/stock_view.xml        |  4 +-
 addons/stock/stock.py                   | 54 +++++++++++++-----
 addons/stock/stock_view.xml             | 75 +++++++++++++++----------
 4 files changed, 97 insertions(+), 52 deletions(-)

diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml
index f3b7f7d15063..d914be79ab07 100644
--- a/addons/procurement/procurement_view.xml
+++ b/addons/procurement/procurement_view.xml
@@ -273,17 +273,19 @@
                         <label for="name" class="oe_edit_only"/>
                         <h1><field name="name"/></h1>
                     </div>
-                    <group>
-                        <group string="General Information">
-                            <field name="action"/>
-                            <field name="sequence"/>
+                    <group name="general">
+                        <group>
                             <field name="active"/>
+                            <field name="action"/>
                         </group>
-                        <group name="propagation_group" string="Propagation Options" groups="base.group_no_one">
-                            <field name="group_propagation_option"/>
-                            <field name="group_id" attrs="{'invisible': [('group_propagation_option', '!=', 'fixed')], 'required': [('group_propagation_option', '=', 'fixed')]}"/>
+                        <group>
+                            <field name="sequence"/>
                         </group>
                     </group>
+                    <group name="propagation_group" string="Propagation Options" groups="base.group_no_one">
+                        <field name="group_propagation_option"/>
+                        <field name="group_id" attrs="{'invisible': [('group_propagation_option', '!=', 'fixed')], 'required': [('group_propagation_option', '=', 'fixed')]}"/>
+                    </group>
                 </form>
             </field>
         </record>
diff --git a/addons/sale_stock/stock_view.xml b/addons/sale_stock/stock_view.xml
index 95f72bd6f986..fba53eaadecf 100644
--- a/addons/sale_stock/stock_view.xml
+++ b/addons/sale_stock/stock_view.xml
@@ -25,8 +25,8 @@
             <field name="inherit_id" ref="stock.stock_location_route_form_view"/>
             <field name="model">stock.location.route</field>
             <field name="arch" type="xml">
-                <xpath expr="//field[@name='warehouse_selectable']" position="after">
-                    <field name="sale_selectable" string="Sale Order Lines"/>
+                <xpath expr="//field[@name='warehouse_ids']" position="after">
+                    <br/><field name="sale_selectable" string="Sale Order Lines"/>
                 </xpath>
             </field>
         </record>
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index e317322fcd60..1ad6b363df29 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -200,12 +200,16 @@ class stock_location_route(osv.osv):
         'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Procurement Rules', copy=True),
         'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the route without removing it."),
         'push_ids': fields.one2many('stock.location.path', 'route_id', 'Push Rules', copy=True),
-        'product_selectable': fields.boolean('Applicable on Product'),
-        'product_categ_selectable': fields.boolean('Applicable on Product Category'),
-        'warehouse_selectable': fields.boolean('Applicable on Warehouse'),
+        'product_selectable': fields.boolean('Applicable on Product', help="When checked, the route will be selectable in the Inventory tab of the Product form.  It will take priority over the Warehouse route. "),
+        'product_categ_selectable': fields.boolean('Applicable on Product Category', help="When checked, the route will be selectable on the Product Category.  It will take priority over the Warehouse route. "),
+        'warehouse_selectable': fields.boolean('Applicable on Warehouse', help="When a warehouse is selected for this route, this route should be seen as the default route when products pass through this warehouse.  This behaviour can be overridden by the routes on the Product/Product Categories or by the Preferred Routes on the Procurement"),
         'supplied_wh_id': fields.many2one('stock.warehouse', 'Supplied Warehouse'),
-        'supplier_wh_id': fields.many2one('stock.warehouse', 'Vendor Warehouse'),
-        'company_id': fields.many2one('res.company', 'Company', select=1, help='Let this field empty if this route is shared between all companies'),
+        'supplier_wh_id': fields.many2one('stock.warehouse', 'Supplying Warehouse'),
+        'company_id': fields.many2one('res.company', 'Company', select=1, help='Leave this field empty if this route is shared between all companies'),
+        #Reverse many2many fields:
+        'product_ids': fields.many2many('product.template', 'stock_route_product', 'route_id', 'product_id', 'Products'),
+        'categ_ids': fields.many2many('product.category', 'stock_location_route_categ', 'route_id', 'categ_id', 'Product Categories'),
+        'warehouse_ids': fields.many2many('stock.warehouse', 'stock_route_warehouse', 'route_id', 'warehouse_id', 'Warehouses'),
     }
 
     _defaults = {
@@ -234,6 +238,27 @@ class stock_location_route(osv.osv):
                 self.pool.get('procurement.rule').write(cr, uid, pull_ids, {'active': vals['active']}, context=context)
         return res
 
+    def view_product_ids(self, cr, uid, ids, context=None):
+        return {
+            'name': _('Products'),
+            'view_type': 'form',
+            'view_mode': 'tree,form',
+            'res_model': 'product.template',
+            'type': 'ir.actions.act_window',
+            'domain': [('route_ids', 'in', ids[0])],
+        }
+
+    def view_categ_ids(self, cr, uid, ids, context=None):
+        return {
+            'name': _('Product Categories'),
+            'view_type': 'form',
+            'view_mode': 'tree,form',
+            'res_model': 'product.category',
+            'type': 'ir.actions.act_window',
+            'domain': [('route_ids', 'in', ids[0])],
+        }
+
+
 #----------------------------------------------------------
 # Quants
 #----------------------------------------------------------
@@ -3890,21 +3915,22 @@ class stock_location_path(osv.osv):
         'name': fields.char('Operation Name', required=True),
         'company_id': fields.many2one('res.company', 'Company'),
         'route_id': fields.many2one('stock.location.route', 'Route'),
-        'location_from_id': fields.many2one('stock.location', 'Source Location', ondelete='cascade', select=1, required=True),
-        'location_dest_id': fields.many2one('stock.location', 'Destination Location', ondelete='cascade', select=1, required=True),
-        'delay': fields.integer('Delay (days)', help="Number of days to do this transition"),
-        'picking_type_id': fields.many2one('stock.picking.type', 'Type of the new Operation', required=True, help="This is the picking type associated with the different pickings"), 
+        'location_from_id': fields.many2one('stock.location', 'Source Location', ondelete='cascade', select=1, required=True,
+                                            help="This rule can be applied when a move is confirmed that has this location as destination location"),
+        'location_dest_id': fields.many2one('stock.location', 'Destination Location', ondelete='cascade', select=1, required=True,
+                                            help="The new location where the goods need to go"),
+        'delay': fields.integer('Delay (days)', help="Number of days needed to transfer the goods"),
+        'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True,
+                                           help="This is the picking type that will be put on the stock moves"),
         'auto': fields.selection(
             [('auto','Automatic Move'), ('manual','Manual Operation'),('transparent','Automatic No Step Added')],
             'Automatic Move',
             required=True, select=1,
-            help="This is used to define paths the product has to follow within the location tree.\n" \
-                "The 'Automatic Move' value will create a stock move after the current one that will be "\
-                "validated automatically. With 'Manual Operation', the stock move has to be validated "\
-                "by a worker. With 'Automatic No Step Added', the location is replaced in the original move."
+            help="The 'Automatic Move' / 'Manual Operation' value will create a stock move after the current one.  " \
+                 "With 'Automatic No Step Added', the location is replaced in the original move."
             ),
         'propagate': fields.boolean('Propagate cancel and split', help='If checked, when the previous move is cancelled or split, the move generated by this move will too'),
-        'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the rule without removing it."),
+        'active': fields.boolean('Active'),
         'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
         'route_sequence': fields.related('route_id', 'sequence', string='Route Sequence',
             store={
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index d2d2658864a9..8f33eaf077a8 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -442,21 +442,31 @@
             <field name="model">stock.location.path</field>
             <field name="arch" type="xml">
                 <form string="Location Paths">
-                    <group col="4">
+                    <div class="oe_title">
+                        <label for="name" class="oe_edit_only"/>
+                        <h1><field name="name"/></h1>
+                    </div>
+                    <group>
                         <group>
-                            <field name="name"/>
+                            <field name="active"/>
+                        </group>
+                        <group>
+                            <field name="sequence"/>
+                        </group>
+                    </group>
+                    <group>
+                        <group string="Locations">
                             <field name="location_from_id"/>
                             <field name="location_dest_id"/>
-                            <field name="route_id"/>
                         </group>
-                        <group>
-                            <field name="company_id" groups="base.group_multi_company" />
-                            <field name="picking_type_id"/>
+                        <group string="Details">
                             <field name="auto"/>
+                            <field name="picking_type_id" attrs="{'invisible': [('auto', '=', 'transparent')]}"/>
+                            <field name="company_id" groups="base.group_multi_company" />
                             <label for="delay" string="Delay"/>
-                        <div>
-                            <field name="delay" class="oe_inline"/>days
-                        </div>
+                            <div>
+                                <field name="delay" class="oe_inline"/>days
+                            </div>
                         </group>
                     </group>
                 </form>
@@ -1887,29 +1897,28 @@
             <field name="model">procurement.rule</field>
             <field name="inherit_id" ref="procurement.view_procurement_rule_form"/>
             <field name="arch" type="xml">
-                <xpath expr="//field[@name='action']" position="before">
-                    <field name="location_id"/>
-                    <field name="warehouse_id" groups="base.group_no_one"/>
-                    <field name="route_id" groups="base.group_no_one"/>
-                </xpath>
-                <xpath expr="//field[@name='action']" position="after">
-                    <field name="picking_type_id" attrs="{'required': [('action', '!=', 'manufacture')]}"/>
+                <xpath expr="//group[@name='general']" position="after">
+                    <group>
+                        <group string="Applied On">
+                            <field name="location_id"/>
+                            <field name="warehouse_id" groups="base.group_no_one"/>
+                        </group>
+                        <group string="Creates">
+                            <field name="location_src_id" attrs="{'required': [('action', '=', 'move')], 'invisible':[('action', '!=', 'move')]}"  domain="[('usage','!=','view')]"/>
+                            <field name="procure_method" groups="stock.group_adv_location" attrs="{'invisible': [('action', '!=', 'move')]}"/>
+                            <field name="picking_type_id" attrs="{'required': [('action', '!=', 'manufacture')]}"/>
+                            <field name="partner_address_id" groups="stock.group_adv_location" context="{'show_address': 1}" options="{'always_reload': 1}" attrs="{'invisible': [('action', '!=', 'move')]}"/>
+                            <label for="delay" string="Delay"  groups="stock.group_adv_location" attrs="{'invisible': [('action', '!=', 'move')]}"/>
+                            <div groups="stock.group_adv_location" attrs="{'invisible': [('action', '!=', 'move')]}">
+                               <field name="delay" class="oe_inline"/>days
+                            </div>
+                        </group>
+                    </group>
                 </xpath>
                 <xpath expr="//field[@name='group_id']" position="after">
                     <field name="propagate"/>
                     <field name="propagate_warehouse_id"/>
                 </xpath>
-                <xpath expr="//group[@name='propagation_group']" position="before">
-                    <group attrs="{'invisible': [('action', '!=', 'move')]}" string="Moving Options">
-                        <field name="procure_method" groups="stock.group_adv_location"/>
-                        <field name="location_src_id" attrs="{'required': [('action', '=', 'move')]}"  domain="[('usage','!=','view')]" />
-                        <field name="partner_address_id" groups="stock.group_adv_location" context="{'show_address': 1}" options="{'always_reload': 1}"/>
-                        <label for="delay" string="Delay"  groups="stock.group_adv_location"/>
-                        <div groups="stock.group_adv_location">
-                           <field name="delay" class="oe_inline"/>days
-                        </div>
-                    </group>
-                </xpath>
             </field>
         </record>
         
@@ -2209,11 +2218,19 @@
                     <p class="oe_grey">Select the places where this route can be selected</p>
                     <group>
                         <group>
-                            <field name="product_categ_selectable" string="Product Categories"/>
-                            <field name="product_selectable" string="Products"/>
+                            <button name="view_categ_ids" for="product_categ_selectable" type="object" string="Product Categories" class="oe_link"/>
+                            <div>
+                                <field name="product_categ_selectable" class="oe_inline"/>
+                            </div>
+                            <button name="view_product_ids" for="product_selectable" type="object" string="Products" class="oe_link"/>
+                            <div>
+                                <field name="product_selectable" class="oe_inline"/>
+                            </div>
                         </group>
                         <group>
                             <field name="warehouse_selectable" string="Warehouses"/>
+                            <field name="warehouse_ids"  widget="many2many_tags" nolabel="1"
+                                   attrs="{'readonly': [('warehouse_selectable', '=', False)]}"/>
                         </group>
                     </group>
                     <group string="Push Rules" colspan="4" >
-- 
GitLab