Merge lp:~borjals/openobject-addons/extra-6.0-bugfix-603100 into lp:openobject-addons/extra-trunk
- extra-6.0-bugfix-603100
- Merge into trunk-extra-addons
Status: | Merged |
---|---|
Merged at revision: | 4743 |
Proposed branch: | lp:~borjals/openobject-addons/extra-6.0-bugfix-603100 |
Merge into: | lp:openobject-addons/extra-trunk |
Diff against target: |
652 lines (+424/-114) 7 files modified
purchase_tax_include/__init__.py (+7/-1) purchase_tax_include/__openerp__.py (+36/-0) purchase_tax_include/__terp__.py (+0/-35) purchase_tax_include/i18n/es.po (+89/-0) purchase_tax_include/i18n/purchase_tax_include.pot (+40/-3) purchase_tax_include/purchase_tax_incl.py (+212/-47) purchase_tax_include/purchase_tax_incl.xml (+40/-28) |
To merge this branch: | bzr merge lp:~borjals/openobject-addons/extra-6.0-bugfix-603100 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joël Grand-Guillaume @ camptocamp | Approve | ||
OpenERP Core Team | Pending | ||
Review via email: mp+29566@code.launchpad.net |
Commit message
Description of the change
Complete rewrite of the purchase_
- Solved "column 'amount_tax' of relation 'purchase_order' does not exist"
error when saving a purchase order (bug 603100).
The previous fields redefinitions where incompatible with the purchase
module (comming from the 5.0 addons) since Dec 2008.
- Now correct 'amount_untaxed' and 'amount_total' are shown on the
purchase order totals.
- Now 'price_
purchase order lines list of the purchase form.
- When the order is invoiced, the created invoice did not use the
price type of the order, so the amounts didn't match; fixed.
- When a picking is invoiced, the created invoice did not use the
price type of the original orders; fixed.
Numérigraphe (numerigraphe) wrote : | # |
Borja López Soilán (NeoPolus) (borjals) wrote : | # |
Thanks for the comments Numérigraphe :) There is always room for improvement.
- I didn't want to change the methods signature, cause it might break things.
For example the original _amount_line method of purchase.order.line is defined like this:
class purchase_
def _amount_line(self, cr, uid, ids, prop, unknow_
As you can see, the context (unknown_dict - WTF? who gave it this name?) is not optional.
- Migration script? The changes affect only to function fields (and new documents) so there is no data to migrate :) Also, I seriously doubt anybody was using this module on 5.0 (it has been broken since 2008!).
- I hadn't thought about YAML tests, seems like a good idea (it is a pity that 5.0 does not support YAML tests), but it will take some time.
Borja López Soilán (NeoPolus) (borjals) wrote : | # |
Ok, this has been waiting for a month and only Numérigraphe (thanks!) reviewed the merge proposal. As in its current state purchase_
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
Hi Borja,
Just installed and check some little cases with your improvements/fixes. It seems good to me.
Thanks you for your work.
Regards,
Joël
Borja López Soilán (NeoPolus) (borjals) wrote : | # |
Thanks Joël :)
Preview Diff
1 | === modified file 'purchase_tax_include/__init__.py' (properties changed: +x to -x) |
2 | --- purchase_tax_include/__init__.py 2010-07-06 05:10:58 +0000 |
3 | +++ purchase_tax_include/__init__.py 2010-07-09 15:01:00 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +# -*- encoding: utf-8 -*- |
6 | ############################################################################## |
7 | # |
8 | # OpenERP, Open Source Management Solution |
9 | @@ -18,6 +19,11 @@ |
10 | # |
11 | ############################################################################## |
12 | |
13 | +__authors__ = [ |
14 | + "OpenERP S.A.", |
15 | + "Borja López Soilán (Pexego) <borjals@pexego.es>" |
16 | +] |
17 | + |
18 | import purchase_tax_incl |
19 | -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
20 | + |
21 | |
22 | |
23 | === added file 'purchase_tax_include/__openerp__.py' |
24 | --- purchase_tax_include/__openerp__.py 1970-01-01 00:00:00 +0000 |
25 | +++ purchase_tax_include/__openerp__.py 2010-07-09 15:01:00 +0000 |
26 | @@ -0,0 +1,36 @@ |
27 | +# -*- encoding: utf-8 -*- |
28 | +############################################################################## |
29 | +# |
30 | +# OpenERP, Open Source Management Solution |
31 | +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). |
32 | +# |
33 | +# This program is free software: you can redistribute it and/or modify |
34 | +# it under the terms of the GNU Affero General Public License as |
35 | +# published by the Free Software Foundation, either version 3 of the |
36 | +# License, or (at your option) any later version. |
37 | +# |
38 | +# This program is distributed in the hope that it will be useful, |
39 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
40 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
41 | +# GNU Affero General Public License for more details. |
42 | +# |
43 | +# You should have received a copy of the GNU Affero General Public License |
44 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
45 | +# |
46 | +############################################################################## |
47 | +{ |
48 | + "name" : "Purchases with taxes included", |
49 | + "version" : "2.0", |
50 | + "depends" : ["purchase","account_tax_include"], |
51 | + "author" : "Tiny", |
52 | + "website" : "http://www.openerp.com", |
53 | + "category" : "Generic Modules/Sales & Purchases", |
54 | + "description": "This module allows you to use purchase order with prices including or excluding taxes.", |
55 | + "init_xml" : [ ], |
56 | + "demo_xml" : [ ], |
57 | + "update_xml" : [ 'purchase_tax_incl.xml' ], |
58 | + "active": False, |
59 | + "installable": True |
60 | +} |
61 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
62 | + |
63 | |
64 | === removed file 'purchase_tax_include/__terp__.py' |
65 | --- purchase_tax_include/__terp__.py 2010-07-06 05:10:58 +0000 |
66 | +++ purchase_tax_include/__terp__.py 1970-01-01 00:00:00 +0000 |
67 | @@ -1,35 +0,0 @@ |
68 | -############################################################################## |
69 | -# |
70 | -# OpenERP, Open Source Management Solution |
71 | -# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). |
72 | -# |
73 | -# This program is free software: you can redistribute it and/or modify |
74 | -# it under the terms of the GNU Affero General Public License as |
75 | -# published by the Free Software Foundation, either version 3 of the |
76 | -# License, or (at your option) any later version. |
77 | -# |
78 | -# This program is distributed in the hope that it will be useful, |
79 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
80 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
81 | -# GNU Affero General Public License for more details. |
82 | -# |
83 | -# You should have received a copy of the GNU Affero General Public License |
84 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
85 | -# |
86 | -############################################################################## |
87 | -{ |
88 | - "name" : "Purchases with taxes included", |
89 | - "version" : "1.0", |
90 | - "depends" : ["purchase","account_tax_include"], |
91 | - "author" : "Tiny", |
92 | - "website" : "http://www.openerp.com", |
93 | - "category" : "Generic Modules/Sales & Purchases", |
94 | - "description": "This module allows you to use purchase order with prices including or excluding taxes.", |
95 | - "init_xml" : [ ], |
96 | - "demo_xml" : [ ], |
97 | - "update_xml" : [ 'purchase_tax_incl.xml' ], |
98 | - "active": False, |
99 | - "installable": True |
100 | -} |
101 | -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
102 | - |
103 | |
104 | === added file 'purchase_tax_include/i18n/es.po' |
105 | --- purchase_tax_include/i18n/es.po 1970-01-01 00:00:00 +0000 |
106 | +++ purchase_tax_include/i18n/es.po 2010-07-09 15:01:00 +0000 |
107 | @@ -0,0 +1,89 @@ |
108 | +# Translation of OpenERP Server. |
109 | +# This file contains the translation of the following modules: |
110 | +# * purchase_tax_include |
111 | +# |
112 | +msgid "" |
113 | +msgstr "" |
114 | +"Project-Id-Version: OpenERP Server 6.0dev\n" |
115 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
116 | +"POT-Creation-Date: 2010-07-09 11:24:53+0000\n" |
117 | +"PO-Revision-Date: 2010-07-09 13:32+0100\n" |
118 | +"Last-Translator: Borja López Soilán (Pexego) <borjals@pexego.es>\n" |
119 | +"Language-Team: \n" |
120 | +"MIME-Version: 1.0\n" |
121 | +"Content-Type: text/plain; charset=UTF-8\n" |
122 | +"Content-Transfer-Encoding: 8bit\n" |
123 | +"Plural-Forms: \n" |
124 | + |
125 | +#. module: purchase_tax_include |
126 | +#: constraint:ir.ui.view:0 |
127 | +msgid "Invalid XML for View Architecture!" |
128 | +msgstr "¡XML inválido para la definición de la vista!" |
129 | + |
130 | +#. module: purchase_tax_include |
131 | +#: constraint:ir.model:0 |
132 | +msgid "The Object name must start with x_ and not contain any special character !" |
133 | +msgstr "¡El nombre del objeto debe empezar con x_ y no contener ningún carácter especial!" |
134 | + |
135 | +#. module: purchase_tax_include |
136 | +#: code:addons/purchase_tax_include/purchase_tax_incl.py:0 |
137 | +#, python-format |
138 | +msgid "You can't mix tax included and tax excluded purchases in one invoice!" |
139 | +msgstr "¡No puede mezclar compras con impuestos incluidos y excluidos en una factura!" |
140 | + |
141 | +#. module: purchase_tax_include |
142 | +#: field:purchase.order,price_type:0 |
143 | +msgid "Price method" |
144 | +msgstr "Método de precio" |
145 | + |
146 | +#. module: purchase_tax_include |
147 | +#: model:ir.module.module,shortdesc:purchase_tax_include.module_meta_information |
148 | +msgid "Purchases with taxes included" |
149 | +msgstr "Compras con impuestos incluidos" |
150 | + |
151 | +#. module: purchase_tax_include |
152 | +#: selection:purchase.order,price_type:0 |
153 | +msgid "Tax included" |
154 | +msgstr "Impuestos incluidos" |
155 | + |
156 | +#. module: purchase_tax_include |
157 | +#: model:ir.model,name:purchase_tax_include.model_purchase_order |
158 | +msgid "Purchase order" |
159 | +msgstr "Pedido de compra" |
160 | + |
161 | +#. module: purchase_tax_include |
162 | +#: code:addons/purchase_tax_include/purchase_tax_incl.py:0 |
163 | +#, python-format |
164 | +msgid "Error!" |
165 | +msgstr "¡Error!" |
166 | + |
167 | +#. module: purchase_tax_include |
168 | +#: selection:purchase.order,price_type:0 |
169 | +msgid "Tax excluded" |
170 | +msgstr "Impuestos excluidos" |
171 | + |
172 | +#. module: purchase_tax_include |
173 | +#: model:ir.model,name:purchase_tax_include.model_purchase_order_line |
174 | +msgid "Purchase Order lines" |
175 | +msgstr "Líneas del pedido de compra" |
176 | + |
177 | +#. module: purchase_tax_include |
178 | +#: model:ir.module.module,description:purchase_tax_include.module_meta_information |
179 | +msgid "This module allows you to use purchase order with prices including or excluding taxes." |
180 | +msgstr "Este módulo le permite usar órdenes de compra con precios con impuestos incluídos o excluidos." |
181 | + |
182 | +#. module: purchase_tax_include |
183 | +#: model:ir.model,name:purchase_tax_include.model_stock_picking |
184 | +msgid "Picking List" |
185 | +msgstr "Albarán" |
186 | + |
187 | +#. module: purchase_tax_include |
188 | +#: field:purchase.order.line,price_subtotal:0 |
189 | +msgid "Subtotal w/o tax" |
190 | +msgstr "Subtotal sin imp." |
191 | + |
192 | +#. module: purchase_tax_include |
193 | +#: field:purchase.order.line,price_subtotal_incl:0 |
194 | +msgid "Subtotal" |
195 | +msgstr "Subtotal" |
196 | + |
197 | |
198 | === modified file 'purchase_tax_include/i18n/fr_BE.po' (properties changed: +x to -x) |
199 | === modified file 'purchase_tax_include/i18n/purchase_tax_include.pot' (properties changed: +x to -x) |
200 | --- purchase_tax_include/i18n/purchase_tax_include.pot 2010-07-06 05:10:58 +0000 |
201 | +++ purchase_tax_include/i18n/purchase_tax_include.pot 2010-07-09 15:01:00 +0000 |
202 | @@ -4,10 +4,10 @@ |
203 | # |
204 | msgid "" |
205 | msgstr "" |
206 | -"Project-Id-Version: OpenERP Server 5.0.6\n" |
207 | +"Project-Id-Version: OpenERP Server 6.0dev\n" |
208 | "Report-Msgid-Bugs-To: support@openerp.com\n" |
209 | -"POT-Creation-Date: 2009-11-25 14:07:16+0000\n" |
210 | -"PO-Revision-Date: 2009-11-25 14:07:16+0000\n" |
211 | +"POT-Creation-Date: 2010-07-09 11:22:17+0000\n" |
212 | +"PO-Revision-Date: 2010-07-09 11:22:17+0000\n" |
213 | "Last-Translator: <>\n" |
214 | "Language-Team: \n" |
215 | "MIME-Version: 1.0\n" |
216 | @@ -21,6 +21,17 @@ |
217 | msgstr "" |
218 | |
219 | #. module: purchase_tax_include |
220 | +#: constraint:ir.model:0 |
221 | +msgid "The Object name must start with x_ and not contain any special character !" |
222 | +msgstr "" |
223 | + |
224 | +#. module: purchase_tax_include |
225 | +#: code:addons/purchase_tax_include/purchase_tax_incl.py:0 |
226 | +#, python-format |
227 | +msgid "You can't mix tax included and tax excluded purchases in one invoice!" |
228 | +msgstr "" |
229 | + |
230 | +#. module: purchase_tax_include |
231 | #: field:purchase.order,price_type:0 |
232 | msgid "Price method" |
233 | msgstr "" |
234 | @@ -36,16 +47,42 @@ |
235 | msgstr "" |
236 | |
237 | #. module: purchase_tax_include |
238 | +#: model:ir.model,name:purchase_tax_include.model_purchase_order |
239 | +msgid "Purchase order" |
240 | +msgstr "" |
241 | + |
242 | +#. module: purchase_tax_include |
243 | +#: code:addons/purchase_tax_include/purchase_tax_incl.py:0 |
244 | +#, python-format |
245 | +msgid "Error!" |
246 | +msgstr "" |
247 | + |
248 | +#. module: purchase_tax_include |
249 | #: selection:purchase.order,price_type:0 |
250 | msgid "Tax excluded" |
251 | msgstr "" |
252 | |
253 | #. module: purchase_tax_include |
254 | +#: model:ir.model,name:purchase_tax_include.model_purchase_order_line |
255 | +msgid "Purchase Order lines" |
256 | +msgstr "" |
257 | + |
258 | +#. module: purchase_tax_include |
259 | #: model:ir.module.module,description:purchase_tax_include.module_meta_information |
260 | msgid "This module allows you to use purchase order with prices including or excluding taxes." |
261 | msgstr "" |
262 | |
263 | #. module: purchase_tax_include |
264 | +#: model:ir.model,name:purchase_tax_include.model_stock_picking |
265 | +msgid "Picking List" |
266 | +msgstr "" |
267 | + |
268 | +#. module: purchase_tax_include |
269 | +#: field:purchase.order.line,price_subtotal:0 |
270 | +msgid "Subtotal w/o tax" |
271 | +msgstr "" |
272 | + |
273 | +#. module: purchase_tax_include |
274 | #: field:purchase.order.line,price_subtotal_incl:0 |
275 | msgid "Subtotal" |
276 | msgstr "" |
277 | |
278 | === modified file 'purchase_tax_include/purchase_tax_incl.py' (properties changed: +x to -x) |
279 | --- purchase_tax_include/purchase_tax_incl.py 2010-07-06 05:10:58 +0000 |
280 | +++ purchase_tax_include/purchase_tax_incl.py 2010-07-09 15:01:00 +0000 |
281 | @@ -1,3 +1,4 @@ |
282 | +# -*- encoding: utf-8 -*- |
283 | ############################################################################## |
284 | # |
285 | # OpenERP, Open Source Management Solution |
286 | @@ -18,80 +19,244 @@ |
287 | # |
288 | ############################################################################## |
289 | |
290 | -import time |
291 | -import netsvc |
292 | +__authors__ = [ |
293 | + "OpenERP S.A.", |
294 | + "Borja López Soilán (Pexego) <borjals@pexego.es>" |
295 | +] |
296 | + |
297 | from osv import fields, osv |
298 | -import ir |
299 | +import decimal_precision as dp |
300 | |
301 | class purchase_order(osv.osv): |
302 | + """ |
303 | + Extends the purchase order to allow using "tax included" prices. |
304 | + """ |
305 | _inherit = "purchase.order" |
306 | - def _amount_tax(self, cr, uid, ids, field_name, arg, context): |
307 | + |
308 | + def _amount_all(self, cr, uid, ids, field_name, arg, context): |
309 | + """ |
310 | + Overwrites/extends the amounts calculation to allow tax included prices. |
311 | + """ |
312 | res = {} |
313 | cur_obj=self.pool.get('res.currency') |
314 | for order in self.browse(cr, uid, ids): |
315 | - val = 0.0 |
316 | - cur=order.pricelist_id.currency_id |
317 | - for line in order.order_line: |
318 | - if order.price_type=='tax_included': |
319 | - ttt = self.pool.get('account.tax').compute_inv(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id, order.partner_id) |
320 | - else: |
321 | - ttt = self.pool.get('account.tax').compute(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id, order.partner_id) |
322 | - for c in ttt: |
323 | - val += cur_obj.round(cr, uid, cur, c['amount']) |
324 | - res[order.id]=cur_obj.round(cr, uid, cur, val) |
325 | + if order.price_type == 'tax_included': |
326 | + # |
327 | + # Use the tax included calculation |
328 | + # |
329 | + res[order.id] = { |
330 | + 'amount_untaxed': 0.0, |
331 | + 'amount_tax': 0.0, |
332 | + 'amount_total': 0.0, |
333 | + } |
334 | + val = val1 = 0.0 |
335 | + cur=order.pricelist_id.currency_id |
336 | + for line in order.order_line: |
337 | + for c in self.pool.get('account.tax').compute_inv(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id, order.partner_id): |
338 | + val+= c['amount'] |
339 | + val1 += line.price_subtotal |
340 | + res[order.id]['amount_tax']=cur_obj.round(cr, uid, cur, val) |
341 | + res[order.id]['amount_untaxed']=cur_obj.round(cr, uid, cur, val1) |
342 | + res[order.id]['amount_total']=res[order.id]['amount_untaxed'] + res[order.id]['amount_tax'] |
343 | + else: |
344 | + # |
345 | + # Use the default calculation |
346 | + # |
347 | + res = super(purchase_order, self)._amount_all(cr, uid, ids, field_name, arg, context) |
348 | return res |
349 | + |
350 | + |
351 | + def _get_order(self, cr, uid, ids, context={}): |
352 | + """ |
353 | + Returns the orders that must be updated when some order lines change. |
354 | + """ |
355 | + result = {} |
356 | + for line in self.pool.get('purchase.order.line').browse(cr, uid, ids, context=context): |
357 | + result[line.order_id.id] = True |
358 | + return result.keys() |
359 | + |
360 | _columns = { |
361 | 'price_type': fields.selection([ |
362 | ('tax_included','Tax included'), |
363 | ('tax_excluded','Tax excluded') |
364 | ], 'Price method', required=True), |
365 | - 'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'), |
366 | + 'amount_untaxed': fields.function(_amount_all, method=True, digits_compute=dp.get_precision('Purchase Price'), string='Untaxed Amount', |
367 | + store={ |
368 | + 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20), |
369 | + 'purchase.order.line': (_get_order, None, 10), |
370 | + }, multi="sums"), |
371 | + 'amount_tax': fields.function(_amount_all, method=True, digits_compute=dp.get_precision('Purchase Price'), string='Taxes', |
372 | + store={ |
373 | + 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20), |
374 | + 'purchase.order.line': (_get_order, None, 10), |
375 | + }, multi="sums"), |
376 | + 'amount_total': fields.function(_amount_all, method=True, digits_compute=dp.get_precision('Purchase Price'), string='Total', |
377 | + store={ |
378 | + 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20), |
379 | + 'purchase.order.line': (_get_order, None, 10), |
380 | + }, multi="sums"), |
381 | } |
382 | + |
383 | _defaults = { |
384 | 'price_type': lambda *a: 'tax_excluded', |
385 | } |
386 | + |
387 | def _inv_get(self, cr, uid, order, context={}): |
388 | + """ |
389 | + Returns the columns as a dictionary. |
390 | + """ |
391 | return { |
392 | 'price_type': order.price_type |
393 | } |
394 | + |
395 | + |
396 | + def action_invoice_create(self, cr, uid, ids, *args): |
397 | + """ |
398 | + Extend the invoice creation action to set the price type if needed. |
399 | + """ |
400 | + # |
401 | + # Count how many orders have tax included prices. |
402 | + # |
403 | + tax_included_count = 0 |
404 | + orders = self.browse(cr, uid, ids) |
405 | + for order in orders: |
406 | + if order.price_type == 'tax_included': |
407 | + tax_included_count += 1 |
408 | + |
409 | + if tax_included_count: |
410 | + if len(orders) == tax_included_count: |
411 | + # |
412 | + # Every order has tax include prices, we must create the invoice |
413 | + # and (afterwards) set the price type and recalculate. |
414 | + # |
415 | + invoice_id = super(purchase_order, self).action_invoice_create(cr, uid, ids, args) |
416 | + self.pool.get('account.invoice').write(cr, uid, [invoice_id], { 'price_type': 'tax_included' }) |
417 | + self.pool.get('account.invoice').button_compute(cr, uid, [invoice_id], {'type': 'in_invoice'}, set_total=True) |
418 | + else: |
419 | + # We have no current way of creating an invoice mixing |
420 | + # tax included and tax excluded prices, so we just fail: |
421 | + raise osv.except_osv(_('Error!'), _("You can't mix tax included and tax excluded purchases in one invoice!")) |
422 | + else: |
423 | + # All the invoices are 'tax excluded', that's the default value |
424 | + # so we just let the default method create the invoice. |
425 | + invoice_id = super(purchase_order, self).action_invoice_create(cr, uid, ids, args) |
426 | + |
427 | + return invoice_id |
428 | + |
429 | + |
430 | purchase_order() |
431 | |
432 | class purchase_order_line(osv.osv): |
433 | + """ |
434 | + Extends the purchase order lines to alter the calculation when |
435 | + tax includes prices are used. |
436 | + """ |
437 | _inherit = 'purchase.order.line' |
438 | + |
439 | def _amount_line(self, cr, uid, ids, name, arg, context): |
440 | - res = {} |
441 | - cur_obj=self.pool.get('res.currency') |
442 | - tax_obj = self.pool.get('account.tax') |
443 | - res = super(purchase_order_line, self)._amount_line(cr, uid, ids, name, arg, context) |
444 | - res2 = res.copy() |
445 | - for line in self.browse(cr, uid, ids): |
446 | - if line.order_id.price_type == 'tax_included': |
447 | - if line.product_id: |
448 | - for tax in tax_obj.compute_inv(cr, uid, line.product_id.supplier_taxes_id, res[line.id]/line.product_qty, line.product_qty): |
449 | - res[line.id] = res[line.id] - tax['amount'] |
450 | - else: |
451 | - for tax in tax_obj.compute_inv(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty): |
452 | - res[line.id] = res[line.id] - tax['amount'] |
453 | - if name == 'price_subtotal_incl' and line.order_id.price_type == 'tax_included': |
454 | - if line.product_id: |
455 | - prod_taxe_ids = [ t.id for t in line.product_id.supplier_taxes_id ] |
456 | - prod_taxe_ids.sort() |
457 | - line_taxe_ids = [ t.id for t in line.taxes_id ] |
458 | - line_taxe_ids.sort() |
459 | - if line.product_id and prod_taxe_ids == line_taxe_ids: |
460 | - res[line.id] = res2[line.id] |
461 | - elif not line.product_id: |
462 | - res[line.id] = res2[line.id] |
463 | - else: |
464 | - for tax in tax_obj.compute(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty): |
465 | - res[line.id] = res[line.id] + tax['amount'] |
466 | - cur = line.order_id.pricelist_id.currency_id |
467 | - res[line.id] = cur_obj.round(cr, uid, cur, res[line.id]) |
468 | - return res |
469 | + """ |
470 | + Calculate the subtotal for the line without taxes. |
471 | + """ |
472 | + # Use the original method to calculate the amounts: |
473 | + res = super(purchase_order_line, self)._amount_line(cr, uid, ids, 'price_subtotal', arg, context) |
474 | + # Check if we are using 'tax_included' prices: |
475 | + if ids and self.browse(cr, uid, ids[0]).order_id.price_type == 'tax_included': |
476 | + # |
477 | + # Tax included => Remove the taxes from the line amounts. |
478 | + # |
479 | + cur_facade=self.pool.get('res.currency') |
480 | + tax_facade = self.pool.get('account.tax') |
481 | + for line in self.browse(cr, uid, ids): |
482 | + for tax in tax_facade.compute_inv(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty): |
483 | + res[line.id] = res[line.id] - tax['amount'] |
484 | + cur = line.order_id.pricelist_id.currency_id |
485 | + res[line.id] = cur_facade.round(cr, uid, cur, res[line.id]) |
486 | + return res |
487 | + |
488 | + def _amount_line_incl(self, cr, uid, ids, name, arg, context): |
489 | + """ |
490 | + Calculate the subtotal for the line with taxes. |
491 | + """ |
492 | + # Use the original method to calculate the amounts: |
493 | + res = super(purchase_order_line, self)._amount_line(cr, uid, ids, 'price_subtotal', arg, context) |
494 | + # Check if we *aren't* using 'tax_included' prices on the subtotal: |
495 | + if ids and self.browse(cr, uid, ids[0]).order_id.price_type != 'tax_included': |
496 | + # |
497 | + # Tax excluded on the subtotal => Add taxes here from the line amounts. |
498 | + # |
499 | + cur_facade=self.pool.get('res.currency') |
500 | + tax_facade = self.pool.get('account.tax') |
501 | + for line in self.browse(cr, uid, ids): |
502 | + for tax in tax_facade.compute(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty): |
503 | + res[line.id] = res[line.id] + tax['amount'] |
504 | + cur = line.order_id.pricelist_id.currency_id |
505 | + res[line.id] = cur_facade.round(cr, uid, cur, res[line.id]) |
506 | + return res |
507 | + |
508 | + |
509 | _columns = { |
510 | - 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o tax'), |
511 | - 'price_subtotal_incl': fields.function(_amount_line, method=True, string='Subtotal'), |
512 | + 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o tax', digits_compute=dp.get_precision('Purchase Price')), |
513 | + 'price_subtotal_incl': fields.function(_amount_line_incl, method=True, string='Subtotal', digits_compute=dp.get_precision('Purchase Price')), |
514 | } |
515 | purchase_order_line() |
516 | -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
517 | + |
518 | +class stock_picking(osv.osv): |
519 | + """ |
520 | + Extends the stock pickings to manage the creation of invoices with |
521 | + tax included prices when the original order had tax included prices. |
522 | + """ |
523 | + _inherit = 'stock.picking' |
524 | + _description = "Picking list" |
525 | + |
526 | + def action_invoice_create(self, cr, uid, ids, journal_id=False, |
527 | + group=False, type='out_invoice', context=None): |
528 | + """ |
529 | + Extend the invoice creation action to set the price type if needed. |
530 | + """ |
531 | + # |
532 | + # Count how many pickings have tax included prices. |
533 | + # |
534 | + tax_included_count = 0 |
535 | + lines_count = 0 |
536 | + pickings = self.browse(cr, uid, ids, context=context) |
537 | + for picking in pickings: |
538 | + # |
539 | + # We must find the orders associated with this picking and check |
540 | + # if they have tax included prices. |
541 | + # As picking lines may come from different orders (even if it is |
542 | + # not the usual), we must check it line by line. |
543 | + # |
544 | + for move in picking.move_lines: |
545 | + if move.purchase_line_id and move.purchase_line_id.order_id: |
546 | + lines_count += 1 |
547 | + if move.purchase_line_id.order_id.price_type == 'tax_included': |
548 | + tax_included_count += 1 |
549 | + |
550 | + if tax_included_count: |
551 | + if lines_count == tax_included_count: |
552 | + # |
553 | + # Every order has tax include prices, we must create the invoice |
554 | + # and (afterwards) set the price type and recalculate. |
555 | + # |
556 | + invoices_map = super(stock_picking, self).action_invoice_create(cr, |
557 | + uid, ids, journal_id=journal_id, |
558 | + group=group, type=type, |
559 | + context=context) |
560 | + invoice_ids = list(set(invoices_map.values())) |
561 | + self.pool.get('account.invoice').write(cr, uid, invoice_ids, { 'price_type': 'tax_included' }) |
562 | + self.pool.get('account.invoice').button_compute(cr, uid, invoice_ids, {'type': 'in_invoice'}, set_total=True) |
563 | + else: |
564 | + # We have no current way of creating an invoice mixing |
565 | + # tax included and tax excluded prices, so we just fail: |
566 | + raise osv.except_osv(_('Error!'), _("You can't mix tax included and tax excluded purchases in one invoice!")) |
567 | + else: |
568 | + # All the invoices are 'tax excluded', that's the default value |
569 | + # so we just let the default method create the invoice. |
570 | + invoices_map = super(stock_picking, self).action_invoice_create(cr, |
571 | + uid, ids, journal_id=journal_id, |
572 | + group=group, type=type, |
573 | + context=context) |
574 | + return invoices_map |
575 | + |
576 | +stock_picking() |
577 | |
578 | |
579 | === modified file 'purchase_tax_include/purchase_tax_incl.xml' (properties changed: +x to -x) |
580 | --- purchase_tax_include/purchase_tax_incl.xml 2010-07-06 05:10:58 +0000 |
581 | +++ purchase_tax_include/purchase_tax_incl.xml 2010-07-09 15:01:00 +0000 |
582 | @@ -1,31 +1,43 @@ |
583 | -<?xml version="1.0"?> |
584 | +<?xml version="1.0" encoding="utf-8"?> |
585 | <openerp> |
586 | -<data> |
587 | - |
588 | - <record model="ir.ui.view" id="account_tax_view_price"> |
589 | - <field name="name">purchase.order.exlcuded.view.form</field> |
590 | - <field name="type">form</field> |
591 | - <field name="model">purchase.order</field> |
592 | - <field name="inherit_id" ref="purchase.purchase_order_form" /> |
593 | - <field name="arch" type="xml"> |
594 | - <field name="origin" position="after"> |
595 | - <field name="price_type"/> |
596 | - </field> |
597 | - </field> |
598 | - </record> |
599 | - |
600 | - <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl"> |
601 | - <field name="name">purchase.order.line.tree</field> |
602 | - <field name="type">tree</field> |
603 | - <field name="model">purchase.order.line</field> |
604 | - <field name="inherit_id" ref="purchase.purchase_order_line_tree" /> |
605 | - <field name="arch" type="xml"> |
606 | - <field name="price_subtotal" position="after"> |
607 | - <field name="price_subtotal_incl"/> |
608 | - </field> |
609 | - </field> |
610 | - </record> |
611 | - |
612 | -</data> |
613 | + <data> |
614 | + |
615 | + <record model="ir.ui.view" id="account_tax_view_price"> |
616 | + <field name="name">purchase.order.form.add_price_type</field> |
617 | + <field name="type">form</field> |
618 | + <field name="model">purchase.order</field> |
619 | + <field name="inherit_id" ref="purchase.purchase_order_form" /> |
620 | + <field name="arch" type="xml"> |
621 | + <field name="shipped" position="after"> |
622 | + <field name="price_type"/> |
623 | + </field> |
624 | + </field> |
625 | + </record> |
626 | + |
627 | + <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl"> |
628 | + <field name="name">purchase.order.line.tree.add_price_subtotal_incl</field> |
629 | + <field name="type">tree</field> |
630 | + <field name="model">purchase.order.line</field> |
631 | + <field name="inherit_id" ref="purchase.purchase_order_line_tree" /> |
632 | + <field name="arch" type="xml"> |
633 | + <field name="price_subtotal" position="after"> |
634 | + <field name="price_subtotal_incl"/> |
635 | + </field> |
636 | + </field> |
637 | + </record> |
638 | + |
639 | + <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl"> |
640 | + <field name="name">purchase.order.form.add_price_subtotal_incl_to_lines</field> |
641 | + <field name="type">form</field> |
642 | + <field name="model">purchase.order</field> |
643 | + <field name="inherit_id" ref="purchase.purchase_order_form" /> |
644 | + <field name="arch" type="xml"> |
645 | + <xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after"> |
646 | + <field name="price_subtotal_incl"/> |
647 | + </xpath> |
648 | + </field> |
649 | + </record> |
650 | + |
651 | + </data> |
652 | </openerp> |
653 |
I'm not a core team reviewer, but please allow me to share a few comments on the form:
- you should add a proper default context in the methods
- maybe you shouldn't bump the version number to 2.0 unless you provide a migration script (then the server can apply it automatically).
- would you care to write a few YAML test to prove it works?
I hope you don't mind my intervention.
Lionel