Merge lp:~jean-lelievre/purchase-wkfl/new_modules_purchase into lp:~purchase-core-editors/purchase-wkfl/7.0

Proposed by Jean LELIEVRE ElicoCorp
Status: Superseded
Proposed branch: lp:~jean-lelievre/purchase-wkfl/new_modules_purchase
Merge into: lp:~purchase-core-editors/purchase-wkfl/7.0
Diff against target: 1618 lines (+1475/-0)
24 files modified
product_supplier_info/__init__.py (+23/-0)
product_supplier_info/__openerp__.py (+47/-0)
product_supplier_info/product.py (+54/-0)
product_supplier_info/product_view.xml (+71/-0)
purchase_contacts/__init__.py (+25/-0)
purchase_contacts/__openerp__.py (+51/-0)
purchase_contacts/i18n/zh_CN.po (+42/-0)
purchase_contacts/purchase.py (+90/-0)
purchase_contacts/purchase_view.xml (+54/-0)
purchase_control_supplier/__init__.py (+25/-0)
purchase_control_supplier/__openerp__.py (+46/-0)
purchase_control_supplier/i18n/zh_CN.po (+37/-0)
purchase_control_supplier/purchase.py (+53/-0)
purchase_control_supplier/purchase_view.xml (+34/-0)
purchase_po_price/__init__.py (+23/-0)
purchase_po_price/__openerp__.py (+42/-0)
purchase_po_price/i18n/zh_CN.po (+89/-0)
purchase_po_price/purchase.py (+113/-0)
purchase_po_price/purchase_view.xml (+68/-0)
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:~jean-lelievre/purchase-wkfl/new_modules_purchase
Reviewer Review Type Date Requested Status
Purchase Core Editors Pending
Review via email: mp+179669@code.launchpad.net

This proposal has been superseded by a proposal from 2013-08-16.

Description of the change

Add module :
- purchase_contacts : Add contact person and delivery person in purchase

To post a comment you must log in.
17. By Jean LELIEVRE ElicoCorp

[ADD] purchase_control_supplier, purchase_po_price, purchase_price_list_item

Unmerged revisions

17. By Jean LELIEVRE ElicoCorp

[ADD] purchase_control_supplier, purchase_po_price, purchase_price_list_item

16. By Jean LELIEVRE ElicoCorp

Add contact person and delivery person in Purchase

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'product_supplier_info'
2=== added file 'product_supplier_info/__init__.py'
3--- product_supplier_info/__init__.py 1970-01-01 00:00:00 +0000
4+++ product_supplier_info/__init__.py 2013-08-16 03:22:06 +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: Yannick Gouin <yannick.gouin@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+import product
28+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
29\ No newline at end of file
30
31=== added file 'product_supplier_info/__openerp__.py'
32--- product_supplier_info/__openerp__.py 1970-01-01 00:00:00 +0000
33+++ product_supplier_info/__openerp__.py 2013-08-16 03:22:06 +0000
34@@ -0,0 +1,47 @@
35+# -*- coding: utf-8 -*-
36+##############################################################################
37+#
38+# OpenERP, Open Source Management Solution
39+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
40+# Author: LIN Yu <lin.yu@elico-corp.com>
41+#
42+# This program is free software: you can redistribute it and/or modify
43+# it under the terms of the GNU Affero General Public License as
44+# published by the Free Software Foundation, either version 3 of the
45+# License, or (at your option) any later version.
46+#
47+# This program is distributed in the hope that it will be useful,
48+# but WITHOUT ANY WARRANTY; without even the implied warranty of
49+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+# GNU Affero General Public License for more details.
51+#
52+# You should have received a copy of the GNU Affero General Public License
53+# along with this program. If not, see <http://www.gnu.org/licenses/>.
54+#
55+##############################################################################
56+
57+{
58+ 'name': 'Product Supplier Info',
59+ 'version': '1.0',
60+ 'category': 'purchase',
61+ 'sequence': 19,
62+ 'summary': 'Product Supplier Info',
63+ 'description': """
64+Add a specific View for Supplier
65+==================================================
66+ """,
67+ 'author': 'Elico Corp',
68+ 'website': 'http://www.elico-corp.com',
69+ 'images' : [],
70+ 'depends': ['product','stock'],#TO REMOVE joomlaconnector for standard
71+ 'data': [
72+ 'product_view.xml',
73+ ],
74+ 'test': [],
75+ 'demo': [],
76+ 'installable': True,
77+ 'auto_install': False,
78+ 'application': False,
79+}
80+
81+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
82\ No newline at end of file
83
84=== added file 'product_supplier_info/product.py'
85--- product_supplier_info/product.py 1970-01-01 00:00:00 +0000
86+++ product_supplier_info/product.py 2013-08-16 03:22:06 +0000
87@@ -0,0 +1,54 @@
88+# -*- coding: utf-8 -*-
89+##############################################################################
90+#
91+# OpenERP, Open Source Management Solution
92+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
93+# Author: Yannick Gouin <yannick.gouin@elico-corp.com>
94+#
95+# This program is free software: you can redistribute it and/or modify
96+# it under the terms of the GNU Affero General Public License as
97+# published by the Free Software Foundation, either version 3 of the
98+# License, or (at your option) any later version.
99+#
100+# This program is distributed in the hope that it wil l be useful,
101+# but WITHOUT ANY WARRANTY; without even the implied warranty of
102+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
103+# GNU Affero General Public License for more details.
104+#
105+# You should have received a copy of the GNU Affero General Public License
106+# along with this program. If not, see <http://www.gnu.org/licenses/>.
107+#
108+##############################################################################
109+
110+from osv import osv, fields
111+from openerp import tools
112+from tools.translate import _
113+import openerp.addons.decimal_precision as dp
114+
115+class product_supplierinfo(osv.osv):
116+ _inherit = 'product.supplierinfo'
117+
118+ def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None):
119+ if not field_names:
120+ field_names = []
121+ if context is None:
122+ context = {}
123+ res = {}
124+ for id in ids:
125+ res[id] = {}.fromkeys(field_names, 0.0)
126+ supplier_info = self.browse(cr, uid, id)
127+ for f in field_names:
128+ if f == 'qty_available':
129+ res[id][f] = supplier_info.product_id.qty_available
130+ if f == 'virtual_available':
131+ res[id][f] = supplier_info.product_id.virtual_available
132+ return res
133+
134+ _columns={
135+ 'product_id' : fields.many2one('product.product', 'Product', select=1, ondelete='cascade', required=True),
136+ 'qty_available' : fields.function(_product_available,multi='qty_available',type='float',digits_compute=dp.get_precision('Product Unit of Measure'),string="Quantity On Hand"),
137+ 'virtual_available' : fields.function(_product_available,multi='qty_available',type='float', digits_compute=dp.get_precision('Product Unit of Measure'),string="Forecasted Quantity"),
138+ }
139+product_supplierinfo()
140+
141+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
142
143=== added file 'product_supplier_info/product_view.xml'
144--- product_supplier_info/product_view.xml 1970-01-01 00:00:00 +0000
145+++ product_supplier_info/product_view.xml 2013-08-16 03:22:06 +0000
146@@ -0,0 +1,71 @@
147+<?xml version="1.0" encoding="UTF-8"?>
148+<openerp>
149+ <data>
150+
151+ <record id="view_product_supplierinfo_search" model="ir.ui.view">
152+ <field name="name">product.supplierinfo.search</field>
153+ <field name="model">product.supplierinfo</field>
154+ <field name="arch" type="xml">
155+ <search string="Product Supplier Info">
156+ <field name="name" string="Supplier"/>
157+ <field name="product_code" string="Supplier Product Code"/>
158+ <field name="product_name" string="Supplier Product Code"/>
159+ <field name="product_id" />
160+ <group expand='1' string='Group by...' groups="base.group_extended">
161+ <filter string='Product Code' name='supplier_code' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'product_code'}" />
162+ <filter string='Product' name='product' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'product_id'}" />
163+ <filter string='Supplier' name='supplier' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'name'}" />
164+ </group>
165+ </search>
166+ </field>
167+ </record>
168+
169+ <record id="view_product_supplierinfo_tree1" model="ir.ui.view">
170+ <field name="name">product.supplierinfo.tree1</field>
171+ <field name="model">product.supplierinfo</field>
172+ <field name="arch" type="xml">
173+ <tree string="Supplier Information" editable="top">
174+ <field name="sequence" widget="handle"/>
175+ <field name="product_code" string="Supplier Product Code"/>
176+ <field name="product_id" string="Product Name"/>
177+ <field name="product_name" string="Supplier Product Name"/>
178+ <field name="name"/>
179+ <field name="delay"/>
180+ <field name="qty_available"/>
181+ <field name="virtual_available"/>
182+ <field name="min_qty"/>
183+ <field name="company_id" groups="base.group_multi_company" widget="selection"/>
184+ </tree>
185+ </field>
186+ </record>
187+ <record id="view_product_supplierinfo_from1" model="ir.ui.view">
188+ <field name="name">product.supplierinfo.from1</field>
189+ <field name="model">product.supplierinfo</field>
190+ <field name="inherit_id" ref="product.product_supplierinfo_form_view"/>
191+ <field name="arch" type="xml">
192+ <xpath expr="//field[@name='sequence']" position="before">
193+ <field name="product_id"/>
194+ </xpath>
195+ </field>
196+ </record>
197+
198+
199+ <record id="action_product_supplier_info" model="ir.actions.act_window">
200+ <field name="name">Product Supplier Info</field>
201+ <field name="res_model">product.supplierinfo</field>
202+ <field name="type">ir.actions.act_window</field>
203+ <field name="view_type">form</field>
204+ <field name="view_mode">tree,form</field>
205+ <field name="view_id" ref="view_product_supplierinfo_tree1"/>
206+ <field name="search_view_id" ref="view_product_supplierinfo_search"/>
207+ <field name="context">{'search_default_supplier':1,'group_by':[]}</field>
208+ </record>
209+
210+ <menuitem
211+ id="menu_product_supplier_info"
212+ name="Product Suppliers"
213+ sequence="15"
214+ action="action_product_supplier_info"
215+ parent="purchase.menu_procurement_management_product"/>
216+ </data>
217+</openerp>
218
219=== added directory 'purchase_contacts'
220=== added file 'purchase_contacts/__init__.py'
221--- purchase_contacts/__init__.py 1970-01-01 00:00:00 +0000
222+++ purchase_contacts/__init__.py 2013-08-16 03:22:06 +0000
223@@ -0,0 +1,25 @@
224+# -*- coding: utf-8 -*-
225+##############################################################################
226+#
227+# OpenERP, Open Source Management Solution
228+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
229+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
230+#
231+# This program is free software: you can redistribute it and/or modify
232+# it under the terms of the GNU Affero General Public License as
233+# published by the Free Software Foundation, either version 3 of the
234+# License, or (at your option) any later version.
235+#
236+# This program is distributed in the hope that it will be useful,
237+# but WITHOUT ANY WARRANTY; without even the implied warranty of
238+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
239+# GNU Affero General Public License for more details.
240+#
241+# You should have received a copy of the GNU Affero General Public License
242+# along with this program. If not, see <http://www.gnu.org/licenses/>.
243+#
244+##############################################################################
245+
246+import purchase
247+
248+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
249\ No newline at end of file
250
251=== added file 'purchase_contacts/__openerp__.py'
252--- purchase_contacts/__openerp__.py 1970-01-01 00:00:00 +0000
253+++ purchase_contacts/__openerp__.py 2013-08-16 03:22:06 +0000
254@@ -0,0 +1,51 @@
255+# -*- coding: utf-8 -*-
256+##############################################################################
257+#
258+# OpenERP, Open Source Management Solution
259+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
260+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
261+#
262+# This program is free software: you can redistribute it and/or modify
263+# it under the terms of the GNU Affero General Public License as
264+# published by the Free Software Foundation, either version 3 of the
265+# License, or (at your option) any later version.
266+#
267+# This program is distributed in the hope that it will be useful,
268+# but WITHOUT ANY WARRANTY; without even the implied warranty of
269+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
270+# GNU Affero General Public License for more details.
271+#
272+# You should have received a copy of the GNU Affero General Public License
273+# along with this program. If not, see <http://www.gnu.org/licenses/>.
274+#
275+##############################################################################
276+
277+{
278+ 'name': 'Purchase Contacts',
279+ 'version': '1.0',
280+ 'category': 'Purchase',
281+ 'sequence': 19,
282+ 'summary': 'Enables the Supplier Contact and Delivery Contact fields in the Purchase module',
283+ 'description': """
284+FieldsChina purchase
285+==================================================
286+Fine tune Purchase addon
287+
288+* Add several contact for purchase order of own company, delivery, contact.
289+* Add sequence for partner ref.
290+ """,
291+ 'author': 'Elico Corp',
292+ 'website': 'http://www.elico-corp.com',
293+ 'images' : [],
294+ 'depends': ['purchase'],
295+ 'data': [
296+ 'purchase_view.xml'
297+ ],
298+ 'test': [],
299+ 'demo': [],
300+ 'installable': True,
301+ 'auto_install': False,
302+ 'application': False,
303+}
304+
305+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
306\ No newline at end of file
307
308=== added directory 'purchase_contacts/i18n'
309=== added file 'purchase_contacts/i18n/zh_CN.po'
310--- purchase_contacts/i18n/zh_CN.po 1970-01-01 00:00:00 +0000
311+++ purchase_contacts/i18n/zh_CN.po 2013-08-16 03:22:06 +0000
312@@ -0,0 +1,42 @@
313+# Translation of OpenERP Server.
314+# This file contains the translation of the following modules:
315+# * purchase_contacts
316+#
317+msgid ""
318+msgstr ""
319+"Project-Id-Version: OpenERP Server 7.0\n"
320+"Report-Msgid-Bugs-To: \n"
321+"POT-Creation-Date: 2013-08-14 08:56+0000\n"
322+"PO-Revision-Date: 2013-08-14 08:56+0000\n"
323+"Last-Translator: <>\n"
324+"Language-Team: \n"
325+"MIME-Version: 1.0\n"
326+"Content-Type: text/plain; charset=UTF-8\n"
327+"Content-Transfer-Encoding: \n"
328+"Plural-Forms: \n"
329+
330+#. module: purchase_contacts
331+#: field:purchase.order,delivery_id:0
332+msgid "Delivery"
333+msgstr "收货"
334+
335+#. module: purchase_contacts
336+#: model:ir.model,name:purchase_contacts.model_res_partner
337+msgid "Partner"
338+msgstr "业务伙伴"
339+
340+#. module: purchase_contacts
341+#: field:purchase.order,contact_partner_id:0
342+msgid "Supplier Contact"
343+msgstr "供应商联系人"
344+
345+#. module: purchase_contacts
346+#: field:purchase.order,contact_delivery_id:0
347+msgid "Delivery Contact"
348+msgstr "收货联系"
349+
350+#. module: purchase_contacts
351+#: model:ir.model,name:purchase_contacts.model_purchase_order
352+msgid "Purchase Order"
353+msgstr "采购订单"
354+
355
356=== added file 'purchase_contacts/purchase.py'
357--- purchase_contacts/purchase.py 1970-01-01 00:00:00 +0000
358+++ purchase_contacts/purchase.py 2013-08-16 03:22:06 +0000
359@@ -0,0 +1,90 @@
360+# -*- coding: utf-8 -*-
361+##############################################################################
362+#
363+# OpenERP, Open Source Management Solution
364+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
365+# Author: Yannick Gouin <yannick.gouin@elico-corp.com>
366+# Author: Andy Lu <andy.lu@elico-corp.com>
367+#
368+# This program is free software: you can redistribute it and/or modify
369+# it under the terms of the GNU Affero General Public License as
370+# published by the Free Software Foundation, either version 3 of the
371+# License, or (at your option) any later version.
372+#
373+# This program is distributed in the hope that it will be useful,
374+# but WITHOUT ANY WARRANTY; without even the implied warranty of
375+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
376+# GNU Affero General Public License for more details.
377+#
378+# You should have received a copy of the GNU Affero General Public License
379+# along with this program. If not, see <http://www.gnu.org/licenses/>.
380+#
381+##############################################################################
382+
383+import time
384+from product._common import rounding
385+
386+from osv import osv, fields
387+from tools.translate import _
388+import openerp.addons.decimal_precision as dp
389+import netsvc
390+from openerp.osv.orm import browse_record, browse_null
391+from dateutil.relativedelta import relativedelta
392+import pytz
393+from datetime import datetime
394+import pooler
395+
396+class purchase_order(osv.osv):
397+ _inherit = 'purchase.order'
398+
399+ _columns = {
400+ 'delivery_id':fields.many2one('res.partner', 'Delivery', states={'done':[('readonly', True)]},),
401+ 'contact_delivery_id':fields.many2one('res.partner', 'Delivery Contact', states={'done':[('readonly', True)]}),
402+ 'contact_partner_id':fields.many2one('res.partner', 'Supplier Contact', states={'done':[('readonly', True)]}),
403+ }
404+
405+ def onchange_delivery_id(self, cr, uid, ids, partner_id):
406+ if not partner_id:
407+ return {'value': {
408+ 'contact_delivery_id': False }}
409+
410+ partner = self.pool.get('res.partner')
411+ supplier_address = partner.contact_get(cr, uid, [partner_id], ['default'])
412+ #supplier = partner.browse(cr, uid, partner_id)
413+ return {'value': {
414+ 'contact_delivery_id': supplier_address and supplier_address['default'] or False
415+ }}
416+
417+purchase_order()
418+
419+class res_partner(osv.osv):
420+ _name = "res.partner"
421+ _inherit = "res.partner"
422+
423+ #_sql_constraints = [
424+ # ('ref_uniq', 'unique(ref, company_id)', 'Supplier Reference must be unique per Company!'),
425+ #]
426+
427+ _defaults = {
428+ 'ref': lambda obj, cr, uid, context: '/',
429+ }
430+
431+ def create(self, cr, uid, vals, context=None):
432+ if vals.get('ref', '/') == '/' and vals.get('supplier', False):
433+ # SHOULD USE ir_sequence.next_by_code() or ir_sequence.next_by_id()
434+ vals['ref'] = self.pool.get('ir.sequence').get(cr, uid, 'fake.supplier') or '/'
435+ doc = super(res_partner, self).create(cr, uid, vals, context=context)
436+ return doc
437+
438+ def copy(self, cr, uid, id, default=None, context=None):
439+ if not default:
440+ default = {}
441+ if default.get('supplier', False):
442+ # SHOULD USE ir_sequence.next_by_code() or ir_sequence.next_by_id()
443+ default.update({
444+ 'ref': self.pool.get('ir.sequence').get(cr, uid, 'fake.supplier'),
445+ 'name': default.get('name', '/') + "(copy)",
446+ })
447+ return super(res_partner, self).copy(cr, uid, id, default, context)
448+
449+res_partner()
450\ No newline at end of file
451
452=== added file 'purchase_contacts/purchase_view.xml'
453--- purchase_contacts/purchase_view.xml 1970-01-01 00:00:00 +0000
454+++ purchase_contacts/purchase_view.xml 2013-08-16 03:22:06 +0000
455@@ -0,0 +1,54 @@
456+<?xml version="1.0" encoding="UTF-8"?>
457+<openerp>
458+
459+ <data noupdate="1">
460+ <record id="seq_type_supplier" model="ir.sequence.type">
461+ <field name="name">Supplier</field>
462+ <field name="code">fake.supplier</field>
463+ </record>
464+
465+ <!--Sequences for Delivery Route-->
466+
467+ <record id="seq_delivery_route" model="ir.sequence">
468+ <field name="name">Supplier</field>
469+ <field name="code">fake.supplier</field>
470+ <field name="prefix">C</field>
471+ <field name="padding">5</field>
472+ <field name="company_id" eval="False"/>
473+ </record>
474+ </data>
475+
476+ <data>
477+
478+ <!-- Purchase order -->
479+ <record id="purchase_order_form_fc" model="ir.ui.view">
480+
481+ <field name="name">purchase.order.form_contact</field>
482+ <field name="model">purchase.order</field>
483+ <field name="type">form</field>
484+ <field name="inherit_id" ref="purchase.purchase_order_form"/>
485+
486+ <field name="arch" type="xml">
487+
488+ <xpath expr="/form/sheet/group/group/field[@name='warehouse_id']" position="after">
489+ <field name="delivery_id" on_change="onchange_delivery_id(delivery_id)" attrs="{'required': 1}"/>
490+ </xpath>
491+
492+ <xpath expr="/form/sheet/group/group/field[@name='partner_ref']" position="after">
493+
494+ <field name="contact_delivery_id" domain="[('parent_id','=', delivery_id)]" context="{'show_mobile': 1}" options="{&quot;always_reload&quot;: True}"/>
495+ </xpath>
496+
497+ <xpath expr="/form/sheet/group/group/field[@name='partner_id']" position="replace">
498+
499+ <field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_supplier':1,'default_supplier':1,'default_customer':0,'show_address': 1}" options="{&quot;always_reload&quot;: True}" domain="[('supplier','=',True)]"/>
500+
501+ <field name="contact_partner_id" domain="[('parent_id','=', partner_id)]" context="{'show_mobile': 1}" options="{&quot;always_reload&quot;: True}"/>
502+
503+ </xpath>
504+
505+ </field>
506+ </record>
507+
508+ </data>
509+</openerp>
510
511=== added directory 'purchase_control_supplier'
512=== added file 'purchase_control_supplier/__init__.py'
513--- purchase_control_supplier/__init__.py 1970-01-01 00:00:00 +0000
514+++ purchase_control_supplier/__init__.py 2013-08-16 03:22:06 +0000
515@@ -0,0 +1,25 @@
516+# -*- coding: utf-8 -*-
517+##############################################################################
518+#
519+# OpenERP, Open Source Management Solution
520+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
521+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
522+#
523+# This program is free software: you can redistribute it and/or modify
524+# it under the terms of the GNU Affero General Public License as
525+# published by the Free Software Foundation, either version 3 of the
526+# License, or (at your option) any later version.
527+#
528+# This program is distributed in the hope that it will be useful,
529+# but WITHOUT ANY WARRANTY; without even the implied warranty of
530+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
531+# GNU Affero General Public License for more details.
532+#
533+# You should have received a copy of the GNU Affero General Public License
534+# along with this program. If not, see <http://www.gnu.org/licenses/>.
535+#
536+##############################################################################
537+
538+import purchase
539+
540+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
541\ No newline at end of file
542
543=== added file 'purchase_control_supplier/__openerp__.py'
544--- purchase_control_supplier/__openerp__.py 1970-01-01 00:00:00 +0000
545+++ purchase_control_supplier/__openerp__.py 2013-08-16 03:22:06 +0000
546@@ -0,0 +1,46 @@
547+# -*- coding: utf-8 -*-
548+##############################################################################
549+#
550+# OpenERP, Open Source Management Solution
551+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
552+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
553+#
554+# This program is free software: you can redistribute it and/or modify
555+# it under the terms of the GNU Affero General Public License as
556+# published by the Free Software Foundation, either version 3 of the
557+# License, or (at your option) any later version.
558+#
559+# This program is distributed in the hope that it will be useful,
560+# but WITHOUT ANY WARRANTY; without even the implied warranty of
561+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
562+# GNU Affero General Public License for more details.
563+#
564+# You should have received a copy of the GNU Affero General Public License
565+# along with this program. If not, see <http://www.gnu.org/licenses/>.
566+#
567+##############################################################################
568+
569+{
570+ 'name': 'Purchase Control Supplier',
571+ 'version': '1.0',
572+ 'category': 'Purchase',
573+ 'sequence': 19,
574+ 'summary': 'Purchase Control Supplier',
575+ 'description': """
576+Enables/Disables the supplier control in Purchase.
577+ """,
578+ 'author': 'Elico Corp',
579+ 'website': 'http://www.elico-corp.com',
580+ 'images' : [],
581+ 'depends': ['purchase'],
582+ 'data': [
583+ 'purchase_view.xml',
584+ ],
585+ 'test': [],
586+ 'demo': [],
587+ 'installable': True,
588+ 'auto_install': False,
589+ 'application': False,
590+}
591+
592+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
593\ No newline at end of file
594
595=== added directory 'purchase_control_supplier/i18n'
596=== added file 'purchase_control_supplier/i18n/zh_CN.po'
597--- purchase_control_supplier/i18n/zh_CN.po 1970-01-01 00:00:00 +0000
598+++ purchase_control_supplier/i18n/zh_CN.po 2013-08-16 03:22:06 +0000
599@@ -0,0 +1,37 @@
600+# Translation of OpenERP Server.
601+# This file contains the translation of the following modules:
602+# * purchase_control_supplier
603+#
604+msgid ""
605+msgstr ""
606+"Project-Id-Version: OpenERP Server 7.0\n"
607+"Report-Msgid-Bugs-To: \n"
608+"POT-Creation-Date: 2013-08-14 09:01+0000\n"
609+"PO-Revision-Date: 2013-08-14 09:01+0000\n"
610+"Last-Translator: <>\n"
611+"Language-Team: \n"
612+"MIME-Version: 1.0\n"
613+"Content-Type: text/plain; charset=UTF-8\n"
614+"Content-Transfer-Encoding: \n"
615+"Plural-Forms: \n"
616+
617+#. module: purchase_control_supplier
618+#: field:res.partner,supplier_product_limit:0
619+msgid "Control Supplier Search"
620+msgstr "Control Supplier Search"
621+
622+#. module: purchase_control_supplier
623+#: model:ir.model,name:purchase_control_supplier.model_res_partner
624+msgid "Partner"
625+msgstr "业务伙伴"
626+
627+#. module: purchase_control_supplier
628+#: model:ir.model,name:purchase_control_supplier.model_product_product
629+msgid "Product"
630+msgstr "产品"
631+
632+#. module: purchase_control_supplier
633+#: help:res.partner,supplier_product_limit:0
634+msgid "If checked, allows you to search only the product in this supplier )"
635+msgstr "If checked, allows you to search only the product in this supplier )"
636+
637
638=== added file 'purchase_control_supplier/purchase.py'
639--- purchase_control_supplier/purchase.py 1970-01-01 00:00:00 +0000
640+++ purchase_control_supplier/purchase.py 2013-08-16 03:22:06 +0000
641@@ -0,0 +1,53 @@
642+# -*- coding: utf-8 -*-
643+##############################################################################
644+#
645+# OpenERP, Open Source Management Solution
646+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
647+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
648+#
649+# This program is free software: you can redistribute it and/or modify
650+# it under the terms of the GNU Affero General Public License as
651+# published by the Free Software Foundation, either version 3 of the
652+# License, or (at your option) any later version.
653+#
654+# This program is distributed in the hope that it will be useful,
655+# but WITHOUT ANY WARRANTY; without even the implied warranty of
656+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
657+# GNU Affero General Public License for more details.
658+#
659+# You should have received a copy of the GNU Affero General Public License
660+# along with this program. If not, see <http://www.gnu.org/licenses/>.
661+#
662+##############################################################################
663+
664+from osv import osv, fields
665+
666+class product_product(osv.osv):
667+ _name = "product.product"
668+ _inherit = "product.product"
669+
670+ def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
671+
672+ if context and context.get('supplier_id', False):
673+ product_limit = self.pool.get('res.partner').read(cr,uid,context['supplier_id'],['supplier_product_limit'])['supplier_product_limit']
674+ if product_limit:
675+ # ids = []
676+ cr.execute("SELECT distinct(product_id) FROM product_supplierinfo where name = %s" % (context.get('supplier_id')))
677+ ids = [x[0] for x in cr.fetchall()]
678+ args.append(('id', 'in', ids))
679+ order = 'default_code'
680+ return super(product_product, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
681+
682+product_product()
683+
684+class res_partner(osv.osv):
685+ _name = 'res.partner'
686+ _inherit = 'res.partner'
687+
688+ _columns = {
689+ 'supplier_product_limit':fields.boolean("Control Supplier Search", help="""If checked, allows you to search only the product in this supplier )"""),
690+ }
691+
692+ _defaults = {
693+ 'supplier_product_limit': True,
694+ }
695\ No newline at end of file
696
697=== added file 'purchase_control_supplier/purchase_view.xml'
698--- purchase_control_supplier/purchase_view.xml 1970-01-01 00:00:00 +0000
699+++ purchase_control_supplier/purchase_view.xml 2013-08-16 03:22:06 +0000
700@@ -0,0 +1,34 @@
701+<?xml version="1.0" encoding="UTF-8"?>
702+<openerp>
703+ <data>
704+
705+ <record id="view_partner_form_joomla1" model="ir.ui.view">
706+ <field name="name">res.partner.form.FC</field>
707+ <field name="model">res.partner</field>
708+ <field name="type">form</field>
709+ <field name="inherit_id" ref="base.view_partner_form" />
710+ <field name="arch" type="xml">
711+ <xpath expr="//field[@name='customer']" position="after">
712+ <field name="supplier_product_limit" attrs="{'invisible':[('supplier','!=',True)]}"/>
713+ </xpath>
714+ </field>
715+ </record>
716+
717+
718+
719+ <!-- Purchase Order -->
720+ <record id="purchase_order_form_fc" model="ir.ui.view">
721+ <field name="name">purchase.order.form_FC</field>
722+ <field name="model">purchase.order</field>
723+ <field name="type">form</field>
724+ <field name="inherit_id" ref="purchase.purchase_order_form"/>
725+ <field name="arch" type="xml">
726+ <xpath expr="//field[@name='order_line']/tree/field['product_id']" position="replace">
727+
728+ <field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,0,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)" context="{'supplier_id': parent.partner_id}"/>
729+
730+ </xpath>
731+ </field>
732+ </record>
733+ </data>
734+</openerp>
735
736=== added directory 'purchase_po_price'
737=== added file 'purchase_po_price/__init__.py'
738--- purchase_po_price/__init__.py 1970-01-01 00:00:00 +0000
739+++ purchase_po_price/__init__.py 2013-08-16 03:22:06 +0000
740@@ -0,0 +1,23 @@
741+# -*- coding: utf-8 -*-
742+##############################################################################
743+#
744+# OpenERP, Open Source Management Solution
745+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
746+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
747+#
748+# This program is free software: you can redistribute it and/or modify
749+# it under the terms of the GNU Affero General Public License as
750+# published by the Free Software Foundation, either version 3 of the
751+# License, or (at your option) any later version.
752+#
753+# This program is distributed in the hope that it will be useful,
754+# but WITHOUT ANY WARRANTY; without even the implied warranty of
755+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
756+# GNU Affero General Public License for more details.
757+#
758+# You should have received a copy of the GNU Affero General Public License
759+# along with this program. If not, see <http://www.gnu.org/licenses/>.
760+#
761+##############################################################################
762+
763+import purchase
764\ No newline at end of file
765
766=== added file 'purchase_po_price/__openerp__.py'
767--- purchase_po_price/__openerp__.py 1970-01-01 00:00:00 +0000
768+++ purchase_po_price/__openerp__.py 2013-08-16 03:22:06 +0000
769@@ -0,0 +1,42 @@
770+# -*- coding: utf-8 -*-
771+##############################################################################
772+#
773+# OpenERP, Open Source Management Solution
774+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
775+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
776+#
777+# This program is free software: you can redistribute it and/or modify
778+# it under the terms of the GNU Affero General Public License as
779+# published by the Free Software Foundation, either version 3 of the
780+# License, or (at your option) any later version.
781+#
782+# This program is distributed in the hope that it will be useful,
783+# but WITHOUT ANY WARRANTY; without even the implied warranty of
784+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
785+# GNU Affero General Public License for more details.
786+#
787+# You should have received a copy of the GNU Affero General Public License
788+# along with this program. If not, see <http://www.gnu.org/licenses/>.
789+#
790+##############################################################################
791+
792+{
793+ 'name': 'Purchase PO Price',
794+ 'version': '1.0',
795+ 'category': 'Purchase',
796+ 'sequence': 19,
797+ 'summary': 'Purchase PO Price',
798+ 'description': """ Enable/Disable control on PO Price """,
799+ 'author': 'Elico Corp',
800+ 'website': 'http://www.elico-corp.com',
801+ 'images' : [],
802+ 'depends': ['purchase'],
803+ 'data': [
804+ 'purchase_view.xml',
805+ ],
806+ 'test': [],
807+ 'demo': [],
808+ 'installable': True,
809+ 'auto_install': False,
810+ 'application': False,
811+}
812\ No newline at end of file
813
814=== added directory 'purchase_po_price/i18n'
815=== added file 'purchase_po_price/i18n/zh_CN.po'
816--- purchase_po_price/i18n/zh_CN.po 1970-01-01 00:00:00 +0000
817+++ purchase_po_price/i18n/zh_CN.po 2013-08-16 03:22:06 +0000
818@@ -0,0 +1,89 @@
819+# Translation of OpenERP Server.
820+# This file contains the translation of the following modules:
821+# * purchase_po_price
822+#
823+msgid ""
824+msgstr ""
825+"Project-Id-Version: OpenERP Server 7.0\n"
826+"Report-Msgid-Bugs-To: \n"
827+"POT-Creation-Date: 2013-08-14 09:02+0000\n"
828+"PO-Revision-Date: 2013-08-14 09:02+0000\n"
829+"Last-Translator: <>\n"
830+"Language-Team: \n"
831+"MIME-Version: 1.0\n"
832+"Content-Type: text/plain; charset=UTF-8\n"
833+"Content-Transfer-Encoding: \n"
834+"Plural-Forms: \n"
835+
836+#. module: purchase_po_price
837+#: code:addons/purchase_po_price/purchase.py:105
838+#, python-format
839+msgid "You can not modify the price of this product sold by this supplier !"
840+msgstr "You can not modify the price of this product sold by this supplier !"
841+
842+#. module: purchase_po_price
843+#: model:ir.model,name:purchase_po_price.model_purchase_order_line
844+msgid "Purchase Order Line"
845+msgstr "采购订单明细"
846+
847+#. module: purchase_po_price
848+#: field:purchase.order.line,amount_subtotal:0
849+msgid "Subtotal(Inc. Tax)"
850+msgstr "小计(含税)"
851+
852+#. module: purchase_po_price
853+#: field:purchase.order.line,modify_price:0
854+msgid "Modify Price"
855+msgstr "修改价格"
856+
857+#. module: purchase_po_price
858+#: field:purchase.order.line,qty_received:0
859+msgid "Reception Qty"
860+msgstr "已收货数量"
861+
862+#. module: purchase_po_price
863+#: field:purchase.order.line,sequence:0
864+msgid "Sequence"
865+msgstr "序号"
866+
867+#. module: purchase_po_price
868+#: code:addons/purchase_po_price/purchase.py:105
869+#, python-format
870+msgid "PO Price"
871+msgstr "PO Price"
872+
873+#. module: purchase_po_price
874+#: field:purchase.order.line,qty_unreceived:0
875+msgid "Waiting Qty"
876+msgstr "待收货数量"
877+
878+#. module: purchase_po_price
879+#: view:purchase.order:0
880+msgid "Purchase Order Lines"
881+msgstr "采购订单明细"
882+
883+#. module: purchase_po_price
884+#: field:purchase.order.line,price_unit_original:0
885+msgid "Original Unit Price"
886+msgstr "原始单价"
887+
888+#. module: purchase_po_price
889+#: model:ir.model,name:purchase_po_price.model_res_partner
890+msgid "Partner"
891+msgstr "业务伙伴"
892+
893+#. module: purchase_po_price
894+#: help:res.partner,po_price_modification_limit:0
895+msgid "If checked, allows you to change the price in PO (only when either the Supplier or Product allow it)"
896+msgstr "若选择, 允许你在采购上修改单价(在供应商或者产品上设置一个即可)"
897+
898+#. module: purchase_po_price
899+#: help:purchase.order.line,sequence:0
900+msgid "Sequence for order in view and print report"
901+msgstr "用于视图和报表中的序号"
902+
903+#. module: purchase_po_price
904+#: field:res.partner,po_price_modification_limit:0
905+msgid "No control on PO price"
906+msgstr "不控采购单价"
907+
908
909=== added file 'purchase_po_price/purchase.py'
910--- purchase_po_price/purchase.py 1970-01-01 00:00:00 +0000
911+++ purchase_po_price/purchase.py 2013-08-16 03:22:06 +0000
912@@ -0,0 +1,113 @@
913+# -*- coding: utf-8 -*-
914+##############################################################################
915+#
916+# OpenERP, Open Source Management Solution
917+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
918+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
919+#
920+# This program is free software: you can redistribute it and/or modify
921+# it under the terms of the GNU Affero General Public License as
922+# published by the Free Software Foundation, either version 3 of the
923+# License, or (at your option) any later version.
924+#
925+# This program is distributed in the hope that it will be useful,
926+# but WITHOUT ANY WARRANTY; without even the implied warranty of
927+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
928+# GNU Affero General Public License for more details.
929+#
930+# You should have received a copy of the GNU Affero General Public License
931+# along with this program. If not, see <http://www.gnu.org/licenses/>.
932+#
933+##############################################################################
934+
935+from osv import osv, fields
936+from tools.translate import _
937+import openerp.addons.decimal_precision as dp
938+
939+class res_partner(osv.osv):
940+ _name = 'res.partner'
941+ _inherit = 'res.partner'
942+
943+ _columns = {
944+ 'po_price_modification_limit':fields.boolean("No control on PO price", help="""If checked, allows you to change the price in PO (only when either the Supplier or Product allow it)"""),
945+ }
946+
947+ _defaults = {
948+ 'po_price_modification_limit': True,
949+ }
950+res_partner()
951+
952+class purchase_order_line(osv.osv):
953+ _inherit = 'purchase.order.line'
954+
955+ _order = 'order_id desc, sequence'
956+
957+ def _amount_line_with_tax(self, cr, uid, ids, prop, arg, context=None):
958+ res = {}
959+ cur_obj = self.pool.get('res.currency')
960+ tax_obj = self.pool.get('account.tax')
961+ for line in self.browse(cr, uid, ids, context=context):
962+ taxes = tax_obj.compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty, line.product_id, line.order_id.partner_id, force_excluded=True)
963+ cur = line.order_id.pricelist_id.currency_id
964+ res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
965+ return res
966+
967+ def _qty_received(self, cr, uid, ids, prop, arg, context=None):
968+ res = {}
969+ for line in self.browse(cr, uid, ids, context=context):
970+ qty = 0.0
971+ for move in line.move_ids:
972+ if move.state == 'done':
973+ qty += move.product_qty
974+ res[line.id] = qty
975+ return res
976+
977+ def _qty_unreceived(self, cr, uid, ids, prop, arg, context=None):
978+ res = {}
979+ for line in self.browse(cr, uid, ids, context=context):
980+ qty = 0.0
981+ for move in line.move_ids:
982+ if move.state not in ('done', 'cancel'):
983+ qty += move.product_qty
984+ res[line.id] = qty
985+ return res
986+
987+ _columns = {
988+ 'modify_price': fields.boolean('Modify Price'),
989+ 'sequence': fields.integer('Sequence', help="Sequence for order in view and print report"),
990+ 'amount_subtotal': fields.function(_amount_line_with_tax, string='Subtotal(Inc. Tax)', type='float', digits_compute=dp.get_precision('Account')),
991+ 'qty_received': fields.function(_qty_received, string='Reception Qty', type='float', digits_compute=dp.get_precision('Product Unit of Measure')),
992+ 'qty_unreceived': fields.function(_qty_unreceived, string='Waiting Qty', type='float', digits_compute=dp.get_precision('Product Unit of Measure')),
993+ 'price_unit_original': fields.float('Original Unit Price', digits_compute=dp.get_precision('Product Price')),
994+ #'price_unit_exclude_tax': fields.function(_price_unit_line_without_tax, string='Unit Price(Exc. Tax)', type='float', digits_compute=dp.get_precision('Product Price')),
995+ }
996+ _defaults = {
997+ 'sequence': 1,
998+ 'modify_price': False,
999+ }
1000+
1001+
1002+ def onchange_price_unit(self, cr, uid, ids, partner_id, product_id, price_unit_original, price_unit, context=None):
1003+ #Not use at the moment! add a readonly attribute in view definition!
1004+ context = context or {}
1005+ res = {}
1006+
1007+ if not partner_id and not product_id:
1008+ return res
1009+ product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
1010+ partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
1011+
1012+ #if purchase_config_settings.po_price_modification_limit:
1013+ #if not product.po_price_modification_limit and not partner.po_price_modification_limit and price_unit_original != price_unit:
1014+ if not partner.po_price_modification_limit:
1015+
1016+ res['value'] = {'price_unit': price_unit_original}
1017+ res['warning'] = {'title' : _('PO Price'), 'message' : _('You can not modify the price of this product sold by this supplier !')}
1018+ #raise osv.except_osv(_('Error!'), _('You can not modify the price of this product sold by this supplier !'))
1019+ else:
1020+ res['value'] = {'price_unit_original':price_unit}
1021+ #ENDIF
1022+
1023+ return res
1024+
1025+purchase_order_line()
1026
1027=== added file 'purchase_po_price/purchase_view.xml'
1028--- purchase_po_price/purchase_view.xml 1970-01-01 00:00:00 +0000
1029+++ purchase_po_price/purchase_view.xml 2013-08-16 03:22:06 +0000
1030@@ -0,0 +1,68 @@
1031+<?xml version="1.0" encoding="UTF-8"?>
1032+<openerp>
1033+ <data>
1034+
1035+ <record id="view_partner_form_joomla" model="ir.ui.view">
1036+ <field name="name">res.partner.form.FC</field>
1037+ <field name="model">res.partner</field>
1038+ <field name="type">form</field>
1039+ <field name="inherit_id" ref="base.view_partner_form" />
1040+ <field name="arch" type="xml">
1041+ <xpath expr="//field[@name='customer']" position="after">
1042+
1043+ <field name="po_price_modification_limit" attrs="{'invisible':[('supplier','!=',True)]}"/>
1044+
1045+ <!-- <field name="supplier_product_limit" attrs="{'invisible':[('supplier','!=',True)]}"/> -->
1046+
1047+ </xpath>
1048+ </field>
1049+ </record>
1050+
1051+ <!-- <record id="product_normal_form_view_FC" model="ir.ui.view">
1052+ <field name="name">product.normal.form.FC</field>
1053+ <field name="model">product.product</field>
1054+ <field name="type">form</field>
1055+ <field name="inherit_id" ref="product.product_normal_form_view" />
1056+ <field name="arch" type="xml">
1057+ <xpath expr="//field[@name='uom_po_id']" position="after">
1058+ <field name="po_price_modification_limit"/>
1059+ </xpath>
1060+ </field>
1061+ </record> -->
1062+
1063+ <!-- Purchase Order -->
1064+ <record id="purchase_order_form_fc" model="ir.ui.view">
1065+ <field name="name">purchase.order.form_FC</field>
1066+ <field name="model">purchase.order</field>
1067+ <field name="type">form</field>
1068+ <field name="inherit_id" ref="purchase.purchase_order_form"/>
1069+ <field name="arch" type="xml">
1070+ <xpath expr="//field[@name='order_line']" position="replace">
1071+ <field name="order_line">
1072+ <tree string="Purchase Order Lines" editable="bottom">
1073+
1074+ <!-- field name="sequence"/>< by Andy-->
1075+ <field name="modify_price" invisible="1"/>
1076+ <!-- <field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,0,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)" context="{'supplier_id': parent.partner_id}"/> -->
1077+ <field name="name"/>
1078+ <field name="date_planned"/>
1079+ <field name="company_id" groups="base.group_multi_company" widget="selection"/>
1080+ <field name="account_analytic_id" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]"/>
1081+ <field name="product_qty" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id,parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
1082+ <field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
1083+ <!--field name="price_unit" attrs="{'readonly':[('modify_price','=',True)]}"/-->
1084+ <field name="price_unit_original" invisible="1"/>
1085+ <field name="price_unit" on_change="onchange_price_unit(parent.partner_id,product_id,price_unit_original,price_unit,context)"/>
1086+ <field name="taxes_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
1087+ <!-- <field name="price_unit_exclude_tax"/> -->
1088+ <field name="price_subtotal" invisible="1"/>
1089+ <field name="amount_subtotal"/><!-- by Andy-->
1090+
1091+ </tree>
1092+ </field>
1093+ </xpath>
1094+ </field>
1095+ </record>
1096+
1097+ </data>
1098+</openerp>
1099\ No newline at end of file
1100
1101=== added directory 'purchase_price_list_item'
1102=== added file 'purchase_price_list_item/__init__.py'
1103--- purchase_price_list_item/__init__.py 1970-01-01 00:00:00 +0000
1104+++ purchase_price_list_item/__init__.py 2013-08-16 03:22:06 +0000
1105@@ -0,0 +1,23 @@
1106+# -*- coding: utf-8 -*-
1107+##############################################################################
1108+#
1109+# OpenERP, Open Source Management Solution
1110+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
1111+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
1112+#
1113+# This program is free software: you can redistribute it and/or modify
1114+# it under the terms of the GNU Affero General Public License as
1115+# published by the Free Software Foundation, either version 3 of the
1116+# License, or (at your option) any later version.
1117+#
1118+# This program is distributed in the hope that it will be useful,
1119+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1120+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1121+# GNU Affero General Public License for more details.
1122+#
1123+# You should have received a copy of the GNU Affero General Public License
1124+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1125+#
1126+##############################################################################
1127+
1128+import purchase
1129\ No newline at end of file
1130
1131=== added file 'purchase_price_list_item/__openerp__.py'
1132--- purchase_price_list_item/__openerp__.py 1970-01-01 00:00:00 +0000
1133+++ purchase_price_list_item/__openerp__.py 2013-08-16 03:22:06 +0000
1134@@ -0,0 +1,52 @@
1135+# -*- coding: utf-8 -*-
1136+##############################################################################
1137+#
1138+# OpenERP, Open Source Management Solution
1139+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
1140+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
1141+# Andy LU<andy.lu@elico-corp.com>
1142+#
1143+# This program is free software: you can redistribute it and/or modify
1144+# it under the terms of the GNU Affero General Public License as
1145+# published by the Free Software Foundation, either version 3 of the
1146+# License, or (at your option) any later version.
1147+#
1148+# This program is distributed in the hope that it will be useful,
1149+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1150+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1151+# GNU Affero General Public License for more details.
1152+#
1153+# You should have received a copy of the GNU Affero General Public License
1154+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1155+#
1156+##############################################################################
1157+
1158+{
1159+ 'name': 'Purchase Price List Item',
1160+ 'version': '1.0',
1161+ 'category': 'Purchase',
1162+ 'sequence': 19,
1163+ 'summary': 'Purchase Price List Item',
1164+ 'description': """
1165+Improve purchase price managment
1166+================================
1167+
1168+ * In Purchase List Item, the price is fixed based on price_surchage if base is 'fixed on UOP'
1169+ * If 'fixed on UOP', if product UOP change, the price list price will be change automtically.
1170+ * Add field 'Qty on Hand', and 'Stock Values' for product
1171+ * Add field 'Qty on Hand', 'Stock Values', UOP in product list view
1172+
1173+ """,
1174+ 'author': 'Elico Corp',
1175+ 'website': 'http://www.elico-corp.com',
1176+ 'images' : [],
1177+ 'depends': ['purchase'],
1178+ 'data': [
1179+ 'purchase_view.xml',
1180+ ],
1181+ 'test': [],
1182+ 'demo': [],
1183+ 'installable': True,
1184+ 'auto_install': False,
1185+ 'application': False,
1186+}
1187\ No newline at end of file
1188
1189=== added directory 'purchase_price_list_item/i18n'
1190=== added file 'purchase_price_list_item/i18n/purchase_price_list_item.po'
1191--- purchase_price_list_item/i18n/purchase_price_list_item.po 1970-01-01 00:00:00 +0000
1192+++ purchase_price_list_item/i18n/purchase_price_list_item.po 2013-08-16 03:22:06 +0000
1193@@ -0,0 +1,33 @@
1194+# Translation of OpenERP Server.
1195+# This file contains the translation of the following modules:
1196+# * purchase_price_list_item
1197+#
1198+msgid ""
1199+msgstr ""
1200+"Project-Id-Version: OpenERP Server 7.0\n"
1201+"Report-Msgid-Bugs-To: \n"
1202+"POT-Creation-Date: 2013-08-14 09:03+0000\n"
1203+"PO-Revision-Date: 2013-08-14 09:03+0000\n"
1204+"Last-Translator: <>\n"
1205+"Language-Team: \n"
1206+"MIME-Version: 1.0\n"
1207+"Content-Type: text/plain; charset=UTF-8\n"
1208+"Content-Transfer-Encoding: \n"
1209+"Plural-Forms: \n"
1210+
1211+#. module: purchase_price_list_item
1212+#: code:addons/purchase_price_list_item/purchase.py:34
1213+#, python-format
1214+msgid "Fix Price based on UoP"
1215+msgstr ""
1216+
1217+#. module: purchase_price_list_item
1218+#: model:ir.model,name:purchase_price_list_item.model_product_pricelist_item
1219+msgid "Pricelist item"
1220+msgstr ""
1221+
1222+#. module: purchase_price_list_item
1223+#: field:product.pricelist.item,uom_id:0
1224+msgid "UoM for Fix Price"
1225+msgstr ""
1226+
1227
1228=== added file 'purchase_price_list_item/purchase.py'
1229--- purchase_price_list_item/purchase.py 1970-01-01 00:00:00 +0000
1230+++ purchase_price_list_item/purchase.py 2013-08-16 03:22:06 +0000
1231@@ -0,0 +1,332 @@
1232+# -*- coding: utf-8 -*-
1233+##############################################################################
1234+#
1235+# OpenERP, Open Source Management Solution
1236+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
1237+# Author: Jean LELIEVRE <jean.lelievre@elico-corp.com>
1238+#
1239+# This program is free software: you can redistribute it and/or modify
1240+# it under the terms of the GNU Affero General Public License as
1241+# published by the Free Software Foundation, either version 3 of the
1242+# License, or (at your option) any later version.
1243+#
1244+# This program is distributed in the hope that it will be useful,
1245+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1246+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1247+# GNU Affero General Public License for more details.
1248+#
1249+# You should have received a copy of the GNU Affero General Public License
1250+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1251+#
1252+##############################################################################
1253+
1254+from osv import osv, fields
1255+from tools.translate import _
1256+
1257+import openerp.addons.decimal_precision as dp
1258+
1259+import time
1260+from product._common import rounding
1261+
1262+
1263+class product_pricelist_item(osv.osv):
1264+ _inherit = "product.pricelist.item"
1265+
1266+ def _price_field_get(self, cr, uid, context=None):
1267+ result = super(product_pricelist_item, self)._price_field_get(cr, uid, context=context)
1268+
1269+ result.append((-3, _('Fix Price based on UoP')))
1270+ return result
1271+
1272+ _columns = {
1273+ 'base': fields.selection(_price_field_get, 'Based on',required=True, size=-1, help="Base price for computation."),
1274+ 'uom_id': fields.many2one('product.uom','UoM for Fix Price',store=True),
1275+ }
1276+ _defaults = {
1277+ 'price_discount': lambda *a: -1,
1278+ 'base': lambda *a: -3,
1279+ }
1280+
1281+ def product_id_change(self,cr,uid,ids,product_id,context=None):
1282+ if not product_id:
1283+ return{}
1284+ prod = self.pool.get('product.product').browse(cr,uid,product_id,context=context)
1285+
1286+ if prod.default_code:
1287+ return {'value': {'name': prod.default_code,'uom_id': prod.uom_po_id.id}}
1288+ return{}
1289+
1290+ def create(self,cr,uid,vals,context=None):
1291+ if not vals.get('uom_id',False) and vals.get('product_id', False) and vals.get('base',False) == -3:
1292+ prod = self.pool.get('product.product').browse(cr,uid,vals.get('product_id',False),context=context)
1293+ vals['uom_id'] = prod.uom_po_id.id
1294+
1295+ return super(product_pricelist_item,self).create(cr,uid,vals,context=context)
1296+
1297+ def write(self, cr, uid, ids, vals, context=None):
1298+ if type(ids) != type([]):
1299+ ids = [ids]
1300+ if not vals.get('uom_id', False) and ids:
1301+ pl_item_obj = self.pool.get('product.pricelist.item')
1302+ for id in ids:
1303+ item = pl_item_obj.browse(cr, uid, id, context=context)
1304+ if item.base == -3 and item.product_id:
1305+ vals['uom_id'] = item.product_id.uom_po_id.id
1306+ return super(product_pricelist_item, self).write(cr, uid, ids, vals, context=context)
1307+
1308+product_pricelist_item()
1309+
1310+
1311+class product_pricelist(osv.osv):
1312+ _inherit = "product.pricelist"
1313+
1314+ #def price_get_multi(self, cr, uid, product_ids, context=None):
1315+ def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None):
1316+ """multi products 'price_get'.
1317+ @param pricelist_ids:
1318+ @param products_by_qty:
1319+ @param partner:
1320+ @param context: {
1321+ 'date': Date of the pricelist (%Y-%m-%d),}
1322+ @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value
1323+ """
1324+
1325+ def _create_parent_category_list(id, lst):
1326+ if not id:
1327+ return []
1328+ parent = product_category_tree.get(id)
1329+ if parent:
1330+ lst.append(parent)
1331+ return _create_parent_category_list(parent, lst)
1332+ else:
1333+ return lst
1334+ # _create_parent_category_list
1335+
1336+ if context is None:
1337+ context = {}
1338+
1339+ date = time.strftime('%Y-%m-%d')
1340+ if 'date' in context:
1341+ date = context['date']
1342+
1343+ currency_obj = self.pool.get('res.currency')
1344+ product_obj = self.pool.get('product.product')
1345+ product_category_obj = self.pool.get('product.category')
1346+ product_uom_obj = self.pool.get('product.uom')
1347+ supplierinfo_obj = self.pool.get('product.supplierinfo')
1348+ price_type_obj = self.pool.get('product.price.type')
1349+
1350+ # product.pricelist.version:
1351+ if not pricelist_ids:
1352+ pricelist_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)
1353+
1354+ pricelist_version_ids = self.pool.get('product.pricelist.version').search(cr, uid, [
1355+ ('pricelist_id', 'in', pricelist_ids),
1356+ '|',
1357+ ('date_start', '=', False),
1358+ ('date_start', '<=', date),
1359+ '|',
1360+ ('date_end', '=', False),
1361+ ('date_end', '>=', date),
1362+ ])
1363+ if len(pricelist_ids) != len(pricelist_version_ids):
1364+ raise osv.except_osv(_('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one."))
1365+
1366+ # product.product:
1367+ product_ids = [i[0] for i in products_by_qty_by_partner]
1368+ #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
1369+ products = product_obj.browse(cr, uid, product_ids, context=context)
1370+ products_dict = dict([(item.id, item) for item in products])
1371+
1372+ # product.category:
1373+ product_category_ids = product_category_obj.search(cr, uid, [])
1374+ product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id'])
1375+ product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']])
1376+
1377+ results = {}
1378+ for product_id, qty, partner in products_by_qty_by_partner:
1379+ for pricelist_id in pricelist_ids:
1380+ price = False
1381+
1382+ tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False
1383+
1384+ categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False
1385+ categ_ids = _create_parent_category_list(categ_id, [categ_id])
1386+ if categ_ids:
1387+ categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))'
1388+ else:
1389+ categ_where = '(categ_id IS NULL)'
1390+
1391+ if partner:
1392+ partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) '
1393+ partner_args = (partner, tmpl_id)
1394+ else:
1395+ partner_where = 'base <> -2 '
1396+ partner_args = ()
1397+
1398+ #And
1399+ pl = self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context)
1400+ if pl.type == "purchase":
1401+ product = products_dict[product_id]
1402+ if 'uom' in context:
1403+ uom = product.uom_po_id
1404+ if uom.id != context['uom']:
1405+ qty = qty * product.uom_po_id.factor / product.uom_id.factor
1406+
1407+ cr.execute(
1408+ 'SELECT i.*, pl.currency_id '
1409+ 'FROM product_pricelist_item AS i, '
1410+ 'product_pricelist_version AS v, product_pricelist AS pl '
1411+ 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
1412+ 'AND (product_id IS NULL OR product_id = %s) '
1413+ 'AND (' + categ_where + ' OR (categ_id IS NULL)) '
1414+ 'AND (' + partner_where + ') '
1415+ 'AND price_version_id = %s '
1416+ 'AND (min_quantity IS NULL OR min_quantity <= %s) '
1417+ 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
1418+ 'ORDER BY sequence',
1419+ (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty))
1420+ res1 = cr.dictfetchall()
1421+ uom_price_already_computed = False
1422+ for res in res1:
1423+ if res:
1424+ if res['base'] == -1:
1425+ if not res['base_pricelist_id']:
1426+ price = 0.0
1427+ else:
1428+ price_tmp = self.price_get(cr, uid,
1429+ [res['base_pricelist_id']], product_id,
1430+ qty, context=context)[res['base_pricelist_id']]
1431+ ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id
1432+ uom_price_already_computed = True
1433+ price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False)
1434+ elif res['base'] == -2:
1435+ # this section could be improved by moving the queries outside the loop:
1436+ where = []
1437+ if partner:
1438+ where = [('name', '=', partner) ]
1439+ sinfo = supplierinfo_obj.search(cr, uid,
1440+ [('product_id', '=', tmpl_id)] + where)
1441+ price = 0.0
1442+ if sinfo:
1443+ qty_in_product_uom = qty
1444+ product_default_uom = product_obj.read(cr, uid, [product_id], ['uom_id'])[0]['uom_id'][0]
1445+ supplier = supplierinfo_obj.browse(cr, uid, sinfo, context=context)[0]
1446+ seller_uom = supplier.product_uom and supplier.product_uom.id or False
1447+ if seller_uom and product_default_uom and product_default_uom != seller_uom:
1448+ uom_price_already_computed = True
1449+ qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom)
1450+ cr.execute('SELECT * ' \
1451+ 'FROM pricelist_partnerinfo ' \
1452+ 'WHERE suppinfo_id IN %s' \
1453+ 'AND min_quantity <= %s ' \
1454+ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,))
1455+ res2 = cr.dictfetchone()
1456+ if res2:
1457+ price = res2['price']
1458+ #Add by Andy
1459+ elif res['base'] == -3:
1460+ price = False
1461+ else:
1462+ price_type = price_type_obj.browse(cr, uid, int(res['base']))
1463+ uom_price_already_computed = True
1464+ price = currency_obj.compute(cr, uid,
1465+ price_type.currency_id.id, res['currency_id'],
1466+ product_obj.price_get(cr, uid, [product_id],
1467+ price_type.field, context=context)[product_id], round=False, context=context)
1468+
1469+ if price is not False:
1470+ price_limit = price
1471+ price = price * (1.0 + (res['price_discount'] or 0.0))
1472+ price = rounding(price, res['price_round']) #TOFIX: rounding with tools.float_rouding
1473+ price += (res['price_surcharge'] or 0.0)
1474+ if res['price_min_margin']:
1475+ price = max(price, price_limit + res['price_min_margin'])
1476+ if res['price_max_margin']:
1477+ price = min(price, price_limit + res['price_max_margin'])
1478+ break
1479+ #Add by Andy
1480+ else:
1481+ if res['base'] == -3:
1482+ price = res['price_surcharge'] or 0.0
1483+ product = products_dict[product_id]
1484+ if 'uom' in context:
1485+ uom = product.uom_po_id
1486+ if uom.id != context['uom']:
1487+ price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
1488+ uom_price_already_computed = True
1489+ #Todo: # Use company currency?
1490+ if 'currency_id' in context:
1491+ price = currency_obj.compute(cr, uid, 1,
1492+ context['currency_id'], price, context=context)
1493+ if price:
1494+ break
1495+ else:
1496+ # False means no valid line found ! But we may not raise an
1497+ # exception here because it breaks the search
1498+ price = False
1499+
1500+ if price:
1501+ results['item_id'] = res['id']
1502+ if 'uom' in context and not uom_price_already_computed:
1503+ product = products_dict[product_id]
1504+ uom = product.uos_id or product.uom_id
1505+ price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
1506+
1507+ if results.get(product_id):
1508+ results[product_id][pricelist_id] = price
1509+ else:
1510+ results[product_id] = {pricelist_id: price}
1511+
1512+ return results
1513+
1514+product_pricelist()
1515+
1516+
1517+
1518+class product_product(osv.osv):
1519+ _name = "product.product"
1520+ _inherit = "product.product"
1521+
1522+ def _qty_uop(self, cr, uid, ids, name, arg, context=None):
1523+ res = {}
1524+
1525+ uom_obj = self.pool.get('product.uom')
1526+ for id in ids:
1527+ res.setdefault(id, 0.0)
1528+ for product in self.browse(cr, uid, ids):
1529+ res[product.id] = uom_obj._compute_qty(cr, uid, product.uom_id.id, product.qty_available, product.uom_po_id.id)
1530+ return res
1531+
1532+ def _amount_uom(self, cr, uid, ids, name, arg, context=None):
1533+ res = {}
1534+
1535+ for id in ids:
1536+ res.setdefault(id, 0.0)
1537+ for product in self.browse(cr, uid, ids):
1538+ res[product.id] = product.qty_available * product.standard_price
1539+ return res
1540+
1541+ _columns = {
1542+ #'price_uop': fields.float('Purchase Price(UoP)', digits_compute=dp.get_precision('Product Price')),
1543+ 'qty_uop': fields.function(_qty_uop, type='float', string='Qty on Hand (UoP)', digits_compute=dp.get_precision('Product Unit of Measure')),
1544+ 'amount_uom': fields.function(_amount_uom, type='float', string='Stock Values', digits_compute=dp.get_precision('Account')),
1545+ }
1546+
1547+ def write(self, cr, uid, ids, vals, context=None):
1548+ if type(ids) != type([]):
1549+ ids = [ids]
1550+ if vals.get('uom_po_id', False) and ids:
1551+ uom_obj = self.pool.get('product.uom')
1552+ uop = uom_obj.browse(cr, uid, vals.get('uom_po_id', False), context=context)
1553+ pl_item_obj = self.pool.get('product.pricelist.item')
1554+ pl_ids = pl_item_obj.search(cr, uid, [('product_id', '=', ids[0]), ('base', '=', -3)], context=context)
1555+ for item in pl_item_obj.browse(cr, uid, pl_ids, context=context):
1556+ if item.uom_id and uop.id == item.uom_id.id:
1557+ continue
1558+ new_price = item.price_surcharge / uop.factor * item.uom_id.factor
1559+ pl_item_obj.write(cr, uid, [item.id], {'uom_id': vals.get('uom_po_id', False), 'price_surcharge': new_price})
1560+
1561+ return super(product_product, self).write(cr, uid, ids, vals, context=context)
1562+
1563+product_product()
1564\ No newline at end of file
1565
1566=== added file 'purchase_price_list_item/purchase_view.xml'
1567--- purchase_price_list_item/purchase_view.xml 1970-01-01 00:00:00 +0000
1568+++ purchase_price_list_item/purchase_view.xml 2013-08-16 03:22:06 +0000
1569@@ -0,0 +1,48 @@
1570+<?xml version="1.0" encoding="UTF-8" ?>
1571+<openerp>
1572+ <data>
1573+
1574+ <record id="product_pricelist_item_list_view_FC" model="ir.ui.view">
1575+ <field name="name">product.pricelist.item.list.FC</field>
1576+ <field name="model">product.pricelist.item</field>
1577+ <field name="inherit_id" ref="product.product_pricelist_item_tree_view" />
1578+ <field name="arch" type="xml">
1579+ <xpath expr="//field[@name='categ_id']" position="before">
1580+ <field name="price_surcharge" attrs="{'invisible':[('base', '!=', -3)]}"/>
1581+ <field name="uom_id" attrs="{'invisible':[('base', '!=', -3)],'readonly':1}"/>
1582+ </xpath>
1583+ </field>
1584+ </record>
1585+
1586+ <record id="product_pricelist_item_form_view_FC" model="ir.ui.view">
1587+ <field name="name">product.pricelist.item.form.FC</field>
1588+ <field name="model">product.pricelist.item</field>
1589+ <field name="type">form</field>
1590+ <field name="inherit_id" ref="product.product_pricelist_item_form_view" />
1591+ <field name="arch" type="xml">
1592+ <xpath expr="//field[@name='product_id']" position="replace">
1593+ <field name="product_id" on_change="product_id_change(product_id)" attrs="{'required': [('base','=', -3)]}"/>
1594+ <field name="uom_id" attrs="{'invisible':[('base', '!=', -3)],'readonly':1}"/>
1595+ </xpath>
1596+ </field>
1597+ </record>
1598+
1599+ <record id="product_product_tree_view_uop" model="ir.ui.view">
1600+ <field name="name">product.product.tree.uop</field>
1601+ <field name="model">product.product</field>
1602+ <field name="type">form</field>
1603+ <field name="inherit_id" ref="product.product_product_tree_view" />
1604+ <field name="arch" type="xml">
1605+ <xpath expr="//field[@name='state']" position="before">
1606+ <field name="qty_uop"/>
1607+ <field name="uom_po_id"/>
1608+ </xpath>
1609+ <xpath expr="//field[@name='standard_price']" position="replace">
1610+ <field name="standard_price"/>
1611+ <field name="amount_uom"/>
1612+ </xpath>
1613+ </field>
1614+ </record>
1615+
1616+ </data>
1617+</openerp>
1618\ No newline at end of file

Subscribers

People subscribed via source and target branches