Merge lp:~therp-nl/openobject-addons/trunk-lp754339 into lp:openobject-addons

Proposed by Holger Brunn (Therp)
Status: Needs review
Proposed branch: lp:~therp-nl/openobject-addons/trunk-lp754339
Merge into: lp:openobject-addons
Diff against target: 226 lines (+182/-20)
3 files modified
account/account_invoice.py (+84/-18)
account/tests/__init__.py (+4/-2)
account/tests/test_product_id_change.py (+94/-0)
To merge this branch: bzr merge lp:~therp-nl/openobject-addons/trunk-lp754339
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+191211@code.launchpad.net

Commit message

[ADD] get price on invoice line from pricelist if there is one

Description of the change

Use pricelists for creating invoices. If there's no pricelist configured, nothing should change.

Also add tests for that.

To post a comment you must log in.
8942. By Holger Brunn (Therp)

[ADD] test

8943. By Stefan Rijnhart (Opener)

[MRG] Merged with trunk

Unmerged revisions

8943. By Stefan Rijnhart (Opener)

[MRG] Merged with trunk

8942. By Holger Brunn (Therp)

[ADD] test

8941. By Holger Brunn (Therp)

[ADD] get price on invoice line from pricelist if there is one

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account/account_invoice.py'
2--- account/account_invoice.py 2013-09-23 17:13:10 +0000
3+++ account/account_invoice.py 2013-10-15 15:07:53 +0000
4@@ -1540,26 +1540,92 @@
5
6 domain = {'uos_id':[('category_id','=',res.uom_id.category_id.id)]}
7
8- res_final = {'value':result, 'domain':domain}
9-
10- if not company_id or not currency_id:
11- return res_final
12-
13- company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
14- currency = self.pool.get('res.currency').browse(cr, uid, currency_id, context=context)
15-
16- if company.currency_id.id != currency.id:
17- if type in ('in_invoice', 'in_refund'):
18- res_final['value']['price_unit'] = res.standard_price
19- new_price = res_final['value']['price_unit'] * currency.rate
20- res_final['value']['price_unit'] = new_price
21-
22- if result['uos_id'] and result['uos_id'] != res.uom_id.id:
23- selected_uom = self.pool.get('product.uom').browse(cr, uid, result['uos_id'], context=context)
24- new_price = self.pool.get('product.uom')._compute_price(cr, uid, res.uom_id.id, res_final['value']['price_unit'], result['uos_id'])
25- res_final['value']['price_unit'] = new_price
26+ warning = {}
27+ # When product changes, price ALWAYS need to be reset. If not price
28+ # found in product, or pricelist, it should become False. Only if
29+ # product_id has been cleared by user, we will leave price_unit as is.
30+ if product:
31+ price_unit, pu_warning = self._price_unit_get(
32+ cr, uid, product, uom_id, qty, type, partner_id,
33+ currency_id, context=context)
34+ result['price_unit'] = price_unit # might be False
35+ warning.update(pu_warning)
36+
37+ res_final = {'value': result, 'domain': domain, 'warning': warning}
38 return res_final
39
40+ def _price_unit_get(
41+ self, cr, uid, product_id, uom_id, qty, invoice_type, partner_id,
42+ currency_id, context=None):
43+ price_unit = False
44+ warning = {}
45+ standard_currency_id = currency_id
46+ partner_model = self.pool.get('res.partner')
47+ partner_obj = partner_model.browse(
48+ cr, uid, partner_id, context=context)
49+ assert partner_obj, _('No partner found for id %d') % partner_id
50+ if invoice_type in ('in_invoice', 'in_refund'):
51+ field = 'list_price'
52+ pricelist_property = 'property_product_pricelist_purchase'
53+ else:
54+ field = 'standard_price'
55+ pricelist_property = 'property_product_pricelist'
56+ if pricelist_property in partner_obj:
57+ pricelist_id = partner_obj[pricelist_property].id
58+ else:
59+ pricelist_id = False
60+ # Check whether standard price p.u. modified by pricelist
61+ if pricelist_id:
62+ pricelist_model = self.pool.get('product.pricelist')
63+ price_unit = pricelist_model.price_get(
64+ cr, uid, [pricelist_id], product_id, qty or 1.0,
65+ partner=partner_id,
66+ context=dict(context, uom=uom_id))[pricelist_id]
67+ if price_unit is False: # 0.0 is OK, we night have free products
68+ warning = {
69+ 'title': _('No valid pricelist line found!'),
70+ 'message':
71+ _("Couldn't find a pricelist line matching this product"
72+ " and quantity.\n"
73+ "You have to change either the product, the quantity or"
74+ " the pricelist.")
75+ }
76+ # Pricelist converts price from standard currency to pricelist
77+ # currency. We have to convert this to the invoice currency.
78+ # In practice that will often mean undoing the conversion
79+ # done by the pricelist object
80+ pricelist_obj = pricelist_model.browse(
81+ cr, uid, pricelist_id, context=context)
82+ if pricelist_obj and pricelist_obj.currency_id:
83+ standard_currency_id = pricelist_obj.currency_id.id
84+ else:
85+ # Take standard price per unit directly from product
86+ product_model = self.pool.get('product.product')
87+ product_obj = product_model.browse(
88+ cr, uid, product_id, context=context)
89+ assert product_obj, _('No product found for id %d') % product_id
90+ assert field in product_obj, _(
91+ 'Field %s not found in product') % field
92+ price_unit = product_obj.uom_id._compute_price(
93+ cr, uid, product_obj.uom_id.id, product_obj[field], uom_id)
94+ # When price not taken from pricelist, the currency is
95+ # determined by the price_type:
96+ price_type_model = self.pool.get('product.price.type')
97+ price_type_ids = price_type_model.search(
98+ cr, uid, [('field', '=', field)], context=context)
99+ if price_type_ids:
100+ price_type_obj = price_type_model.browse(
101+ cr, uid, price_type_ids[0], context=context)
102+ if price_type_obj and price_type_obj.currency_id:
103+ standard_currency_id = price_type_obj.currency_id.id
104+ # convert price_unit to currency of invoice
105+ if standard_currency_id != currency_id:
106+ currency_model = self.pool.get('res.currency')
107+ price_unit = currency_model.compute(
108+ cr, uid, standard_currency_id, currency_id,
109+ price_unit, round=True, context=context)
110+ return price_unit, warning
111+
112 def uos_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None):
113 if context is None:
114 context = {}
115
116=== modified file 'account/tests/__init__.py'
117--- account/tests/__init__.py 2012-11-01 20:39:35 +0000
118+++ account/tests/__init__.py 2013-10-15 15:07:53 +0000
119@@ -1,4 +1,6 @@
120-from . import test_tax
121+from . import test_tax, test_product_id_change
122
123-fast_suite = [test_tax,
124+fast_suite = [
125+ test_tax,
126+ test_product_id_change,
127 ]
128
129=== added file 'account/tests/test_product_id_change.py'
130--- account/tests/test_product_id_change.py 1970-01-01 00:00:00 +0000
131+++ account/tests/test_product_id_change.py 2013-10-15 15:07:53 +0000
132@@ -0,0 +1,94 @@
133+from openerp.tests.common import TransactionCase
134+
135+class TestProductIdChange(TransactionCase):
136+ """Test for product_id_change on account.invoice.line
137+ """
138+
139+ def setUp(self):
140+ super(TestProductIdChange, self).setUp()
141+ self.line_model = self.registry('account.invoice.line')
142+
143+ def get_line(self):
144+ line_id = self.line_model.create(
145+ self.cr,
146+ self.uid,
147+ {
148+ 'name': 'testline',
149+ })
150+ return self.line_model.browse(
151+ self.cr, self.uid, line_id)
152+
153+
154+ def get_partner(self):
155+ partner_id = self.registry('res.partner').search(
156+ self.cr,
157+ self.uid,
158+ [('customer', '=', True)],
159+ limit=1)[0]
160+
161+ return self.registry('res.partner').browse(
162+ self.cr, self.uid, partner_id)
163+
164+ def get_product(self):
165+ product_id = self.registry('product.product').search(
166+ self.cr,
167+ self.uid,
168+ [('uom_id', '!=', False)],
169+ limit=1)[0]
170+ return self.registry('product.product').browse(
171+ self.cr, self.uid, product_id)
172+
173+ def test_random_product(self):
174+ line = self.get_line()
175+ product = self.get_product()
176+ partner = self.get_partner()
177+
178+ values = line.product_id_change(
179+ product.id, None,
180+ partner_id=partner.id)['value']
181+
182+ self.assertEquals(values['price_unit'], product.list_price)
183+ self.assertEquals(values['uos_id'], product.uom_id.id)
184+
185+ def test_with_pricelist(self):
186+ line = self.get_line()
187+ product = self.get_product()
188+
189+ pricelist_id = self.registry('product.pricelist').create(
190+ self.cr,
191+ self.uid,
192+ {
193+ 'name': 'testpricelist',
194+ 'type': self.browse_ref('product.pricelist_type_sale').key,
195+ 'version_id': [
196+ (0, 0, {
197+ 'name': 'testversion',
198+ 'items_id': [
199+ (0, 0, {
200+ 'name': 'testitem',
201+ 'product_id': product.id,
202+ 'price_discount': .5,
203+ 'price_surcharge': 42,
204+ 'base': self.browse_ref(
205+ 'product.list_price').id,
206+ }),
207+ ],
208+ }),
209+ ],
210+ })
211+
212+ partner_id = self.registry('res.partner').create(
213+ self.cr,
214+ self.uid,
215+ {
216+ 'name': 'testcustomer',
217+ 'customer': True,
218+ 'property_product_pricelist':
219+ 'product.pricelist,%d' % pricelist_id,
220+ })
221+
222+ values = line.product_id_change(
223+ product.id, None,
224+ partner_id=partner_id)['value']
225+
226+ self.assertEquals(values['price_unit'], product.list_price * 1.5 + 42)

Subscribers

People subscribed via source and target branches

to all changes: