← Back to team overview

openerp-community-reviewer team mailing list archive

[Merge] lp:~camptocamp/sale-wkfl/product_procurement_type into lp:sale-wkfl

 

Alexandre Fayolle - camptocamp has proposed merging lp:~camptocamp/sale-wkfl/product_procurement_type into lp:sale-wkfl.

Requested reviews:
  Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c): code review + no tests
  Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c): code review, test
  Lorenzo Battistini - Agile BG (elbati)
  Stefan Rijnhart (Therp) (stefan-therp)
  Leonardo Pistone - camptocamp (lpistone): code review
  Yannick Vaucher @ Camptocamp (yvaucher-c2c): code review, no tests

For more details, see:
https://code.launchpad.net/~camptocamp/sale-wkfl/product_procurement_type/+merge/222111

Here are two new addons who brings a simple field to manage several combinations
for two procurements fields : procure_method & supply_method :
First addon adds:
- Normal: MTS + buy
- Bill of Materials: MTO + produce
Second addon depends of sale_dropshipping addon and adds:
- Dropshipping: MTO + buy

I'm not sure if it's the right community branch to propose it, if you think about a better
place, let me know.

-- 
https://code.launchpad.net/~camptocamp/sale-wkfl/product_procurement_type/+merge/222111
Your team Sale Core Editors is subscribed to branch lp:sale-wkfl.
=== added directory 'product_procurement_type'
=== added file 'product_procurement_type/__init__.py'
--- product_procurement_type/__init__.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type/__init__.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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 . import product

=== added file 'product_procurement_type/__openerp__.py'
--- product_procurement_type/__openerp__.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type/__openerp__.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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": "Product Procurement Types",
+    "version": "0.1",
+    "author": "Camptocamp",
+    "license": "AGPL-3",
+    "category": "Sales",
+    "description":
+    """
+    Add a procurement type selection on products.
+    Let create products as :
+     - Standard
+     - Bill of Materials
+
+    Choose "Standard" changes automatically
+    procurement method as "make to stock" and supply method as "buy".
+    Choose "Bill of Materials" changes automatically
+    procurement method as "make to order" and supply method as "produce".
+
+    """,
+    "website": "http://camptocamp.com";,
+    "depends": ['sale',
+                'procurement',
+                'mrp'],
+    "data": ['product_view.xml'],
+    "demo": [],
+    "test": ['test/test_onchange_procurement_type.yml'],
+    "active": False,
+    "installable": True,
+}

=== added file 'product_procurement_type/product.py'
--- product_procurement_type/product.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type/product.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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 logging
+
+from openerp.osv import orm, fields
+
+_logger = logging.getLogger('openerp.upgrade')
+
+def get_procurement_type_selection():
+    return [('buy_stock', 'On stock, buy'),
+            ('buy_demand', 'On demand, buy'),
+            ('produce_demand', 'On demand, produce'),
+            ('produce_stock', 'On stock, produce'),
+            ]
+
+class product_template(orm.Model):
+
+    _inherit = 'product.template'
+
+    def init(self, cr):
+        _logger.info('Migrating product_procurement_type')
+        query = ("UPDATE product_template pt "
+                 "SET procurement_type=%(procurement_type)s "
+                 "WHERE procure_method=%(procure_method)s and supply_method=%(supply_method)s")
+        fixes = [{'procurement_type': 'buy_stock',
+                  'procure_method': 'make_to_stock',
+                  'supply_method': 'buy'},
+                 {'procurement_type': 'buy_demand',
+                  'procure_method': 'make_to_order',
+                  'supply_method': 'buy'},
+                 {'procurement_type': 'produce_stock',
+                  'procure_method': 'make_to_stock',
+                  'supply_method': 'produce'},
+                 {'procurement_type': 'produce_demand',
+                  'procure_method': 'make_to_order',
+                  'supply_method': 'produce'},
+                 ]
+        for fix in fixes:
+            cr.execute(query, fix)
+
+    def get_procurement_type_selection(self, cr, uid, context=None):
+        """
+        Has to be inherited to add procurement type
+        """
+        return get_procurement_type_selection()
+
+    def _compute_procurement_vals(self, vals):
+        if vals['procurement_type'] == 'buy_stock':
+            vals.update({'procure_method': 'make_to_stock',
+                         'supply_method': 'buy',
+                         })
+        elif vals['procurement_type'] == 'produce_demand':
+            vals.update({'procure_method': 'make_to_order',
+                         'supply_method': 'produce',
+                         })
+        elif vals['procurement_type'] == 'buy_demand':
+            vals.update({'procure_method': 'make_to_order',
+                         'supply_method': 'buy',
+                         })
+        elif vals['procurement_type'] == 'produce_stock':
+            vals.update({'procure_method': 'make_to_stock',
+                         'supply_method': 'produce',
+                         })
+        else:
+            raise ValueError(vals['procurement_type'])
+        return vals
+
+    _columns = {
+        'procurement_type': fields.selection(
+            get_procurement_type_selection,
+            'Procurement Type',
+            required=True,
+            help='On stock, buy: Procurement Method: Make to Stock, '
+                 'Supply Method: Buy.\n'
+                 'On stock, produce: Procurement Method: Make to Stock, '
+                 'Supply Method: Produce.\n'
+                 'On order, buy: Procurement Method: Make to Order, '
+                 'Supply Method: Buy.\n'
+                 'On order, produce: Procurement Method: Make to Order, '
+                 'Supply Method: Produce.\n'
+            ),
+    }
+
+    _defaults = {
+        'procurement_type': 'buy_stock',
+    }
+
+    def onchange_procurement_type(self, cr, uid, ids, type, procurement_type,
+                                  context=None):
+        vals = {'procurement_type': procurement_type}
+        if type != 'service':
+            vals = self._compute_procurement_vals(vals)
+        return {'value': vals}
+
+    def write(self, cr, uid, ids, vals, context=None):
+        for product in self.read(cr, uid, ids, ['type'], context=context):
+            if product['type'] != 'service' and \
+                    vals.get('procurement_type'):
+                vals = self._compute_procurement_vals(vals)
+        res = super(product_template, self).write(cr, uid, ids, vals,
+                                                  context=context)
+        return res
+
+    def create(self, cr, uid, vals, context=None):
+        if vals['type'] != 'service' and vals.get('procurement_type'):
+            vals = self._compute_procurement_vals(vals)
+        return super(product_template, self).create(cr, uid, vals,
+                                                    context=context)
+
+
+class product_product(orm.Model):
+
+    _inherit = 'product.product'
+
+    def onchange_procurement_type(self, cr, uid, ids, type, procurement_type,
+                                  context=None):
+        tmpl_obj = self.pool['product.template']
+        res = tmpl_obj.onchange_procurement_type(cr, uid, ids, type,
+                                                 procurement_type,
+                                                 context=context)
+        return {'value': res['value']}

=== added file 'product_procurement_type/product_view.xml'
--- product_procurement_type/product_view.xml	1970-01-01 00:00:00 +0000
+++ product_procurement_type/product_view.xml	2014-06-04 22:49:14 +0000
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="product_normal_form_view_procurement_type" model="ir.ui.view">
+            <field name="name">product.product.procurement_type</field>
+            <field name="model">product.product</field>
+            <field name="inherit_id" ref="procurement.product_form_view_procurement_button"/>
+            <field name="arch" type="xml">
+                <data>
+                    <field name="procure_method" position="before">
+                        <field name="procurement_type" on_change="onchange_procurement_type(type, procurement_type)" attrs="{'invisible':[('type','=','service')]}"/>
+                    </field>
+                    <field name="supply_method" position="attributes">
+                     <attribute name="attrs">{'invisible':[('type','!=','service')]}</attribute>
+                    </field>
+                    <field name="procure_method" position="attributes">
+                     <attribute name="attrs">{'invisible':[('type','!=','service')]}</attribute>
+                    </field>
+                </data>
+            </field>
+        </record>
+        
+        <record model="ir.ui.view" id="product_template_form_view_procurement_type">
+            <field name="name">product.template.procurement_type</field>
+            <field name="model">product.template</field>
+            <field name="inherit_id" ref="procurement.product_template_form_view_procurement"/>
+            <field name="arch" type="xml">
+                <data>
+                    <field name="procure_method" position="before">
+                        <field name="procurement_type" on_change="onchange_procurement_type(type, procurement_type)" attrs="{'invisible':[('type','=','service')]}"/>
+                    </field>
+                    <field name="procure_method" position="attributes">
+                     <attribute name="invisible">{'invisible':[('type','!=','service')]}</attribute>
+                    </field>
+                    <field name="supply_method" position="attributes">
+                     <attribute name="invisible">{'invisible':[('type','!=','service')]}</attribute>
+                    </field>
+                </data>
+            </field>
+        </record>        
+    </data>
+</openerp>

=== added directory 'product_procurement_type/test'
=== added file 'product_procurement_type/test/test_onchange_procurement_type.yml'
--- product_procurement_type/test/test_onchange_procurement_type.yml	1970-01-01 00:00:00 +0000
+++ product_procurement_type/test/test_onchange_procurement_type.yml	2014-06-04 22:49:14 +0000
@@ -0,0 +1,56 @@
+-
+  Testing change of procurement type on product
+-
+  I create a product "Store" with type buy_stock
+-
+  !record {model: product.product, id: product1}:
+    name: Store
+    type: product
+    procurement_type: buy_stock
+-
+  I check if the product is MTS + buy
+-
+  !assert {model: product.product, id: product1}:
+    - procure_method == 'make_to_stock' 
+    - supply_method == 'buy' 
+-
+  I create a product "Curtain" with type produce_demand
+-
+  !record {model: product.product, id: product2}:
+    name: Curtain
+    type: product
+    procurement_type: produce_demand
+-
+  I check if the product is MTO + produce
+-
+  !assert {model: product.product, id: product2}:
+    - procure_method == 'make_to_order'
+    - supply_method == 'produce'
+
+-
+  I create a product "Curtain2" with type produce_stock
+-
+  !record {model: product.product, id: product3}:
+    name: Curtain2
+    type: product
+    procurement_type: produce_stock
+-
+  I check if the product is MTS + produce
+-
+  !assert {model: product.product, id: product3}:
+    - procure_method == 'make_to_stock' 
+    - supply_method == 'produce'
+
+-
+  I create a product "Store2" with type buy_demand
+-
+  !record {model: product.product, id: product4}:
+    name: Store2
+    type: product
+    procurement_type: buy_demand
+-
+  I check if the product is MTO + buy
+-
+  !assert {model: product.product, id: product4}:
+    - procure_method == 'make_to_order' 
+    - supply_method == 'buy' 

=== added directory 'product_procurement_type_dropshipping'
=== added file 'product_procurement_type_dropshipping/__init__.py'
--- product_procurement_type_dropshipping/__init__.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type_dropshipping/__init__.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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 . import product

=== added file 'product_procurement_type_dropshipping/__openerp__.py'
--- product_procurement_type_dropshipping/__openerp__.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type_dropshipping/__openerp__.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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": "Product Procurement Type Dropshipping",
+    "version": "0.1",
+    "author": "Camptocamp",
+    "license": "AGPL-3",
+    "category": "Sales",
+    "description":
+    """
+    Add a choice named 'dropshipping' in procurement_type selection
+    introduced by product_procurement_type addon.
+    Choose "Dropshipping" changes automatically
+    procurement method as "make to order" and supply method as "buy".
+    It checks if at least one supplier is associated on supplier list
+    in product form.
+
+    """,
+    "website": "http://camptocamp.com";,
+    "depends": ['product_procurement_type',
+                'sale_dropshipping'],
+    "data": ['product_view.xml'],
+    "demo": [],
+    "test": ['test/test_onchange_procurement_type.yml'],
+    "active": False,
+    "installable": True,
+}

=== added file 'product_procurement_type_dropshipping/product.py'
--- product_procurement_type_dropshipping/product.py	1970-01-01 00:00:00 +0000
+++ product_procurement_type_dropshipping/product.py	2014-06-04 22:49:14 +0000
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Romain Deheele
+#    Copyright 2014 Camptocamp SA
+#
+#    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 logging
+
+from openerp.osv import orm, fields
+from openerp.tools.translate import _
+from openerp.addons.product_procurement_type.product import get_procurement_type_selection
+
+_logger = logging.getLogger(__name__)
+def get_procurement_type_selection_with_dropshipping():
+    selections = get_procurement_type_selection()
+    selections.append(('direct_delivery', 'Drop Shipping'))
+    return selections
+
+class product_template(orm.Model):
+
+    _inherit = 'product.template'
+
+    def init(self, cr):
+        _logger.info('Migrating product_procurement_type_dropshipping')
+        query = ("UPDATE product_template AS pt "
+                 "SET procurement_type=%(procurement_type)s "
+                 "FROM product_supplierinfo AS psi "
+                 "WHERE procure_method=%(procure_method)s "
+                 "  AND supply_method=%(supply_method)s "
+                 "  AND psi.product_id = pt.id "
+                 "  AND psi.direct_delivery_flag = true")
+        fixes = [{'procurement_type': 'direct_delivery', 'procure_method': 'make_to_order', 'supply_method': 'buy'},
+                 ]
+        for fix in fixes:
+            cr.execute(query, fix)
+
+
+    def get_procurement_type_selection(self, cr, uid, context=None):
+        """
+        Adds type dropshipping in procurement_type selection
+        """
+        return get_procurement_type_selection_with_dropshipping()
+
+    def _compute_procurement_vals(self, vals):
+        if vals['procurement_type'] == 'direct_delivery':
+            vals.update({'procure_method': 'make_to_order',
+                         'supply_method': 'buy',
+                         })
+        else:
+            vals = super(product_template, self)._compute_procurement_vals(vals)
+        return vals
+
+    def _check_sellers(self, cr, uid, ids, procurement_type, context=None):
+        dd_flag = procurement_type == 'direct_delivery'
+        seller_pool = self.pool['product.supplierinfo']
+        seller_ids = seller_pool.search(cr, uid, [('product_id', 'in', ids)],
+                                        context=context)
+        if seller_ids:
+            seller_pool.write(cr, uid, seller_ids,
+                              {'direct_delivery_flag': dd_flag},
+                              context=context)
+        else:
+            if dd_flag:
+                raise orm.except_orm(
+                    _('Warning'),
+                    _('No suppliers defined'))
+
+    _columns = {
+        'procurement_type': fields.selection(
+            get_procurement_type_selection,
+            'Procurement Type',
+            required=True,
+            help='On stock, buy: Procurement Method: Make to Stock, '
+                 'Supply Method: Buy.\n'
+                 'On stock, produce: Procurement Method: Make to Stock, '
+                 'Supply Method: Produce.\n'
+                 'On order, buy: Procurement Method: Make to Order, '
+                 'Supply Method: Buy.\n'
+                 'On order, produce: Procurement Method: Make to Order, '
+                 'Supply Method: Produce.\n'
+                 'DropShipping: Procurement Method: Make to Order, '
+                 'Supply Method: Buy + supplier does drop shipping'),
+    }
+
+    def onchange_procurement_type(self, cr, uid, ids, type,
+                                  procurement_type, context=None):
+        res = super(product_template, self).\
+            onchange_procurement_type(cr,
+                                      uid,
+                                      ids,
+                                      type,
+                                      procurement_type)
+        if type != 'service':
+            res['value'].update(
+                self._compute_procurement_vals(
+                    {'procurement_type': procurement_type})
+                )
+            self._check_sellers(cr, uid, ids, procurement_type,
+                                context=context)
+        return res
+

=== added file 'product_procurement_type_dropshipping/product_view.xml'
--- product_procurement_type_dropshipping/product_view.xml	1970-01-01 00:00:00 +0000
+++ product_procurement_type_dropshipping/product_view.xml	2014-06-04 22:49:14 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_product_supplier_context_dropshipping" model="ir.ui.view">
+            <field name="name">product.supplier.context.dropshipping</field>
+            <field name="model">product.product</field>
+            <field name="inherit_id" ref="purchase.view_product_supplier_inherit"/>
+            <field name="arch" type="xml">
+                <data>
+                    <field name="seller_ids" position="attributes">
+                     <attribute name="context">{'uom_id': uom_id, 'default_direct_delivery_flag': procurement_type == 'direct_delivery'}</attribute>
+                    </field>
+                </data>
+            </field>
+        </record>
+    </data>
+</openerp>

=== added directory 'product_procurement_type_dropshipping/test'
=== added file 'product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml'
--- product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml	1970-01-01 00:00:00 +0000
+++ product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml	2014-06-04 22:49:14 +0000
@@ -0,0 +1,52 @@
+-
+  Testing change of procurement type on product
+-
+  I create a product "Jalousie"
+-
+  !record {model: product.product, id: product3}:
+    name: Jalousie
+    type: product
+-
+  I define the product with dropshipping
+  but it fails because the product has no suppliers defined.
+-
+  !python {model: product.product}: |
+    from openerp.osv import orm
+    product3_id = ref("product3")
+    try:
+        self.write(cr, uid, [product3_id], {'procurement_type': 'direct_delivery'})
+    except orm.except_orm as err:
+        assert 'Error Expected'
+-
+  I create a supplier "Dupont"
+-
+  !record {model: res.partner, id: partner1}:
+    name: Dupont
+    supplier: True
+-
+  I set this supplier on the product "Jalousie"
+-
+  !record {model: product.supplierinfo, id: psupinfo1}:
+    name: partner1
+    product_id: product3
+    min_qty: 1.0
+-
+  I define dropshipping on the product.
+-
+  !python {model: product.product}: |
+    product3_id = ref("product3")
+    try:
+        values = self.onchange_procurement_type(cr, uid, [product3_id], 'product', 'direct_delivery')
+        self.write(cr, uid, [product3_id], values['value'])
+    except:
+        raise AssertionError('Expected no error')
+-
+  I check if the product is now made to order
+-
+  !assert {model: product.product, id: product3}:
+    - procure_method == 'make_to_order'
+-
+  I check if supplier is checked as doing dropshipping
+-
+  !assert {model: product.supplierinfo, id: psupinfo1}:
+    - direct_delivery_flag == 1
\ No newline at end of file


References