Merge lp:~borjals/openobject-addons/extra-5.0-bugfix-603100 into lp:openobject-addons/extra-5.0

Proposed by Borja López Soilán (NeoPolus)
Status: Merged
Merged at revision: 4462
Proposed branch: lp:~borjals/openobject-addons/extra-5.0-bugfix-603100
Merge into: lp:openobject-addons/extra-5.0
Diff against target: 731 lines (+515/-107)
7 files modified
purchase_tax_include/__init__.py (+15/-11)
purchase_tax_include/__terp__.py (+10/-11)
purchase_tax_include/i18n/es_ES.po (+89/-0)
purchase_tax_include/i18n/fr_BE.po (+52/-0)
purchase_tax_include/i18n/purchase_tax_include.pot (+89/-0)
purchase_tax_include/purchase_tax_incl.py (+220/-57)
purchase_tax_include/purchase_tax_incl.xml (+40/-28)
To merge this branch: bzr merge lp:~borjals/openobject-addons/extra-5.0-bugfix-603100
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+29567@code.launchpad.net

Description of the change

Complete rewrite of the purchase_tax_include module to address multiple bugs.

- 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 from the 5.0 addons since Dec 2008.

- Now correct 'amount_untaxed' and 'amount_total' are shown on the
  purchase order totals.

- Now 'price_subtotal_incl' column is properly displayed on the
  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.

To post a comment you must log in.
Revision history for this message
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 (on trunk). As in its current state purchase_tax_include is not usable at all, I think I'll just merge it tomorrow.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'purchase_tax_include/__init__.py'
2--- purchase_tax_include/__init__.py 2008-11-03 19:56:05 +0000
3+++ purchase_tax_include/__init__.py 2010-07-09 15:01:37 +0000
4@@ -1,25 +1,29 @@
5 # -*- encoding: utf-8 -*-
6 ##############################################################################
7-#
8-# OpenERP, Open Source Management Solution
9-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
10-# $Id$
11+#
12+# OpenERP, Open Source Management Solution
13+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
14 #
15 # This program is free software: you can redistribute it and/or modify
16-# it under the terms of the GNU General Public License as published by
17-# the Free Software Foundation, either version 3 of the License, or
18-# (at your option) any later version.
19+# it under the terms of the GNU Affero General Public License as
20+# published by the Free Software Foundation, either version 3 of the
21+# License, or (at your option) any later version.
22 #
23 # This program is distributed in the hope that it will be useful,
24 # but WITHOUT ANY WARRANTY; without even the implied warranty of
25 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26-# GNU General Public License for more details.
27+# GNU Affero General Public License for more details.
28 #
29-# You should have received a copy of the GNU General Public License
30-# along with this program. If not, see <http://www.gnu.org/licenses/>.
31+# You should have received a copy of the GNU Affero General Public License
32+# along with this program. If not, see <http://www.gnu.org/licenses/>.
33 #
34 ##############################################################################
35
36+__authors__ = [
37+ "OpenERP S.A.",
38+ "Borja López Soilán (Pexego) <borjals@pexego.es>"
39+]
40+
41 import purchase_tax_incl
42-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
43+
44
45
46=== modified file 'purchase_tax_include/__terp__.py'
47--- purchase_tax_include/__terp__.py 2009-02-17 12:57:51 +0000
48+++ purchase_tax_include/__terp__.py 2010-07-09 15:01:37 +0000
49@@ -1,27 +1,26 @@
50 # -*- encoding: utf-8 -*-
51 ##############################################################################
52-#
53-# OpenERP, Open Source Management Solution
54-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
55-# $Id$
56+#
57+# OpenERP, Open Source Management Solution
58+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
59 #
60 # This program is free software: you can redistribute it and/or modify
61-# it under the terms of the GNU General Public License as published by
62-# the Free Software Foundation, either version 3 of the License, or
63-# (at your option) any later version.
64+# it under the terms of the GNU Affero General Public License as
65+# published by the Free Software Foundation, either version 3 of the
66+# License, or (at your option) any later version.
67 #
68 # This program is distributed in the hope that it will be useful,
69 # but WITHOUT ANY WARRANTY; without even the implied warranty of
70 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71-# GNU General Public License for more details.
72+# GNU Affero General Public License for more details.
73 #
74-# You should have received a copy of the GNU General Public License
75-# along with this program. If not, see <http://www.gnu.org/licenses/>.
76+# You should have received a copy of the GNU Affero General Public License
77+# along with this program. If not, see <http://www.gnu.org/licenses/>.
78 #
79 ##############################################################################
80 {
81 "name" : "Purchases with taxes included",
82- "version" : "1.0",
83+ "version" : "2.0",
84 "depends" : ["purchase","account_tax_include"],
85 "author" : "Tiny",
86 "website" : "http://www.openerp.com",
87
88=== added directory 'purchase_tax_include/i18n'
89=== added file 'purchase_tax_include/i18n/es_ES.po'
90--- purchase_tax_include/i18n/es_ES.po 1970-01-01 00:00:00 +0000
91+++ purchase_tax_include/i18n/es_ES.po 2010-07-09 15:01:37 +0000
92@@ -0,0 +1,89 @@
93+# Translation of OpenERP Server.
94+# This file contains the translation of the following modules:
95+# * purchase_tax_include
96+#
97+msgid ""
98+msgstr ""
99+"Project-Id-Version: OpenERP Server 6.0dev\n"
100+"Report-Msgid-Bugs-To: support@openerp.com\n"
101+"POT-Creation-Date: 2010-07-09 11:24:53+0000\n"
102+"PO-Revision-Date: 2010-07-09 13:32+0100\n"
103+"Last-Translator: Borja López Soilán (Pexego) <borjals@pexego.es>\n"
104+"Language-Team: \n"
105+"MIME-Version: 1.0\n"
106+"Content-Type: text/plain; charset=UTF-8\n"
107+"Content-Transfer-Encoding: 8bit\n"
108+"Plural-Forms: \n"
109+
110+#. module: purchase_tax_include
111+#: constraint:ir.ui.view:0
112+msgid "Invalid XML for View Architecture!"
113+msgstr "¡XML inválido para la definición de la vista!"
114+
115+#. module: purchase_tax_include
116+#: constraint:ir.model:0
117+msgid "The Object name must start with x_ and not contain any special character !"
118+msgstr "¡El nombre del objeto debe empezar con x_ y no contener ningún carácter especial!"
119+
120+#. module: purchase_tax_include
121+#: code:addons/purchase_tax_include/purchase_tax_incl.py:0
122+#, python-format
123+msgid "You can't mix tax included and tax excluded purchases in one invoice!"
124+msgstr "¡No puede mezclar compras con impuestos incluidos y excluidos en una factura!"
125+
126+#. module: purchase_tax_include
127+#: field:purchase.order,price_type:0
128+msgid "Price method"
129+msgstr "Método de precio"
130+
131+#. module: purchase_tax_include
132+#: model:ir.module.module,shortdesc:purchase_tax_include.module_meta_information
133+msgid "Purchases with taxes included"
134+msgstr "Compras con impuestos incluidos"
135+
136+#. module: purchase_tax_include
137+#: selection:purchase.order,price_type:0
138+msgid "Tax included"
139+msgstr "Impuestos incluidos"
140+
141+#. module: purchase_tax_include
142+#: model:ir.model,name:purchase_tax_include.model_purchase_order
143+msgid "Purchase order"
144+msgstr "Pedido de compra"
145+
146+#. module: purchase_tax_include
147+#: code:addons/purchase_tax_include/purchase_tax_incl.py:0
148+#, python-format
149+msgid "Error!"
150+msgstr "¡Error!"
151+
152+#. module: purchase_tax_include
153+#: selection:purchase.order,price_type:0
154+msgid "Tax excluded"
155+msgstr "Impuestos excluidos"
156+
157+#. module: purchase_tax_include
158+#: model:ir.model,name:purchase_tax_include.model_purchase_order_line
159+msgid "Purchase Order lines"
160+msgstr "Líneas del pedido de compra"
161+
162+#. module: purchase_tax_include
163+#: model:ir.module.module,description:purchase_tax_include.module_meta_information
164+msgid "This module allows you to use purchase order with prices including or excluding taxes."
165+msgstr "Este módulo le permite usar órdenes de compra con precios con impuestos incluídos o excluidos."
166+
167+#. module: purchase_tax_include
168+#: model:ir.model,name:purchase_tax_include.model_stock_picking
169+msgid "Picking List"
170+msgstr "Albarán"
171+
172+#. module: purchase_tax_include
173+#: field:purchase.order.line,price_subtotal:0
174+msgid "Subtotal w/o tax"
175+msgstr "Subtotal sin imp."
176+
177+#. module: purchase_tax_include
178+#: field:purchase.order.line,price_subtotal_incl:0
179+msgid "Subtotal"
180+msgstr "Subtotal"
181+
182
183=== added file 'purchase_tax_include/i18n/fr_BE.po'
184--- purchase_tax_include/i18n/fr_BE.po 1970-01-01 00:00:00 +0000
185+++ purchase_tax_include/i18n/fr_BE.po 2010-07-09 15:01:37 +0000
186@@ -0,0 +1,52 @@
187+# Translation of OpenERP Server.
188+# This file contains the translation of the following modules:
189+# * purchase_tax_include
190+#
191+msgid ""
192+msgstr ""
193+"Project-Id-Version: OpenERP Server 5.0.6\n"
194+"Report-Msgid-Bugs-To: support@openerp.com\n"
195+"POT-Creation-Date: 2009-11-25 14:07:16+0000\n"
196+"PO-Revision-Date: 2009-11-25 14:07:16+0000\n"
197+"Last-Translator: <>\n"
198+"Language-Team: \n"
199+"MIME-Version: 1.0\n"
200+"Content-Type: text/plain; charset=UTF-8\n"
201+"Content-Transfer-Encoding: \n"
202+"Plural-Forms: \n"
203+
204+#. module: purchase_tax_include
205+#: constraint:ir.ui.view:0
206+msgid "Invalid XML for View Architecture!"
207+msgstr ""
208+
209+#. module: purchase_tax_include
210+#: field:purchase.order,price_type:0
211+msgid "Price method"
212+msgstr ""
213+
214+#. module: purchase_tax_include
215+#: model:ir.module.module,shortdesc:purchase_tax_include.module_meta_information
216+msgid "Purchases with taxes included"
217+msgstr ""
218+
219+#. module: purchase_tax_include
220+#: selection:purchase.order,price_type:0
221+msgid "Tax included"
222+msgstr ""
223+
224+#. module: purchase_tax_include
225+#: selection:purchase.order,price_type:0
226+msgid "Tax excluded"
227+msgstr ""
228+
229+#. module: purchase_tax_include
230+#: model:ir.module.module,description:purchase_tax_include.module_meta_information
231+msgid "This module allows you to use purchase order with prices including or excluding taxes."
232+msgstr ""
233+
234+#. module: purchase_tax_include
235+#: field:purchase.order.line,price_subtotal_incl:0
236+msgid "Subtotal"
237+msgstr ""
238+
239
240=== added file 'purchase_tax_include/i18n/purchase_tax_include.pot'
241--- purchase_tax_include/i18n/purchase_tax_include.pot 1970-01-01 00:00:00 +0000
242+++ purchase_tax_include/i18n/purchase_tax_include.pot 2010-07-09 15:01:37 +0000
243@@ -0,0 +1,89 @@
244+# Translation of OpenERP Server.
245+# This file contains the translation of the following modules:
246+# * purchase_tax_include
247+#
248+msgid ""
249+msgstr ""
250+"Project-Id-Version: OpenERP Server 6.0dev\n"
251+"Report-Msgid-Bugs-To: support@openerp.com\n"
252+"POT-Creation-Date: 2010-07-09 11:22:17+0000\n"
253+"PO-Revision-Date: 2010-07-09 11:22:17+0000\n"
254+"Last-Translator: <>\n"
255+"Language-Team: \n"
256+"MIME-Version: 1.0\n"
257+"Content-Type: text/plain; charset=UTF-8\n"
258+"Content-Transfer-Encoding: \n"
259+"Plural-Forms: \n"
260+
261+#. module: purchase_tax_include
262+#: constraint:ir.ui.view:0
263+msgid "Invalid XML for View Architecture!"
264+msgstr ""
265+
266+#. module: purchase_tax_include
267+#: constraint:ir.model:0
268+msgid "The Object name must start with x_ and not contain any special character !"
269+msgstr ""
270+
271+#. module: purchase_tax_include
272+#: code:addons/purchase_tax_include/purchase_tax_incl.py:0
273+#, python-format
274+msgid "You can't mix tax included and tax excluded purchases in one invoice!"
275+msgstr ""
276+
277+#. module: purchase_tax_include
278+#: field:purchase.order,price_type:0
279+msgid "Price method"
280+msgstr ""
281+
282+#. module: purchase_tax_include
283+#: model:ir.module.module,shortdesc:purchase_tax_include.module_meta_information
284+msgid "Purchases with taxes included"
285+msgstr ""
286+
287+#. module: purchase_tax_include
288+#: selection:purchase.order,price_type:0
289+msgid "Tax included"
290+msgstr ""
291+
292+#. module: purchase_tax_include
293+#: model:ir.model,name:purchase_tax_include.model_purchase_order
294+msgid "Purchase order"
295+msgstr ""
296+
297+#. module: purchase_tax_include
298+#: code:addons/purchase_tax_include/purchase_tax_incl.py:0
299+#, python-format
300+msgid "Error!"
301+msgstr ""
302+
303+#. module: purchase_tax_include
304+#: selection:purchase.order,price_type:0
305+msgid "Tax excluded"
306+msgstr ""
307+
308+#. module: purchase_tax_include
309+#: model:ir.model,name:purchase_tax_include.model_purchase_order_line
310+msgid "Purchase Order lines"
311+msgstr ""
312+
313+#. module: purchase_tax_include
314+#: model:ir.module.module,description:purchase_tax_include.module_meta_information
315+msgid "This module allows you to use purchase order with prices including or excluding taxes."
316+msgstr ""
317+
318+#. module: purchase_tax_include
319+#: model:ir.model,name:purchase_tax_include.model_stock_picking
320+msgid "Picking List"
321+msgstr ""
322+
323+#. module: purchase_tax_include
324+#: field:purchase.order.line,price_subtotal:0
325+msgid "Subtotal w/o tax"
326+msgstr ""
327+
328+#. module: purchase_tax_include
329+#: field:purchase.order.line,price_subtotal_incl:0
330+msgid "Subtotal"
331+msgstr ""
332+
333
334=== modified file 'purchase_tax_include/purchase_tax_incl.py'
335--- purchase_tax_include/purchase_tax_incl.py 2008-11-03 19:56:05 +0000
336+++ purchase_tax_include/purchase_tax_incl.py 2010-07-09 15:01:37 +0000
337@@ -1,99 +1,262 @@
338 # -*- encoding: utf-8 -*-
339 ##############################################################################
340-#
341-# OpenERP, Open Source Management Solution
342-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
343-# $Id$
344+#
345+# OpenERP, Open Source Management Solution
346+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
347 #
348 # This program is free software: you can redistribute it and/or modify
349-# it under the terms of the GNU General Public License as published by
350-# the Free Software Foundation, either version 3 of the License, or
351-# (at your option) any later version.
352+# it under the terms of the GNU Affero General Public License as
353+# published by the Free Software Foundation, either version 3 of the
354+# License, or (at your option) any later version.
355 #
356 # This program is distributed in the hope that it will be useful,
357 # but WITHOUT ANY WARRANTY; without even the implied warranty of
358 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
359-# GNU General Public License for more details.
360+# GNU Affero General Public License for more details.
361 #
362-# You should have received a copy of the GNU General Public License
363-# along with this program. If not, see <http://www.gnu.org/licenses/>.
364+# You should have received a copy of the GNU Affero General Public License
365+# along with this program. If not, see <http://www.gnu.org/licenses/>.
366 #
367 ##############################################################################
368
369-import time
370-import netsvc
371+__authors__ = [
372+ "OpenERP S.A.",
373+ "Borja López Soilán (Pexego) <borjals@pexego.es>"
374+]
375+
376 from osv import fields, osv
377-import ir
378+from tools import config
379
380 class purchase_order(osv.osv):
381+ """
382+ Extends the purchase order to allow using "tax included" prices.
383+ """
384 _inherit = "purchase.order"
385- def _amount_tax(self, cr, uid, ids, field_name, arg, context):
386+
387+ def _amount_all(self, cr, uid, ids, field_name, arg, context):
388+ """
389+ Overwrites/extends the amounts calculation to allow tax included prices.
390+ """
391 res = {}
392 cur_obj=self.pool.get('res.currency')
393 for order in self.browse(cr, uid, ids):
394- val = 0.0
395- cur=order.pricelist_id.currency_id
396- for line in order.order_line:
397- if order.price_type=='tax_included':
398- 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)
399- else:
400- 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)
401- for c in ttt:
402- val += cur_obj.round(cr, uid, cur, c['amount'])
403- res[order.id]=cur_obj.round(cr, uid, cur, val)
404+ if order.price_type == 'tax_included':
405+ #
406+ # Use the tax included calculation
407+ #
408+ res[order.id] = {
409+ 'amount_untaxed': 0.0,
410+ 'amount_tax': 0.0,
411+ 'amount_total': 0.0,
412+ }
413+ val = val1 = 0.0
414+ cur=order.pricelist_id.currency_id
415+ for line in order.order_line:
416+ 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):
417+ val+= c['amount']
418+ val1 += line.price_subtotal
419+ res[order.id]['amount_tax']=cur_obj.round(cr, uid, cur, val)
420+ res[order.id]['amount_untaxed']=cur_obj.round(cr, uid, cur, val1)
421+ res[order.id]['amount_total']=res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
422+ else:
423+ #
424+ # Use the default calculation
425+ #
426+ res = super(purchase_order, self)._amount_all(cr, uid, ids, field_name, arg, context)
427 return res
428+
429+
430+ def _get_order(self, cr, uid, ids, context={}):
431+ """
432+ Returns the orders that must be updated when some order lines change.
433+ """
434+ result = {}
435+ for line in self.pool.get('purchase.order.line').browse(cr, uid, ids, context=context):
436+ result[line.order_id.id] = True
437+ return result.keys()
438+
439 _columns = {
440 'price_type': fields.selection([
441 ('tax_included','Tax included'),
442 ('tax_excluded','Tax excluded')
443 ], 'Price method', required=True),
444- 'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'),
445+ 'amount_untaxed': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])), string='Untaxed Amount',
446+ store={
447+ 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20),
448+ 'purchase.order.line': (_get_order, None, 10),
449+ }, multi="sums"),
450+ 'amount_tax': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])), string='Taxes',
451+ store={
452+ 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20),
453+ 'purchase.order.line': (_get_order, None, 10),
454+ }, multi="sums"),
455+ 'amount_total': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])), string='Total',
456+ store={
457+ 'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['price_type'], 20),
458+ 'purchase.order.line': (_get_order, None, 10),
459+ }, multi="sums"),
460 }
461+
462 _defaults = {
463 'price_type': lambda *a: 'tax_excluded',
464 }
465+
466 def _inv_get(self, cr, uid, order, context={}):
467+ """
468+ Returns the columns as a dictionary.
469+ """
470 return {
471 'price_type': order.price_type
472 }
473+
474+
475+ def action_invoice_create(self, cr, uid, ids, *args):
476+ """
477+ Extend the invoice creation action to set the price type if needed.
478+ """
479+ #
480+ # Count how many orders have tax included prices.
481+ #
482+ tax_included_count = 0
483+ orders = self.browse(cr, uid, ids)
484+ for order in orders:
485+ if order.price_type == 'tax_included':
486+ tax_included_count += 1
487+
488+ if tax_included_count:
489+ if len(orders) == tax_included_count:
490+ #
491+ # Every order has tax include prices, we must create the invoice
492+ # and (afterwards) set the price type and recalculate.
493+ #
494+ invoice_id = super(purchase_order, self).action_invoice_create(cr, uid, ids, args)
495+ self.pool.get('account.invoice').write(cr, uid, [invoice_id], { 'price_type': 'tax_included' })
496+ self.pool.get('account.invoice').button_compute(cr, uid, [invoice_id], {'type': 'in_invoice'}, set_total=True)
497+ else:
498+ # We have no current way of creating an invoice mixing
499+ # tax included and tax excluded prices, so we just fail:
500+ raise osv.except_osv(_('Error!'), _("You can't mix tax included and tax excluded purchases in one invoice!"))
501+ else:
502+ # All the invoices are 'tax excluded', that's the default value
503+ # so we just let the default method create the invoice.
504+ invoice_id = super(purchase_order, self).action_invoice_create(cr, uid, ids, args)
505+
506+ return invoice_id
507+
508+
509 purchase_order()
510
511 class purchase_order_line(osv.osv):
512+ """
513+ Extends the purchase order lines to alter the calculation when
514+ tax includes prices are used.
515+ """
516 _inherit = 'purchase.order.line'
517+
518 def _amount_line(self, cr, uid, ids, name, arg, context):
519- res = {}
520- cur_obj=self.pool.get('res.currency')
521- tax_obj = self.pool.get('account.tax')
522- res = super(purchase_order_line, self)._amount_line(cr, uid, ids, name, arg, context)
523- res2 = res.copy()
524- for line in self.browse(cr, uid, ids):
525- if line.order_id.price_type == 'tax_included':
526- if line.product_id:
527- for tax in tax_obj.compute_inv(cr, uid, line.product_id.supplier_taxes_id, res[line.id]/line.product_qty, line.product_qty):
528- res[line.id] = res[line.id] - tax['amount']
529- else:
530- for tax in tax_obj.compute_inv(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty):
531- res[line.id] = res[line.id] - tax['amount']
532- if name == 'price_subtotal_incl' and line.order_id.price_type == 'tax_included':
533- if line.product_id:
534- prod_taxe_ids = [ t.id for t in line.product_id.supplier_taxes_id ]
535- prod_taxe_ids.sort()
536- line_taxe_ids = [ t.id for t in line.taxes_id ]
537- line_taxe_ids.sort()
538- if line.product_id and prod_taxe_ids == line_taxe_ids:
539- res[line.id] = res2[line.id]
540- elif not line.product_id:
541- res[line.id] = res2[line.id]
542- else:
543- for tax in tax_obj.compute(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty):
544- res[line.id] = res[line.id] + tax['amount']
545- cur = line.order_id.pricelist_id.currency_id
546- res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
547- return res
548+ """
549+ Calculate the subtotal for the line without taxes.
550+ """
551+ # Use the original method to calculate the amounts:
552+ res = super(purchase_order_line, self)._amount_line(cr, uid, ids, 'price_subtotal', arg, context)
553+ # Check if we are using 'tax_included' prices:
554+ if ids and self.browse(cr, uid, ids[0]).order_id.price_type == 'tax_included':
555+ #
556+ # Tax included => Remove the taxes from the line amounts.
557+ #
558+ cur_facade=self.pool.get('res.currency')
559+ tax_facade = self.pool.get('account.tax')
560+ for line in self.browse(cr, uid, ids):
561+ for tax in tax_facade.compute_inv(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty):
562+ res[line.id] = res[line.id] - tax['amount']
563+ cur = line.order_id.pricelist_id.currency_id
564+ res[line.id] = cur_facade.round(cr, uid, cur, res[line.id])
565+ return res
566+
567+ def _amount_line_incl(self, cr, uid, ids, name, arg, context):
568+ """
569+ Calculate the subtotal for the line with taxes.
570+ """
571+ # Use the original method to calculate the amounts:
572+ res = super(purchase_order_line, self)._amount_line(cr, uid, ids, 'price_subtotal', arg, context)
573+ # Check if we *aren't* using 'tax_included' prices on the subtotal:
574+ if ids and self.browse(cr, uid, ids[0]).order_id.price_type != 'tax_included':
575+ #
576+ # Tax excluded on the subtotal => Add taxes here from the line amounts.
577+ #
578+ cur_facade=self.pool.get('res.currency')
579+ tax_facade = self.pool.get('account.tax')
580+ for line in self.browse(cr, uid, ids):
581+ for tax in tax_facade.compute(cr, uid, line.taxes_id, res[line.id]/line.product_qty, line.product_qty):
582+ res[line.id] = res[line.id] + tax['amount']
583+ cur = line.order_id.pricelist_id.currency_id
584+ res[line.id] = cur_facade.round(cr, uid, cur, res[line.id])
585+ return res
586+
587+
588 _columns = {
589- 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o tax'),
590- 'price_subtotal_incl': fields.function(_amount_line, method=True, string='Subtotal'),
591+ 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o tax', digits=(16, int(config['price_accuracy']))),
592+ 'price_subtotal_incl': fields.function(_amount_line_incl, method=True, string='Subtotal', digits=(16, int(config['price_accuracy']))),
593 }
594 purchase_order_line()
595-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
596+
597+class stock_picking(osv.osv):
598+ """
599+ Extends the stock pickings to manage the creation of invoices with
600+ tax included prices when the original order had tax included prices.
601+ """
602+ _inherit = 'stock.picking'
603+ _description = "Picking list"
604+
605+ def action_invoice_create(self, cr, uid, ids, journal_id=False,
606+ group=False, type='out_invoice', context=None):
607+ """
608+ Extend the invoice creation action to set the price type if needed.
609+ """
610+ #
611+ # Count how many pickings have tax included prices.
612+ #
613+ tax_included_count = 0
614+ lines_count = 0
615+ pickings = self.browse(cr, uid, ids, context=context)
616+ for picking in pickings:
617+ #
618+ # We must find the orders associated with this picking and check
619+ # if they have tax included prices.
620+ # As picking lines may come from different orders (even if it is
621+ # not the usual), we must check it line by line.
622+ #
623+ for move in picking.move_lines:
624+ if move.purchase_line_id and move.purchase_line_id.order_id:
625+ lines_count += 1
626+ if move.purchase_line_id.order_id.price_type == 'tax_included':
627+ tax_included_count += 1
628+
629+ if tax_included_count:
630+ if lines_count == tax_included_count:
631+ #
632+ # Every order has tax include prices, we must create the invoice
633+ # and (afterwards) set the price type and recalculate.
634+ #
635+ invoices_map = super(stock_picking, self).action_invoice_create(cr,
636+ uid, ids, journal_id=journal_id,
637+ group=group, type=type,
638+ context=context)
639+ invoice_ids = list(set(invoices_map.values()))
640+ self.pool.get('account.invoice').write(cr, uid, invoice_ids, { 'price_type': 'tax_included' })
641+ self.pool.get('account.invoice').button_compute(cr, uid, invoice_ids, {'type': 'in_invoice'}, set_total=True)
642+ else:
643+ # We have no current way of creating an invoice mixing
644+ # tax included and tax excluded prices, so we just fail:
645+ raise osv.except_osv(_('Error!'), _("You can't mix tax included and tax excluded purchases in one invoice!"))
646+ else:
647+ # All the invoices are 'tax excluded', that's the default value
648+ # so we just let the default method create the invoice.
649+ invoices_map = super(stock_picking, self).action_invoice_create(cr,
650+ uid, ids, journal_id=journal_id,
651+ group=group, type=type,
652+ context=context)
653+ return invoices_map
654+
655+stock_picking()
656
657
658=== modified file 'purchase_tax_include/purchase_tax_incl.xml'
659--- purchase_tax_include/purchase_tax_incl.xml 2008-09-12 22:59:35 +0000
660+++ purchase_tax_include/purchase_tax_incl.xml 2010-07-09 15:01:37 +0000
661@@ -1,31 +1,43 @@
662-<?xml version="1.0"?>
663+<?xml version="1.0" encoding="utf-8"?>
664 <openerp>
665-<data>
666-
667- <record model="ir.ui.view" id="account_tax_view_price">
668- <field name="name">purchase.order.exlcuded.view.form</field>
669- <field name="type">form</field>
670- <field name="model">purchase.order</field>
671- <field name="inherit_id" ref="purchase.purchase_order_form" />
672- <field name="arch" type="xml">
673- <field name="origin" position="after">
674- <field name="price_type"/>
675- </field>
676- </field>
677- </record>
678-
679- <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl">
680- <field name="name">purchase.order.line.tree</field>
681- <field name="type">tree</field>
682- <field name="model">purchase.order.line</field>
683- <field name="inherit_id" ref="purchase.purchase_order_line_tree" />
684- <field name="arch" type="xml">
685- <field name="price_subtotal" position="after">
686- <field name="price_subtotal_incl"/>
687- </field>
688- </field>
689- </record>
690-
691-</data>
692+ <data>
693+
694+ <record model="ir.ui.view" id="account_tax_view_price">
695+ <field name="name">purchase.order.form.add_price_type</field>
696+ <field name="type">form</field>
697+ <field name="model">purchase.order</field>
698+ <field name="inherit_id" ref="purchase.purchase_order_form" />
699+ <field name="arch" type="xml">
700+ <field name="shipped" position="after">
701+ <field name="price_type"/>
702+ </field>
703+ </field>
704+ </record>
705+
706+ <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl">
707+ <field name="name">purchase.order.line.tree.add_price_subtotal_incl</field>
708+ <field name="type">tree</field>
709+ <field name="model">purchase.order.line</field>
710+ <field name="inherit_id" ref="purchase.purchase_order_line_tree" />
711+ <field name="arch" type="xml">
712+ <field name="price_subtotal" position="after">
713+ <field name="price_subtotal_incl"/>
714+ </field>
715+ </field>
716+ </record>
717+
718+ <record model="ir.ui.view" id="account_tax_view_price_subtotal_incl">
719+ <field name="name">purchase.order.form.add_price_subtotal_incl_to_lines</field>
720+ <field name="type">form</field>
721+ <field name="model">purchase.order</field>
722+ <field name="inherit_id" ref="purchase.purchase_order_form" />
723+ <field name="arch" type="xml">
724+ <xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
725+ <field name="price_subtotal_incl"/>
726+ </xpath>
727+ </field>
728+ </record>
729+
730+ </data>
731 </openerp>
732