Merge lp:~lin-yu/purchase-wkfl/add_purchase_price_list into lp:~purchase-core-editors/purchase-wkfl/7.0

Proposed by LIN Yu
Status: Work in progress
Proposed branch: lp:~lin-yu/purchase-wkfl/add_purchase_price_list
Merge into: lp:~purchase-core-editors/purchase-wkfl/7.0
Diff against target: 518 lines (+488/-0)
5 files modified
purchase_price_list_item/__init__.py (+23/-0)
purchase_price_list_item/__openerp__.py (+52/-0)
purchase_price_list_item/i18n/purchase_price_list_item.po (+33/-0)
purchase_price_list_item/purchase.py (+332/-0)
purchase_price_list_item/purchase_view.xml (+48/-0)
To merge this branch: bzr merge lp:~lin-yu/purchase-wkfl/add_purchase_price_list
Reviewer Review Type Date Requested Status
Pedro Manuel Baeza Needs Resubmitting
Joël Grand-Guillaume @ camptocamp code review, no tests Disapprove
Maxime Chambreuil (http://www.savoirfairelinux.com) code review Needs Fixing
Review via email: mp+180796@code.launchpad.net

Description of the change

[ADD] purchase_price_list_item

Improve purchase price managment
================================

    * In Purchase List Item, the price is fixed based on price_surchage if base is 'fixed on UOP'
    * If 'fixed on UOP', if product UOP change, the price list price will be change automtically.
    * Add field 'Qty on Hand', and 'Stock Values' for product
    * Add field 'Qty on Hand', 'Stock Values', UOP in product list view

To post a comment you must log in.
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

Thanks for your contribution Yu.

l163: please use orm.Model instead of osv.osv. Update the import accordingly.
l208, 463: no need to instantiate
l417: 2 lines are enough to comply with PEP8. Run flake8 to check for PEP8 issues

review: Needs Fixing (code review)
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Hi Lin,

Thanks for this contribs ! Do you really need to override the whole function "price_get_multi" without calling super() ?

This can lead in very unexpected result so for now I marks it as Disapprove for that reason. Other module that may override this method can face trouble due to that...

Thanks for your understanding or explanation if I do missed something !

Regards,

review: Disapprove (code review, no tests)
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

This project is now hosted on https://github.com/OCA/purchase-workflow. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

review: Needs Resubmitting

Unmerged revisions

16. By LIN Yu

[ADD] module purchase_price_list_item

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'purchase_price_list_item'
2=== added file 'purchase_price_list_item/__init__.py'
3--- purchase_price_list_item/__init__.py 1970-01-01 00:00:00 +0000
4+++ purchase_price_list_item/__init__.py 2013-08-19 07:32:33 +0000
5@@ -0,0 +1,23 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# OpenERP, Open Source Management Solution
10+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
11+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
12+#
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU Affero General Public License as
15+# published by the Free Software Foundation, either version 3 of the
16+# License, or (at your option) any later version.
17+#
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU Affero General Public License for more details.
22+#
23+# You should have received a copy of the GNU Affero General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+#
26+##############################################################################
27+
28+import purchase
29\ No newline at end of file
30
31=== added file 'purchase_price_list_item/__openerp__.py'
32--- purchase_price_list_item/__openerp__.py 1970-01-01 00:00:00 +0000
33+++ purchase_price_list_item/__openerp__.py 2013-08-19 07:32:33 +0000
34@@ -0,0 +1,52 @@
35+# -*- coding: utf-8 -*-
36+##############################################################################
37+#
38+# OpenERP, Open Source Management Solution
39+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
40+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
41+# Andy LU<andy.lu@elico-corp.com>
42+#
43+# This program is free software: you can redistribute it and/or modify
44+# it under the terms of the GNU Affero General Public License as
45+# published by the Free Software Foundation, either version 3 of the
46+# License, or (at your option) any later version.
47+#
48+# This program is distributed in the hope that it will be useful,
49+# but WITHOUT ANY WARRANTY; without even the implied warranty of
50+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51+# GNU Affero General Public License for more details.
52+#
53+# You should have received a copy of the GNU Affero General Public License
54+# along with this program. If not, see <http://www.gnu.org/licenses/>.
55+#
56+##############################################################################
57+
58+{
59+ 'name': 'Purchase Price List Item',
60+ 'version': '1.0',
61+ 'category': 'Purchase',
62+ 'sequence': 19,
63+ 'summary': 'Purchase Price List Item',
64+ 'description': """
65+Improve purchase price managment
66+================================
67+
68+ * In Purchase List Item, the price is fixed based on price_surchage if base is 'fixed on UOP'
69+ * If 'fixed on UOP', if product UOP change, the price list price will be change automtically.
70+ * Add field 'Qty on Hand', and 'Stock Values' for product
71+ * Add field 'Qty on Hand', 'Stock Values', UOP in product list view
72+
73+ """,
74+ 'author': 'Elico Corp',
75+ 'website': 'http://www.elico-corp.com',
76+ 'images' : [],
77+ 'depends': ['purchase'],
78+ 'data': [
79+ 'purchase_view.xml',
80+ ],
81+ 'test': [],
82+ 'demo': [],
83+ 'installable': True,
84+ 'auto_install': False,
85+ 'application': False,
86+}
87\ No newline at end of file
88
89=== added directory 'purchase_price_list_item/i18n'
90=== added file 'purchase_price_list_item/i18n/purchase_price_list_item.po'
91--- purchase_price_list_item/i18n/purchase_price_list_item.po 1970-01-01 00:00:00 +0000
92+++ purchase_price_list_item/i18n/purchase_price_list_item.po 2013-08-19 07:32:33 +0000
93@@ -0,0 +1,33 @@
94+# Translation of OpenERP Server.
95+# This file contains the translation of the following modules:
96+# * purchase_price_list_item
97+#
98+msgid ""
99+msgstr ""
100+"Project-Id-Version: OpenERP Server 7.0\n"
101+"Report-Msgid-Bugs-To: \n"
102+"POT-Creation-Date: 2013-08-14 09:03+0000\n"
103+"PO-Revision-Date: 2013-08-14 09:03+0000\n"
104+"Last-Translator: <>\n"
105+"Language-Team: \n"
106+"MIME-Version: 1.0\n"
107+"Content-Type: text/plain; charset=UTF-8\n"
108+"Content-Transfer-Encoding: \n"
109+"Plural-Forms: \n"
110+
111+#. module: purchase_price_list_item
112+#: code:addons/purchase_price_list_item/purchase.py:34
113+#, python-format
114+msgid "Fix Price based on UoP"
115+msgstr ""
116+
117+#. module: purchase_price_list_item
118+#: model:ir.model,name:purchase_price_list_item.model_product_pricelist_item
119+msgid "Pricelist item"
120+msgstr ""
121+
122+#. module: purchase_price_list_item
123+#: field:product.pricelist.item,uom_id:0
124+msgid "UoM for Fix Price"
125+msgstr ""
126+
127
128=== added file 'purchase_price_list_item/purchase.py'
129--- purchase_price_list_item/purchase.py 1970-01-01 00:00:00 +0000
130+++ purchase_price_list_item/purchase.py 2013-08-19 07:32:33 +0000
131@@ -0,0 +1,332 @@
132+# -*- coding: utf-8 -*-
133+##############################################################################
134+#
135+# OpenERP, Open Source Management Solution
136+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
137+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
138+#
139+# This program is free software: you can redistribute it and/or modify
140+# it under the terms of the GNU Affero General Public License as
141+# published by the Free Software Foundation, either version 3 of the
142+# License, or (at your option) any later version.
143+#
144+# This program is distributed in the hope that it will be useful,
145+# but WITHOUT ANY WARRANTY; without even the implied warranty of
146+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147+# GNU Affero General Public License for more details.
148+#
149+# You should have received a copy of the GNU Affero General Public License
150+# along with this program. If not, see <http://www.gnu.org/licenses/>.
151+#
152+##############################################################################
153+
154+from osv import osv, fields
155+from tools.translate import _
156+
157+import openerp.addons.decimal_precision as dp
158+
159+import time
160+from product._common import rounding
161+
162+
163+class product_pricelist_item(osv.osv):
164+ _inherit = "product.pricelist.item"
165+
166+ def _price_field_get(self, cr, uid, context=None):
167+ result = super(product_pricelist_item, self)._price_field_get(cr, uid, context=context)
168+
169+ result.append((-3, _('Fix Price based on UoP')))
170+ return result
171+
172+ _columns = {
173+ 'base': fields.selection(_price_field_get, 'Based on',required=True, size=-1, help="Base price for computation."),
174+ 'uom_id': fields.many2one('product.uom','UoM for Fix Price',store=True),
175+ }
176+ _defaults = {
177+ 'price_discount': lambda *a: -1,
178+ 'base': lambda *a: -3,
179+ }
180+
181+ def product_id_change(self,cr,uid,ids,product_id,context=None):
182+ if not product_id:
183+ return{}
184+ prod = self.pool.get('product.product').browse(cr,uid,product_id,context=context)
185+
186+ if prod.default_code:
187+ return {'value': {'name': prod.default_code,'uom_id': prod.uom_po_id.id}}
188+ return{}
189+
190+ def create(self,cr,uid,vals,context=None):
191+ if not vals.get('uom_id',False) and vals.get('product_id', False) and vals.get('base',False) == -3:
192+ prod = self.pool.get('product.product').browse(cr,uid,vals.get('product_id',False),context=context)
193+ vals['uom_id'] = prod.uom_po_id.id
194+
195+ return super(product_pricelist_item,self).create(cr,uid,vals,context=context)
196+
197+ def write(self, cr, uid, ids, vals, context=None):
198+ if type(ids) != type([]):
199+ ids = [ids]
200+ if not vals.get('uom_id', False) and ids:
201+ pl_item_obj = self.pool.get('product.pricelist.item')
202+ for id in ids:
203+ item = pl_item_obj.browse(cr, uid, id, context=context)
204+ if item.base == -3 and item.product_id:
205+ vals['uom_id'] = item.product_id.uom_po_id.id
206+ return super(product_pricelist_item, self).write(cr, uid, ids, vals, context=context)
207+
208+product_pricelist_item()
209+
210+
211+class product_pricelist(osv.osv):
212+ _inherit = "product.pricelist"
213+
214+ #def price_get_multi(self, cr, uid, product_ids, context=None):
215+ def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None):
216+ """multi products 'price_get'.
217+ @param pricelist_ids:
218+ @param products_by_qty:
219+ @param partner:
220+ @param context: {
221+ 'date': Date of the pricelist (%Y-%m-%d),}
222+ @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value
223+ """
224+
225+ def _create_parent_category_list(id, lst):
226+ if not id:
227+ return []
228+ parent = product_category_tree.get(id)
229+ if parent:
230+ lst.append(parent)
231+ return _create_parent_category_list(parent, lst)
232+ else:
233+ return lst
234+ # _create_parent_category_list
235+
236+ if context is None:
237+ context = {}
238+
239+ date = time.strftime('%Y-%m-%d')
240+ if 'date' in context:
241+ date = context['date']
242+
243+ currency_obj = self.pool.get('res.currency')
244+ product_obj = self.pool.get('product.product')
245+ product_category_obj = self.pool.get('product.category')
246+ product_uom_obj = self.pool.get('product.uom')
247+ supplierinfo_obj = self.pool.get('product.supplierinfo')
248+ price_type_obj = self.pool.get('product.price.type')
249+
250+ # product.pricelist.version:
251+ if not pricelist_ids:
252+ pricelist_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)
253+
254+ pricelist_version_ids = self.pool.get('product.pricelist.version').search(cr, uid, [
255+ ('pricelist_id', 'in', pricelist_ids),
256+ '|',
257+ ('date_start', '=', False),
258+ ('date_start', '<=', date),
259+ '|',
260+ ('date_end', '=', False),
261+ ('date_end', '>=', date),
262+ ])
263+ if len(pricelist_ids) != len(pricelist_version_ids):
264+ raise osv.except_osv(_('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one."))
265+
266+ # product.product:
267+ product_ids = [i[0] for i in products_by_qty_by_partner]
268+ #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
269+ products = product_obj.browse(cr, uid, product_ids, context=context)
270+ products_dict = dict([(item.id, item) for item in products])
271+
272+ # product.category:
273+ product_category_ids = product_category_obj.search(cr, uid, [])
274+ product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id'])
275+ product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']])
276+
277+ results = {}
278+ for product_id, qty, partner in products_by_qty_by_partner:
279+ for pricelist_id in pricelist_ids:
280+ price = False
281+
282+ tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False
283+
284+ categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False
285+ categ_ids = _create_parent_category_list(categ_id, [categ_id])
286+ if categ_ids:
287+ categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))'
288+ else:
289+ categ_where = '(categ_id IS NULL)'
290+
291+ if partner:
292+ partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) '
293+ partner_args = (partner, tmpl_id)
294+ else:
295+ partner_where = 'base <> -2 '
296+ partner_args = ()
297+
298+ #And
299+ pl = self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context)
300+ if pl.type == "purchase":
301+ product = products_dict[product_id]
302+ if 'uom' in context:
303+ uom = product.uom_po_id
304+ if uom.id != context['uom']:
305+ qty = qty * product.uom_po_id.factor / product.uom_id.factor
306+
307+ cr.execute(
308+ 'SELECT i.*, pl.currency_id '
309+ 'FROM product_pricelist_item AS i, '
310+ 'product_pricelist_version AS v, product_pricelist AS pl '
311+ 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
312+ 'AND (product_id IS NULL OR product_id = %s) '
313+ 'AND (' + categ_where + ' OR (categ_id IS NULL)) '
314+ 'AND (' + partner_where + ') '
315+ 'AND price_version_id = %s '
316+ 'AND (min_quantity IS NULL OR min_quantity <= %s) '
317+ 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
318+ 'ORDER BY sequence',
319+ (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty))
320+ res1 = cr.dictfetchall()
321+ uom_price_already_computed = False
322+ for res in res1:
323+ if res:
324+ if res['base'] == -1:
325+ if not res['base_pricelist_id']:
326+ price = 0.0
327+ else:
328+ price_tmp = self.price_get(cr, uid,
329+ [res['base_pricelist_id']], product_id,
330+ qty, context=context)[res['base_pricelist_id']]
331+ ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id
332+ uom_price_already_computed = True
333+ price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False)
334+ elif res['base'] == -2:
335+ # this section could be improved by moving the queries outside the loop:
336+ where = []
337+ if partner:
338+ where = [('name', '=', partner) ]
339+ sinfo = supplierinfo_obj.search(cr, uid,
340+ [('product_id', '=', tmpl_id)] + where)
341+ price = 0.0
342+ if sinfo:
343+ qty_in_product_uom = qty
344+ product_default_uom = product_obj.read(cr, uid, [product_id], ['uom_id'])[0]['uom_id'][0]
345+ supplier = supplierinfo_obj.browse(cr, uid, sinfo, context=context)[0]
346+ seller_uom = supplier.product_uom and supplier.product_uom.id or False
347+ if seller_uom and product_default_uom and product_default_uom != seller_uom:
348+ uom_price_already_computed = True
349+ qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom)
350+ cr.execute('SELECT * ' \
351+ 'FROM pricelist_partnerinfo ' \
352+ 'WHERE suppinfo_id IN %s' \
353+ 'AND min_quantity <= %s ' \
354+ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,))
355+ res2 = cr.dictfetchone()
356+ if res2:
357+ price = res2['price']
358+ #Add by Andy
359+ elif res['base'] == -3:
360+ price = False
361+ else:
362+ price_type = price_type_obj.browse(cr, uid, int(res['base']))
363+ uom_price_already_computed = True
364+ price = currency_obj.compute(cr, uid,
365+ price_type.currency_id.id, res['currency_id'],
366+ product_obj.price_get(cr, uid, [product_id],
367+ price_type.field, context=context)[product_id], round=False, context=context)
368+
369+ if price is not False:
370+ price_limit = price
371+ price = price * (1.0 + (res['price_discount'] or 0.0))
372+ price = rounding(price, res['price_round']) #TOFIX: rounding with tools.float_rouding
373+ price += (res['price_surcharge'] or 0.0)
374+ if res['price_min_margin']:
375+ price = max(price, price_limit + res['price_min_margin'])
376+ if res['price_max_margin']:
377+ price = min(price, price_limit + res['price_max_margin'])
378+ break
379+ #Add by Andy
380+ else:
381+ if res['base'] == -3:
382+ price = res['price_surcharge'] or 0.0
383+ product = products_dict[product_id]
384+ if 'uom' in context:
385+ uom = product.uom_po_id
386+ if uom.id != context['uom']:
387+ price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
388+ uom_price_already_computed = True
389+ #Todo: # Use company currency?
390+ if 'currency_id' in context:
391+ price = currency_obj.compute(cr, uid, 1,
392+ context['currency_id'], price, context=context)
393+ if price:
394+ break
395+ else:
396+ # False means no valid line found ! But we may not raise an
397+ # exception here because it breaks the search
398+ price = False
399+
400+ if price:
401+ results['item_id'] = res['id']
402+ if 'uom' in context and not uom_price_already_computed:
403+ product = products_dict[product_id]
404+ uom = product.uos_id or product.uom_id
405+ price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
406+
407+ if results.get(product_id):
408+ results[product_id][pricelist_id] = price
409+ else:
410+ results[product_id] = {pricelist_id: price}
411+
412+ return results
413+
414+product_pricelist()
415+
416+
417+
418+class product_product(osv.osv):
419+ _name = "product.product"
420+ _inherit = "product.product"
421+
422+ def _qty_uop(self, cr, uid, ids, name, arg, context=None):
423+ res = {}
424+
425+ uom_obj = self.pool.get('product.uom')
426+ for id in ids:
427+ res.setdefault(id, 0.0)
428+ for product in self.browse(cr, uid, ids):
429+ res[product.id] = uom_obj._compute_qty(cr, uid, product.uom_id.id, product.qty_available, product.uom_po_id.id)
430+ return res
431+
432+ def _amount_uom(self, cr, uid, ids, name, arg, context=None):
433+ res = {}
434+
435+ for id in ids:
436+ res.setdefault(id, 0.0)
437+ for product in self.browse(cr, uid, ids):
438+ res[product.id] = product.qty_available * product.standard_price
439+ return res
440+
441+ _columns = {
442+ #'price_uop': fields.float('Purchase Price(UoP)', digits_compute=dp.get_precision('Product Price')),
443+ 'qty_uop': fields.function(_qty_uop, type='float', string='Qty on Hand (UoP)', digits_compute=dp.get_precision('Product Unit of Measure')),
444+ 'amount_uom': fields.function(_amount_uom, type='float', string='Stock Values', digits_compute=dp.get_precision('Account')),
445+ }
446+
447+ def write(self, cr, uid, ids, vals, context=None):
448+ if type(ids) != type([]):
449+ ids = [ids]
450+ if vals.get('uom_po_id', False) and ids:
451+ uom_obj = self.pool.get('product.uom')
452+ uop = uom_obj.browse(cr, uid, vals.get('uom_po_id', False), context=context)
453+ pl_item_obj = self.pool.get('product.pricelist.item')
454+ pl_ids = pl_item_obj.search(cr, uid, [('product_id', '=', ids[0]), ('base', '=', -3)], context=context)
455+ for item in pl_item_obj.browse(cr, uid, pl_ids, context=context):
456+ if item.uom_id and uop.id == item.uom_id.id:
457+ continue
458+ new_price = item.price_surcharge / uop.factor * item.uom_id.factor
459+ pl_item_obj.write(cr, uid, [item.id], {'uom_id': vals.get('uom_po_id', False), 'price_surcharge': new_price})
460+
461+ return super(product_product, self).write(cr, uid, ids, vals, context=context)
462+
463+product_product()
464\ No newline at end of file
465
466=== added file 'purchase_price_list_item/purchase_view.xml'
467--- purchase_price_list_item/purchase_view.xml 1970-01-01 00:00:00 +0000
468+++ purchase_price_list_item/purchase_view.xml 2013-08-19 07:32:33 +0000
469@@ -0,0 +1,48 @@
470+<?xml version="1.0" encoding="UTF-8" ?>
471+<openerp>
472+ <data>
473+
474+ <record id="product_pricelist_item_list_view_FC" model="ir.ui.view">
475+ <field name="name">product.pricelist.item.list.FC</field>
476+ <field name="model">product.pricelist.item</field>
477+ <field name="inherit_id" ref="product.product_pricelist_item_tree_view" />
478+ <field name="arch" type="xml">
479+ <xpath expr="//field[@name='categ_id']" position="before">
480+ <field name="price_surcharge" attrs="{'invisible':[('base', '!=', -3)]}"/>
481+ <field name="uom_id" attrs="{'invisible':[('base', '!=', -3)],'readonly':1}"/>
482+ </xpath>
483+ </field>
484+ </record>
485+
486+ <record id="product_pricelist_item_form_view_FC" model="ir.ui.view">
487+ <field name="name">product.pricelist.item.form.FC</field>
488+ <field name="model">product.pricelist.item</field>
489+ <field name="type">form</field>
490+ <field name="inherit_id" ref="product.product_pricelist_item_form_view" />
491+ <field name="arch" type="xml">
492+ <xpath expr="//field[@name='product_id']" position="replace">
493+ <field name="product_id" on_change="product_id_change(product_id)" attrs="{'required': [('base','=', -3)]}"/>
494+ <field name="uom_id" attrs="{'invisible':[('base', '!=', -3)],'readonly':1}"/>
495+ </xpath>
496+ </field>
497+ </record>
498+
499+ <record id="product_product_tree_view_uop" model="ir.ui.view">
500+ <field name="name">product.product.tree.uop</field>
501+ <field name="model">product.product</field>
502+ <field name="type">form</field>
503+ <field name="inherit_id" ref="product.product_product_tree_view" />
504+ <field name="arch" type="xml">
505+ <xpath expr="//field[@name='state']" position="before">
506+ <field name="qty_uop"/>
507+ <field name="uom_po_id"/>
508+ </xpath>
509+ <xpath expr="//field[@name='standard_price']" position="replace">
510+ <field name="standard_price"/>
511+ <field name="amount_uom"/>
512+ </xpath>
513+ </field>
514+ </record>
515+
516+ </data>
517+</openerp>
518\ No newline at end of file

Subscribers

People subscribed via source and target branches