← Back to team overview

openerp-expert-accounting team mailing list archive

Re: vertical_comp patch

 

On 06/19/2012 11:24 PM, Ferdinand @ Camptocamp wrote:
Hello

I just tried the patch

some remarks

1) If SO or PO have
vertical_comp = True
then the generated invoice must have it too

2) I think the vertical_comp must have a general setting
* company
* tax  and/or
* partner

usually it will be sufficient to set this parameter at company level,
because all companies in in the "home" country will usually follow the
local rule vertical or horizontal

if nothing is found at partner we check tax and then company and use
this as default

obviously this parameter can also be set as default in SO/PO/INV


Hello Ferdinand, many thanks for feedback.
I'm replying to expert list only, because, as pointed by Fabrice, I'm not sure that bug is related to this issue.

I just updated the branch lp:~openerp-community/openobject-addons/fix-account-6-1-tax-computation-method <https://code.launchpad.net/%7Eopenerp-community/openobject-addons/fix-account-6-1-tax-computation-method> with the following changes:

 * Added 'vertical_comp' field to company
 * Added 'vertical_comp' field to partner
 * When user creates a new partner, his company's vertical_comp is
   applied to the partner
 * When changing partner on SO/PO/INV, the partner's vertical_comp is
   applied to the document

I did not add the vertical_comp field to taxes because the computation method can't differ according to lines (and their taxes), so it could lead to mixed states.

I'm attaching the new diff for 6.1 branch.

Regards


--
Lorenzo Battistini        lorenzo.battistini@xxxxxxxxxxx
Via Pasture Genovesi, 16 - 6949 - Comano  -  Switzerland
Agile Business Group sagl         http://www.agilebg.com

=== modified file 'account/__openerp__.py'
--- account/__openerp__.py	2012-05-08 09:56:32 +0000
+++ account/__openerp__.py	2012-06-20 06:45:47 +0000
@@ -133,6 +133,7 @@
         'project/analytic_account_demo.xml',
         'demo/account_minimal.xml',
         'demo/account_invoice_demo.xml',
+        'demo/account_tax.xml',
         #'account_unit_test.xml',
     ],
     'test': [
@@ -149,6 +150,7 @@
         'test/test_edi_invoice.yml',
         'test/account_report.yml',
         'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear
+        'test/tax_computation.yml',
     ],
     'installable': True,
     'auto_install': False,

=== modified file 'account/account.py'
--- account/account.py	2012-03-22 12:24:19 +0000
+++ account/account.py	2012-06-20 06:45:47 +0000
@@ -3,6 +3,8 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -1980,12 +1982,27 @@
         'company_id': _default_company,
     }
     _order = 'sequence'
+    
+    def _get_product_for_python_compute(self, cr, uid, tax, products):
+        if ('product' in tax.python_applicable or
+            'product' in tax.python_compute or
+            'product' in tax.python_compute_inv) and len(products) > 1:
+            raise osv.except_osv(_('Error'), _("Python computation for tax %s is configured for using 'product' variable, but the current invoice uses computation by column and the same tax covers several products") % tax.name)
+        elif ('product' in tax.python_applicable or
+            'product' in tax.python_compute or
+            'product' in tax.python_compute_inv) and len(products) == 1:
+            product = products[0]
+        else:
+            product = None
+        return product
 
     def _applicable(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None):
         res = []
         obj_partener_address = self.pool.get('res.partner.address')
         for tax in taxes:
             if tax.applicable_type=='code':
+                if isinstance(product, list):
+                    product = self._get_product_for_python_compute(cr, uid, tax, product)
                 localdict = {'price_unit':price_unit, 'address':obj_partener_address.browse(cr, uid, address_id), 'product':product, 'partner':partner}
                 exec tax.python_applicable in localdict
                 if localdict.get('result', False):
@@ -2027,6 +2044,8 @@
                # data['amount'] = quantity
             elif tax.type=='code':
                 address = address_id and obj_partener_address.browse(cr, uid, address_id) or None
+                if isinstance(product, list):
+                    product = self._get_product_for_python_compute(cr, uid, tax, product)
                 localdict = {'price_unit':cur_price_unit, 'address':address, 'product':product, 'partner':partner}
                 exec tax.python_compute in localdict
                 amount = localdict['result']
@@ -2151,6 +2170,8 @@
 
             elif tax.type=='code':
                 address = address_id and obj_partener_address.browse(cr, uid, address_id) or None
+                if isinstance(product, list):
+                    product = self._get_product_for_python_compute(cr, uid, tax, product)
                 localdict = {'price_unit':cur_price_unit, 'address':address, 'product':product, 'partner':partner}
                 exec tax.python_compute_inv in localdict
                 amount = localdict['result']

=== modified file 'account/account_invoice.py'
--- account/account_invoice.py	2012-03-29 15:43:31 +0000
+++ account/account_invoice.py	2012-06-20 06:45:47 +0000
@@ -3,6 +3,8 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -278,7 +280,8 @@
         'payment_ids': fields.function(_compute_lines, relation='account.move.line', type="many2many", string='Payments'),
         'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}),
         'user_id': fields.many2one('res.users', 'Salesman', readonly=True, states={'draft':[('readonly',False)]}),
-        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]})
+        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]}),
+        'vertical_comp' : fields.boolean('Tax Computation By Column'),
     }
     _defaults = {
         'type': _get_type,
@@ -404,6 +407,7 @@
         acc_id = False
         bank_id = False
         fiscal_position = False
+        vertical_comp = False
 
         opt = [('uid', str(uid))]
         if partner_id:
@@ -443,13 +447,15 @@
             partner_payment_term = p.property_payment_term and p.property_payment_term.id or False
             if p.bank_ids:
                 bank_id = p.bank_ids[0].id
+            vertical_comp = p.vertical_comp
 
         result = {'value': {
             'address_contact_id': contact_addr_id,
             'address_invoice_id': invoice_addr_id,
             'account_id': acc_id,
             'payment_term': partner_payment_term,
-            'fiscal_position': fiscal_position
+            'fiscal_position': fiscal_position,
+            'vertical_comp': vertical_comp,
             }
         }
 
@@ -1439,6 +1445,7 @@
                 continue
             res.append(mres)
             tax_code_found= False
+            # computation by column needed?
             for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id,
                     (line.price_unit * (1.0 - (line['discount'] or 0.0) / 100.0)),
                     line.quantity, inv.address_invoice_id.id, line.product_id,
@@ -1567,6 +1574,54 @@
         'base_amount': 0.0,
         'tax_amount': 0.0,
     }
+    
+    def build_grouped_lines(self, cr, uid, document_lines,
+        tax_field_name='invoice_line_tax_id', price_unit_field_name='price_unit', 
+        discount_field_name='discount', quantity_field_name='quantity', product_id_field_name='product_id', account_id_field_name='account_id'):
+        lines = []
+        lines_grouped_by_tax = {}
+        for line in document_lines:
+            key = tuple(tax.id for tax in line[tax_field_name])
+            if not lines_grouped_by_tax.get(key, False):
+                lines_grouped_by_tax[key] = []
+            lines_grouped_by_tax[key].append(line)
+        for key in lines_grouped_by_tax:
+            price_unit = 0.0
+            products = []
+            account_ids = []
+            for line in lines_grouped_by_tax[key]:
+                price_unit += (line[price_unit_field_name]* (1-(discount_field_name and line[discount_field_name] or 0.0)/100.0)) * line[quantity_field_name]
+                if product_id_field_name and line[product_id_field_name] not in products:
+                    products.append(line.product_id)
+                if account_id_field_name and line[account_id_field_name]['id'] not in account_ids:
+                    account_ids.append(line[account_id_field_name]['id'])
+            lines.append({
+                # using the first line, as being grouped by taxes, invoice_line_tax_id is always the same for every group
+                'taxes': lines_grouped_by_tax[key][0][tax_field_name],
+                'price_unit': price_unit,
+                'quantity': 1,
+                'products': products,
+                'account_ids': account_ids,
+                })
+        return lines
+    
+    def build_invoice_line_list(self, cr, uid, invoice_id, context=None):
+        lines = []
+        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
+        if inv.vertical_comp:
+            lines = self.build_grouped_lines(cr, uid, inv.invoice_line)
+        else:
+            for line in inv.invoice_line:
+                price_unit = (line.price_unit* (1-(line.discount or 0.0)/100.0))
+                lines.append({
+                    'taxes': line.invoice_line_tax_id,
+                    'price_unit': price_unit,
+                    'quantity': line.quantity,
+                    'products': line.product_id,
+                    'account_ids': [line.account_id.id],
+                    })
+        return lines
+    
     def compute(self, cr, uid, invoice_id, context=None):
         tax_grouped = {}
         tax_obj = self.pool.get('account.tax')
@@ -1574,9 +1629,9 @@
         inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
         cur = inv.currency_id
         company_currency = inv.company_id.currency_id.id
-
-        for line in inv.invoice_line:
-            for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id)['taxes']:
+        lines = self.build_invoice_line_list(cr, uid, invoice_id, context=None)
+        for line in lines:
+            for tax in tax_obj.compute_all(cr, uid, line['taxes'], line['price_unit'], line['quantity'], inv.address_invoice_id.id, line['products'], inv.partner_id)['taxes']:
                 tax['price_unit'] = cur_obj.round(cr, uid, cur, tax['price_unit'])
                 val={}
                 val['invoice_id'] = inv.id
@@ -1591,13 +1646,17 @@
                     val['tax_code_id'] = tax['tax_code_id']
                     val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
                     val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
-                    val['account_id'] = tax['account_collected_id'] or line.account_id.id
+                    if not tax['account_collected_id'] and len(line['account_ids']) > 1:
+                        raise osv.except_osv(_('Error'), _("The invoice %s is configured for using computation by column but tax %s does not have an 'account_collected_id' value and its lines cover several accounts") % (inv.name, tax['name']))
+                    val['account_id'] = tax['account_collected_id'] or line['account_ids'][0]
                 else:
                     val['base_code_id'] = tax['ref_base_code_id']
                     val['tax_code_id'] = tax['ref_tax_code_id']
                     val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
                     val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
-                    val['account_id'] = tax['account_paid_id'] or line.account_id.id
+                    if not tax['account_paid_id'] and len(line['account_ids']) > 1:
+                        raise osv.except_osv(_('Error'), _("The invoice %s is configured for using computation by column but tax %s does not have an 'account_paid_id' value and its lines cover several accounts") % (inv.name, tax['name']))
+                    val['account_id'] = tax['account_paid_id'] or line['account_ids'][0]
 
                 key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
                 if not key in tax_grouped:

=== modified file 'account/account_invoice_view.xml'
--- account/account_invoice_view.xml	2012-02-16 18:50:48 +0000
+++ account/account_invoice_view.xml	2012-06-20 06:45:47 +0000
@@ -226,6 +226,7 @@
                             <field domain="[('partner_id','=',partner_id)]" name="address_contact_id" groups="base.group_extended"/>
                             <field name="user_id"/>
                             <field name="move_id" groups="account.group_account_user"/>
+                            <field name="vertical_comp"/>
                             <separator colspan="4" string="Additional Information"/>
                             <field colspan="4" name="comment" nolabel="1"/>
                         </page>
@@ -324,6 +325,7 @@
                             <field colspan="4" domain="[('partner_id','=',partner_id)]" name="address_contact_id"
                                 groups="base.group_extended"/>
                             <field name="move_id" groups="account.group_account_user"/>
+                            <field name="vertical_comp"/>
                             <separator colspan="4" string="Additional Information"/>
                             <field colspan="4" name="comment" nolabel="1"/>
                         </page>

=== modified file 'account/company.py'
--- account/company.py	2011-11-16 13:43:36 +0000
+++ account/company.py	2012-06-20 06:45:47 +0000
@@ -34,6 +34,7 @@
             view_load=True,
             domain="[('type', '=', 'other')]",
             help="This account is used for transferring Profit/Loss (If It is Profit: Amount will be added, Loss : Amount will be deducted.), as calculated in Profit & Loss Report"),
+        'vertical_comp' : fields.boolean('Tax Computation By Column'),
     }
 
     _defaults = {

=== modified file 'account/company_view.xml'
--- account/company_view.xml	2011-09-29 11:08:56 +0000
+++ account/company_view.xml	2012-06-20 06:45:47 +0000
@@ -25,6 +25,7 @@
                 <field name="currency_id" position="after">
                       <field name="property_reserve_and_surplus_account" colspan="2"/>
                       <field name="paypal_account" />
+                      <field name="vertical_comp" />
                 </field>
             </field>
         </record>

=== added file 'account/demo/account_tax.xml'
--- account/demo/account_tax.xml	1970-01-01 00:00:00 +0000
+++ account/demo/account_tax.xml	2012-06-20 06:45:47 +0000
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+
+        <!-- Tax codes -->
+
+        <record id="account_tax_code_10" model="account.tax.code">
+            <field name="name">10 %</field>
+        </record>
+        <record id="account_tax_code_10_imp" model="account.tax.code">
+            <field name="name">10 % IMP</field>
+        </record>
+
+        <record id="account_tax_code_21" model="account.tax.code">
+            <field name="name">21 %</field>
+        </record>
+        <record id="account_tax_code_21_imp" model="account.tax.code">
+            <field name="name">21 % IMP</field>
+        </record>
+
+        <record id="account_tax_code_21_inc" model="account.tax.code">
+            <field name="name">21 % INC</field>
+        </record>
+        <record id="account_tax_code_21_inc_imp" model="account.tax.code">
+            <field name="name">21 % INC IMP</field>
+        </record>
+
+        <record id="account_tax_code_20_inc" model="account.tax.code">
+            <field name="name">20 % INC</field>
+        </record>
+        <record id="account_tax_code_20_inc_imp" model="account.tax.code">
+            <field name="name">20 % INC IMP</field>
+        </record>
+
+        <!-- taxes -->
+
+        <record id="account_tax_10" model="account.tax">
+            <field name="name">10 %</field>
+            <field name="amount">0.1</field>
+            <field name="tax_code_id" ref="account_tax_code_10"></field>
+            <field name="base_code_id" ref="account_tax_code_10_imp"></field>
+        </record>
+
+        <record id="account_tax_21" model="account.tax">
+            <field name="name">21 %</field>
+            <field name="amount">0.21</field>
+            <field name="tax_code_id" ref="account_tax_code_21"></field>
+            <field name="base_code_id" ref="account_tax_code_21_imp"></field>
+        </record>
+
+        <record id="account_tax_21_inc" model="account.tax">
+            <field name="name">21 % INC</field>
+            <field name="amount">0.21</field>
+            <field name="price_include">1</field>
+            <field name="tax_code_id" ref="account_tax_code_21_inc"></field>
+            <field name="base_code_id" ref="account_tax_code_21_inc_imp"></field>
+        </record>
+
+        <record id="account_tax_20_inc" model="account.tax">
+            <field name="name">20 % INC</field>
+            <field name="amount">0.2</field>
+            <field name="price_include">1</field>
+            <field name="tax_code_id" ref="account_tax_code_20_inc"></field>
+            <field name="base_code_id" ref="account_tax_code_20_inc_imp"></field>
+        </record>
+        
+    </data>
+</openerp>

=== modified file 'account/partner.py'
--- account/partner.py	2011-08-24 21:19:43 +0000
+++ account/partner.py	2012-06-20 06:45:47 +0000
@@ -185,7 +185,12 @@
             help="This payment term will be used instead of the default one for the current partner"),
         'ref_companies': fields.one2many('res.company', 'partner_id',
             'Companies that refers to partner'),
-        'last_reconciliation_date': fields.datetime('Latest Reconciliation Date', help='Date on which the partner accounting entries were reconciled last time')
+        'last_reconciliation_date': fields.datetime('Latest Reconciliation Date', help='Date on which the partner accounting entries were reconciled last time'),
+        'vertical_comp' : fields.boolean('Tax Computation By Column'),
+    }
+
+    _defaults = {
+        'vertical_comp': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.vertical_comp,
     }
 
 res_partner()

=== modified file 'account/partner_view.xml'
--- account/partner_view.xml	2011-09-21 07:13:12 +0000
+++ account/partner_view.xml	2012-06-20 06:45:47 +0000
@@ -86,6 +86,7 @@
                     <group col="2" colspan="2">
                         <separator string="Supplier Accounting Properties" colspan="2"/>
                         <field name="property_account_payable" groups="account.group_account_invoice"/>
+                        <field name="vertical_comp" />
                     </group>
                     <group col="2" colspan="2">
                         <separator string="Customer Credit" colspan="2"/>

=== added file 'account/test/tax_computation.yml'
--- account/test/tax_computation.yml	1970-01-01 00:00:00 +0000
+++ account/test/tax_computation.yml	2012-06-20 06:45:47 +0000
@@ -0,0 +1,491 @@
+#-
+  #First invoice. 2 lines
+    #price_unit = 23.83, tax = 0.21
+    #price_unit = 7.44, tax = 0.21
+#-
+-
+  Computation by line
+-
+
+  !record {model: account.invoice, id: invoice_1_computation_by_line}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 0
+    invoice_line:
+      - account_id: a_sale
+        name: '23.83'
+        price_unit: 23.83
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+      - account_id: a_sale
+        name: '7.44'
+        price_unit: 7.44
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_1_computation_by_line")])  
+-  
+    Then I verify the amount (computation by line).
+    23.83 × 0.21 = 5.0043 = 5
+    7.44 × 0.21 = 1.5624 = 1.56
+    5 + 1.56 = 6.56
+-  
+    !assert {model: account.invoice, id: invoice_1_computation_by_line}:
+        - amount_tax == 6.56
+
+-
+  Computation by column
+-
+  !record {model: account.invoice, id: invoice_1_computation_by_column}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: a_sale
+        name: '23.83'
+        price_unit: 23.83
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+      - account_id: a_sale
+        name: '7.44'
+        price_unit: 7.44
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_1_computation_by_column")])  
+-  
+    Then I verify the amount (computation by column).
+    23.83 + 7.44 = 31.27
+    31.27 × 0.21 = 6.5667 = 6.57
+-  
+    !assert {model: account.invoice, id: invoice_1_computation_by_column}:
+        - amount_tax == 6.57
+
+
+#-
+  #Second invoice. 2 lines
+    #price_unit = 24.92, tax = 0.21
+    #price_unit = 7.44, tax = 0.21
+#-
+-
+  Computation by line
+-
+  !record {model: account.invoice, id: invoice_2_computation_by_line}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 0
+    invoice_line:
+      - account_id: a_sale
+        name: '24.92'
+        price_unit: 24.92
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+      - account_id: a_sale
+        name: '7.44'
+        price_unit: 7.44
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_2_computation_by_line")])  
+-  
+    Then I verify the amount (computation by line).
+    24.92 × 0.21 = 5.2332 = 5.23
+    7.44 × 0.21 = 1.5624 = 1.56
+    5.23 + 1.56 = 6.79
+-  
+    !assert {model: account.invoice, id: invoice_2_computation_by_line}:
+        - amount_tax == 6.79
+-
+  Computation by column
+-
+  !record {model: account.invoice, id: invoice_2_computation_by_column}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: a_sale
+        name: '24.92'
+        price_unit: 24.92
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+      - account_id: a_sale
+        name: '7.44'
+        price_unit: 7.44
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_2_computation_by_column")])  
+-  
+    Then I verify the amount (computation by column).
+    24.92 + 7.44 = 32.36
+    32.36 × 0.21 = 6.7956 = 6.8
+-  
+    !assert {model: account.invoice, id: invoice_2_computation_by_column}:
+        - amount_tax == 6.8
+
+
+#-
+  #Third invoice. 6 lines
+    #price_unit = 1.99, tax = 0.1
+    #price_unit = 0.38, tax = 0.1
+    #price_unit = 5.68, tax = 0.1
+    #price_unit = 0.45, tax = 0.1
+    #price_unit = 1.05, tax = 0.1
+    #price_unit = 2.87, tax = 0.1
+#-
+-
+  Computation by line
+-
+  !record {model: account.invoice, id: invoice_3_computation_by_line}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 0
+    invoice_line:
+      - account_id: a_sale
+        name: '1.99'
+        price_unit: 1.99
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '0.38'
+        price_unit: 0.38
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '5.68'
+        price_unit: 5.68
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '0.45'
+        price_unit: 0.45
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '1.05'
+        price_unit: 1.05
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '2.87'
+        price_unit: 2.87
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_3_computation_by_line")])  
+-  
+    Then I verify the amount (computation by line).
+    1.99 × 0.1 = 0.199 = 0.2
+    0.38 × 0.1 = 0.038 = 0.04
+    5.68 × 0.1 = 0.568 = 0.57
+    0.45 × 0.1 = 0.045 = 0.05
+    1.05 × 0.1 = 0.105 = 0.11
+    2.87 × 0.1 = 0.287 = 0.29
+    0.2 + 0.04 + 0.57 + 0.05 + 0.11 + 0.29 = 1.26
+-  
+    !assert {model: account.invoice, id: invoice_3_computation_by_line}:
+        - amount_tax == 1.26
+-
+  Computation by column
+-
+  !record {model: account.invoice, id: invoice_3_computation_by_column}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: a_sale
+        name: '1.99'
+        price_unit: 1.99
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '0.38'
+        price_unit: 0.38
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '5.68'
+        price_unit: 5.68
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '0.45'
+        price_unit: 0.45
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '1.05'
+        price_unit: 1.05
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+      - account_id: a_sale
+        name: '2.87'
+        price_unit: 2.87
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_10
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_3_computation_by_column")])  
+-  
+    Then I verify the amount (computation by column).
+    1.99 + 0.38 + 5.68 + 0.45 + 1.05 + 2.87 = 12.42
+    12.42 * 0.1 = 1.242 = 1.24
+-  
+    !assert {model: account.invoice, id: invoice_3_computation_by_column}:
+        - amount_tax == 1.24
+
+
+#-
+  #Fourth invoice. 2 lines
+    #price_unit = 465, tax = 0.21 included in price
+    #price_unit = 9, tax = 0.21 included in price
+#-
+-
+  Computation by line
+-
+  !record {model: account.invoice, id: invoice_4_computation_by_line}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 0
+    invoice_line:
+      - account_id: a_sale
+        name: '465'
+        price_unit: 465
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21_inc
+      - account_id: a_sale
+        name: '9'
+        price_unit: 9
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21_inc
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_4_computation_by_line")])  
+-  
+    Then I verify the amount (computation by line).
+    465 ÷ 1.21 = 384.297520661 = 384.3
+    9 ÷ 1.21 = 7.438016529 = 7.44
+    465 + 9 = 474
+    384.3 + 7.44 = 391.74
+    474 − 391.74 = 82.26
+-  
+    !assert {model: account.invoice, id: invoice_4_computation_by_line}:
+        - amount_tax == 82.26
+-
+  Computation by column
+-
+  !record {model: account.invoice, id: invoice_4_computation_by_column}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: a_sale
+        name: '465'
+        price_unit: 465
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21_inc
+      - account_id: a_sale
+        name: '9'
+        price_unit: 9
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_21_inc
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_4_computation_by_column")])  
+-  
+    Then I verify the amount (computation by column).
+    465 + 9 = 474
+    474 ÷ 1.21 = 391.73553719 = 391.74
+    474 − 391.74 = 82.26
+-  
+    !assert {model: account.invoice, id: invoice_4_computation_by_column}:
+        - amount_tax == 82.26
+
+
+#-
+  #Fifth invoice. 2 lines
+    #price_unit = 148.28, tax = 0.2 included in price
+    #price_unit = 148.28, tax = 0.2 included in price
+#-
+-
+  Computation by line
+-
+  !record {model: account.invoice, id: invoice_5_computation_by_line}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 0
+    invoice_line:
+      - account_id: a_sale
+        name: '148.28'
+        price_unit: 148.28
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_20_inc
+      - account_id: a_sale
+        name: '148.28'
+        price_unit: 148.28
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_20_inc
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_5_computation_by_line")])  
+-  
+    Then I verify the amount (computation by line).
+    148.28 + 148.28 = 296.56
+    148.28 ÷ 1.2 = 123.566666667 = 123.57
+    123.57 × 2 = 247.14
+    296.56 - 247.14 = 49.42
+-  
+    !assert {model: account.invoice, id: invoice_5_computation_by_line}:
+        - amount_tax == 49.42
+-
+  Computation by column
+-
+  !record {model: account.invoice, id: invoice_5_computation_by_column}:
+    account_id: a_recv
+    address_contact_id: base.res_partner_address_zen
+    address_invoice_id: base.res_partner_address_zen
+    company_id: base.main_company
+    currency_id: base.EUR
+    date_invoice: !eval time.strftime('%Y-%m-%d')
+    vertical_comp: 1
+    invoice_line:
+      - account_id: a_sale
+        name: '148.28'
+        price_unit: 148.28
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_20_inc
+      - account_id: a_sale
+        name: '148.28'
+        price_unit: 148.28
+        quantity: 1.0
+        invoice_line_tax_id:
+            - account_tax_20_inc
+    journal_id: sales_journal
+    partner_id: base.res_partner_3
+    
+-  
+    Compute the total tax.
+-  
+    !python {model: account.invoice}: |
+        self.button_compute(cr, uid, [ref("invoice_5_computation_by_column")])  
+-  
+    Then I verify the amount (computation by column).
+    148.28 + 148.28 = 296.56
+    296.56 ÷ 1.2 = 247.133333333 = 247.13
+    296.56 - 247.13 = 49.43
+-  
+    !assert {model: account.invoice, id: invoice_5_computation_by_column}:
+        - amount_tax == 49.43

=== modified file 'purchase/__openerp__.py'
--- purchase/__openerp__.py	2012-01-31 13:36:57 +0000
+++ purchase/__openerp__.py	2012-06-20 06:45:47 +0000
@@ -72,6 +72,7 @@
         'test/ui/print_report.yml',
         'test/ui/duplicate_order.yml',
         'test/ui/delete_order.yml',
+        'test/tax_computation.yml',
     ],
     'demo': [
         'purchase_order_demo.yml',

=== modified file 'purchase/purchase.py'
--- purchase/purchase.py	2012-02-16 12:34:08 +0000
+++ purchase/purchase.py	2012-06-20 06:45:47 +0000
@@ -3,6 +3,8 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -39,6 +41,8 @@
     def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
         res = {}
         cur_obj=self.pool.get('res.currency')
+        ait_pool = self.pool.get('account.invoice.tax')
+        tax_pool = self.pool.get('account.tax')
         for order in self.browse(cr, uid, ids, context=context):
             res[order.id] = {
                 'amount_untaxed': 0.0,
@@ -48,11 +52,20 @@
             val = val1 = 0.0
             cur = order.pricelist_id.currency_id
             for line in order.order_line:
-               val1 += line.price_subtotal
-               for c in self.pool.get('account.tax').compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id.id, order.partner_id)['taxes']:
-                    val += c.get('amount', 0.0)
+                val1 += line.price_subtotal
+            res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
+            if order.vertical_comp:
+                lines = ait_pool.build_grouped_lines(cr, uid, order.order_line,
+                    tax_field_name='taxes_id', quantity_field_name='product_qty',  account_id_field_name=None, discount_field_name=None)
+                for line in lines:
+                    for c in tax_pool.compute_all(cr, uid, line['taxes'], line['price_unit'], line['quantity'], order.partner_address_id.id, line['products'], order.partner_id)['taxes']:
+                        val += c.get('amount', 0.0)
+                res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
+            else:
+                for line in order.order_line:
+                   for c in self.pool.get('account.tax').compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty, order.partner_address_id.id, line.product_id.id, order.partner_id)['taxes']:
+                        val += c.get('amount', 0.0)
             res[order.id]['amount_tax']=cur_obj.round(cr, uid, cur, val)
-            res[order.id]['amount_untaxed']=cur_obj.round(cr, uid, cur, val1)
             res[order.id]['amount_total']=res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
         return res
 
@@ -193,20 +206,24 @@
         ),
         'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Purchase Price'), string='Untaxed Amount',
             store={
+                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['vertical_comp'], 10),
                 'purchase.order.line': (_get_order, None, 10),
             }, multi="sums", help="The amount without tax"),
         'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Purchase Price'), string='Taxes',
             store={
+                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['vertical_comp'], 10),
                 'purchase.order.line': (_get_order, None, 10),
             }, multi="sums", help="The tax amount"),
         'amount_total': fields.function(_amount_all, digits_compute= dp.get_precision('Purchase Price'), string='Total',
             store={
+                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['vertical_comp'], 10),
                 'purchase.order.line': (_get_order, None, 10),
             }, multi="sums",help="The total amount"),
         'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position'),
         'product_id': fields.related('order_line','product_id', type='many2one', relation='product.product', string='Product'),
         'create_uid':  fields.many2one('res.users', 'Responsible'),
         'company_id': fields.many2one('res.company','Company',required=True,select=1),
+        'vertical_comp' : fields.boolean('Tax Computation By Column'),
     }
     _defaults = {
         'date_order': fields.date.context_today,
@@ -271,7 +288,7 @@
         supplier = partner.browse(cr, uid, partner_id)
         pricelist = supplier.property_product_pricelist_purchase.id
         fiscal_position = supplier.property_account_position and supplier.property_account_position.id or False
-        return {'value':{'partner_address_id': supplier_address['default'], 'pricelist_id': pricelist, 'fiscal_position': fiscal_position}}
+        return {'value':{'partner_address_id': supplier_address['default'], 'pricelist_id': pricelist, 'fiscal_position': fiscal_position, 'vertical_comp': supplier.vertical_comp}}
 
     def wkf_approve_order(self, cr, uid, ids, context=None):
         self.write(cr, uid, ids, {'state': 'approved', 'date_approve': fields.date.context_today(self,cr,uid,context=context)})

=== modified file 'purchase/purchase_view.xml'
--- purchase/purchase_view.xml	2012-02-07 13:17:19 +0000
+++ purchase/purchase_view.xml	2012-06-20 06:45:47 +0000
@@ -169,6 +169,7 @@
                         <field name="partner_ref"/>
                         <field name="shipped"/>
                         <field name="company_id" groups="base.group_multi_company" widget="selection"/>
+                        <field name="vertical_comp"/>
                     </group>
                     <notebook colspan="4">
                         <page string="Purchase Order">

=== added file 'purchase/test/tax_computation.yml'
--- purchase/test/tax_computation.yml	1970-01-01 00:00:00 +0000
+++ purchase/test/tax_computation.yml	2012-06-20 06:45:47 +0000
@@ -0,0 +1,69 @@
+#-
+  #First order. 2 lines
+    #price_unit = 23.83, tax = 0.21
+    #price_unit = 7.44, tax = 0.21
+#-
+-
+  Computation by line
+-
+  !record {model: purchase.order, id: order_1_computation_by_line}:
+    partner_id: base.res_partner_agrolait
+    partner_address_id: base.res_partner_address_8invoice
+    location_id: stock.stock_location_3
+    pricelist_id: 1
+    vertical_comp: 0
+    order_line:
+      - product_qty: 1.0
+        product_uom: 1
+        price_unit: 23.83
+        name: '23.83'
+        taxes_id:
+            - account.account_tax_21
+        date_planned: '2012-05-06'
+      - product_qty: 1.0
+        product_uom: 1
+        price_unit: 7.44
+        name: '7.44'
+        taxes_id:
+            - account.account_tax_21
+        date_planned: '2012-05-06'
+-  
+    Then I verify the amount (computation by line).
+    23.83 × 0.21 = 5.0043 = 5
+    7.44 × 0.21 = 1.5624 = 1.56
+    5 + 1.56 = 6.56
+-  
+    !assert {model: purchase.order, id: order_1_computation_by_line}:
+        - amount_tax == 6.56
+
+-
+  Computation by column
+-
+  !record {model: purchase.order, id: order_1_computation_by_column}:
+    partner_id: base.res_partner_agrolait
+    partner_address_id: base.res_partner_address_8invoice
+    location_id: stock.stock_location_3
+    pricelist_id: 1
+    vertical_comp: 1
+    order_line:
+      - product_qty: 1.0
+        product_uom: 1
+        price_unit: 23.83
+        name: '23.83'
+        taxes_id:
+            - account.account_tax_21
+        date_planned: '2012-05-06'
+      - product_qty: 1.0
+        product_uom: 1
+        price_unit: 7.44
+        name: '7.44'
+        taxes_id:
+            - account.account_tax_21
+        date_planned: '2012-05-06'
+-  
+    Then I verify the amount (computation by column).
+    23.83 + 7.44 = 31.27
+    31.27 × 0.21 = 6.5667 = 6.57
+-  
+    !assert {model: purchase.order, id: order_1_computation_by_column}:
+        - amount_tax == 6.57

=== modified file 'sale/__openerp__.py'
--- sale/__openerp__.py	2012-01-31 13:36:57 +0000
+++ sale/__openerp__.py	2012-06-20 06:45:47 +0000
@@ -96,6 +96,7 @@
         'test/cancel_order.yml',
         'test/delete_order.yml',
         'test/edi_sale_order.yml',
+        'test/tax_computation.yml',
     ],
     'installable': True,
     'auto_install': False,

=== modified file 'sale/sale.py'
--- sale/sale.py	2012-02-16 16:52:53 +0000
+++ sale/sale.py	2012-06-20 06:45:47 +0000
@@ -3,6 +3,8 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#    Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -71,6 +73,8 @@
 
     def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
         cur_obj = self.pool.get('res.currency')
+        ait_pool = self.pool.get('account.invoice.tax')
+        tax_pool = self.pool.get('account.tax')
         res = {}
         for order in self.browse(cr, uid, ids, context=context):
             res[order.id] = {
@@ -82,9 +86,18 @@
             cur = order.pricelist_id.currency_id
             for line in order.order_line:
                 val1 += line.price_subtotal
-                val += self._amount_line_tax(cr, uid, line, context=context)
-            res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
             res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
+            if order.vertical_comp:
+                lines = ait_pool.build_grouped_lines(cr, uid, order.order_line,
+                    tax_field_name='tax_id', quantity_field_name='product_uom_qty',  account_id_field_name=None)
+                for line in lines:
+                    for c in tax_pool.compute_all(cr, uid, line['taxes'], line['price_unit'], line['quantity'], order.partner_invoice_id.id, line['products'], order.partner_id)['taxes']:
+                        val += c.get('amount', 0.0)
+                res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
+            else:
+                for line in order.order_line:
+                    val += self._amount_line_tax(cr, uid, line, context=context)
+                res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
             res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
         return res
 
@@ -248,19 +261,19 @@
 
         'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Untaxed Amount',
             store = {
-                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
+                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'vertical_comp'], 10),
                 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
             },
             multi='sums', help="The amount without tax."),
         'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Taxes',
             store = {
-                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
+                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'vertical_comp'], 10),
                 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
             },
             multi='sums', help="The tax amount."),
         'amount_total': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Total',
             store = {
-                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
+                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'vertical_comp'], 10),
                 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
             },
             multi='sums', help="The total amount."),
@@ -268,7 +281,8 @@
         'invoice_quantity': fields.selection([('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you want your invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.", required=True, readonly=True, states={'draft': [('readonly', False)]}),
         'payment_term': fields.many2one('account.payment.term', 'Payment Term'),
         'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position'),
-        'company_id': fields.related('shop_id','company_id',type='many2one',relation='res.company',string='Company',store=True,readonly=True)
+        'company_id': fields.related('shop_id','company_id',type='many2one',relation='res.company',string='Company',store=True,readonly=True),
+        'vertical_comp' : fields.boolean('Tax Computation By Column'),
     }
     _defaults = {
         'picking_policy': 'direct',
@@ -362,6 +376,7 @@
             'payment_term': payment_term,
             'fiscal_position': fiscal_position,
             'user_id': dedicated_salesman,
+            'vertical_comp': part.vertical_comp,
         }
         if pricelist:
             val['pricelist_id'] = pricelist

=== modified file 'sale/sale_view.xml'
--- sale/sale_view.xml	2012-01-31 13:36:57 +0000
+++ sale/sale_view.xml	2012-06-20 06:45:47 +0000
@@ -234,6 +234,7 @@
                                 <field name="payment_term" widget="selection"/>
                                 <field name="fiscal_position" widget="selection"/>
                                 <field name="company_id" widget="selection" groups="base.group_multi_company"/>
+                                <field name="vertical_comp"/>
                             </group>
                             <group colspan="2" col="2" groups="base.group_extended">
                                 <separator string="Dates" colspan="2"/>

=== added file 'sale/test/tax_computation.yml'
--- sale/test/tax_computation.yml	1970-01-01 00:00:00 +0000
+++ sale/test/tax_computation.yml	2012-06-20 06:45:47 +0000
@@ -0,0 +1,67 @@
+#-
+  #First order. 2 lines
+    #price_unit = 23.83, tax = 0.21
+    #price_unit = 7.44, tax = 0.21
+#-
+-
+  Computation by line
+-
+  !record {model: sale.order, id: order_1_computation_by_line}:
+    partner_id: base.res_partner_agrolait
+    partner_invoice_id: base.res_partner_address_8invoice
+    partner_order_id: base.res_partner_address_8invoice
+    partner_shipping_id: base.res_partner_address_8invoice
+    pricelist_id: 1
+    vertical_comp: 0
+    order_line:
+      - product_uom_qty: 1.0
+        product_uom: 1
+        price_unit: 23.83
+        name: '23.83'
+        tax_id:
+            - account.account_tax_21
+      - product_uom_qty: 1.0
+        product_uom: 1
+        price_unit: 7.44
+        name: '7.44'
+        tax_id:
+            - account.account_tax_21
+-  
+    Then I verify the amount (computation by line).
+    23.83 × 0.21 = 5.0043 = 5
+    7.44 × 0.21 = 1.5624 = 1.56
+    5 + 1.56 = 6.56
+-  
+    !assert {model: sale.order, id: order_1_computation_by_line}:
+        - amount_tax == 6.56
+
+-
+  Computation by column
+-
+  !record {model: sale.order, id: order_1_computation_by_column}:
+    partner_id: base.res_partner_agrolait
+    partner_invoice_id: base.res_partner_address_8invoice
+    partner_order_id: base.res_partner_address_8invoice
+    partner_shipping_id: base.res_partner_address_8invoice
+    pricelist_id: 1
+    vertical_comp: 1
+    order_line:
+      - product_uom_qty: 1.0
+        product_uom: 1
+        price_unit: 23.83
+        name: '23.83'
+        tax_id:
+            - account.account_tax_21
+      - product_uom_qty: 1.0
+        product_uom: 1
+        price_unit: 7.44
+        name: '7.44'
+        tax_id:
+            - account.account_tax_21
+-  
+    Then I verify the amount (computation by column).
+    23.83 + 7.44 = 31.27
+    31.27 × 0.21 = 6.5667 = 6.57
+-  
+    !assert {model: sale.order, id: order_1_computation_by_column}:
+        - amount_tax == 6.57


References