Add an option "Tax calculation rounding method" that can be set to "Round per line...
authorAlexis de Lattre <alexis@via.ecp.fr>
Sat, 7 Jul 2012 16:36:05 +0000 (18:36 +0200)
committerAlexis de Lattre <alexis@via.ecp.fr>
Sat, 7 Jul 2012 16:36:05 +0000 (18:36 +0200)
bzr revid: alexis@via.ecp.fr-20120707163605-byo0o11f2q9dsczl

addons/account/account.py
addons/account/company.py
addons/account/company_view.xml
addons/account/res_config.py
addons/account/res_config_view.xml

index caf1d68..29acca9 100644 (file)
@@ -2066,7 +2066,20 @@ class account_tax(osv.osv):
                 'taxes': []                  # List of taxes, see compute for the format
             }
         """
+
+        # By default, for each tax, tax amount will first be computed
+        # and rounded at the 'Account' decimal precision for each
+        # PO/SO/invoice line and then these rounded amounts will be
+        # summed, leading to the total amount for that tax. But, if the
+        # company has tax_calculation_rounding_method = round_globally,
+        # we still follow the same method, but we use a much larger
+        # precision when we round the tax amount for each line (we use
+        # the 'Account' decimal precision + 5), and that way it's like
+        # rounding after the sum of the tax amounts of each line
         precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
+        tax_compute_precision = precision
+        if taxes and taxes[0].company_id.tax_calculation_rounding_method == 'round_globally':
+            tax_compute_precision += 5
         totalin = totalex = round(price_unit * quantity, precision)
         tin = []
         tex = []
@@ -2075,7 +2088,7 @@ class account_tax(osv.osv):
                 tex.append(tax)
             else:
                 tin.append(tax)
-        tin = self.compute_inv(cr, uid, tin, price_unit, quantity, product=product, partner=partner)
+        tin = self.compute_inv(cr, uid, tin, price_unit, quantity, product=product, partner=partner, precision=tax_compute_precision)
         for r in tin:
             totalex -= r.get('amount', 0.0)
         totlex_qty = 0.0
@@ -2083,7 +2096,7 @@ class account_tax(osv.osv):
             totlex_qty = totalex/quantity
         except:
             pass
-        tex = self._compute(cr, uid, tex, totlex_qty, quantity,product=product, partner=partner)
+        tex = self._compute(cr, uid, tex, totlex_qty, quantity, product=product, partner=partner, precision=tax_compute_precision)
         for r in tex:
             totalin += r.get('amount', 0.0)
         return {
@@ -2096,7 +2109,7 @@ class account_tax(osv.osv):
         _logger.warning("Deprecated, use compute_all(...)['taxes'] instead of compute(...) to manage prices with tax included")
         return self._compute(cr, uid, taxes, price_unit, quantity, product, partner)
 
-    def _compute(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None):
+    def _compute(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, precision=None):
         """
         Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
 
@@ -2105,14 +2118,15 @@ class account_tax(osv.osv):
             tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
             one tax for each tax id in IDS and their children
         """
+        if not precision:
+            precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
         res = self._unit_compute(cr, uid, taxes, price_unit, product, partner, quantity)
         total = 0.0
-        precision_pool = self.pool.get('decimal.precision')
         for r in res:
             if r.get('balance',False):
-                r['amount'] = round(r.get('balance', 0.0) * quantity, precision_pool.precision_get(cr, uid, 'Account')) - total
+                r['amount'] = round(r.get('balance', 0.0) * quantity, precision) - total
             else:
-                r['amount'] = round(r.get('amount', 0.0) * quantity, precision_pool.precision_get(cr, uid, 'Account'))
+                r['amount'] = round(r.get('amount', 0.0) * quantity, precision)
                 total += r['amount']
         return res
 
@@ -2188,7 +2202,7 @@ class account_tax(osv.osv):
             r['todo'] = 0
         return res
 
-    def compute_inv(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None):
+    def compute_inv(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, precision=None):
         """
         Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
         Price Unit is a VAT included price
@@ -2198,15 +2212,15 @@ class account_tax(osv.osv):
             tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
             one tax for each tax id in IDS and their children
         """
+        if not precision:
+            precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
         res = self._unit_compute_inv(cr, uid, taxes, price_unit, product, partner=None)
         total = 0.0
-        obj_precision = self.pool.get('decimal.precision')
         for r in res:
-            prec = obj_precision.precision_get(cr, uid, 'Account')
             if r.get('balance',False):
-                r['amount'] = round(r['balance'] * quantity, prec) - total
+                r['amount'] = round(r['balance'] * quantity, precision) - total
             else:
-                r['amount'] = round(r['amount'] * quantity, prec)
+                r['amount'] = round(r['amount'] * quantity, precision)
                 total += r['amount']
         return res
 
index 932f775..433c03c 100644 (file)
@@ -25,6 +25,11 @@ class res_company(osv.osv):
     _inherit = "res.company"
     _columns = {
         'expects_chart_of_accounts': fields.boolean('Expects a Chart of Accounts'),
+        'tax_calculation_rounding_method': fields.selection([
+            ('round_per_line', 'Round per line'),
+            ('round_globally', 'Round globally'),
+            ], 'Tax calculation rounding method',
+            help="If you select 'Round per line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
         'paypal_account': fields.char("Paypal Account", size=128, help="Paypal username (usually email) for receiving online payments."),
         'overdue_msg': fields.text('Overdue Payments Message', translate=True),
         'property_reserve_and_surplus_account': fields.property(
@@ -39,6 +44,7 @@ class res_company(osv.osv):
 
     _defaults = {
         'expects_chart_of_accounts': True,
+        'tax_calculation_rounding_method': 'round_per_line',
         'overdue_msg': '''Dear Sir, dear Madam,
 
 Our records indicate that some payments on your account are still due. Please find details below.
index b8c595f..6fb763f 100644 (file)
@@ -24,6 +24,7 @@
             <field name="arch" type="xml">
                 <field name="currency_id" position="after">
                       <field name="property_reserve_and_surplus_account" colspan="2"/>
+                      <field name="tax_calculation_rounding_method" />
                       <field name="paypal_account"  placeholder="sales@openerp.com"/>
                 </field>
             </field>
index 8ca3542..7a1540e 100644 (file)
@@ -49,6 +49,12 @@ class account_config_settings(osv.osv_memory):
         'has_chart_of_accounts': fields.boolean('Company has a chart of accounts'),
         'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', domain="[('visible','=', True)]"),
         'code_digits': fields.integer('# of Digits', help="No. of Digits to use for account code"),
+        'tax_calculation_rounding_method': fields.related('company_id',
+            'tax_calculation_rounding_method', type='selection', selection=[
+            ('round_per_line', 'Round per line'),
+            ('round_globally', 'Round globally'),
+            ], string='Tax calculation rounding method',
+            help="If you select 'Round per line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
         'sale_tax': fields.many2one("account.tax.template", "Default Sale Tax"),
         'purchase_tax': fields.many2one("account.tax.template", "Default Purchase Tax"),
         'sale_tax_rate': fields.float('Sales Tax (%)'),
@@ -152,6 +158,7 @@ class account_config_settings(osv.osv_memory):
             'has_chart_of_accounts': has_chart_of_accounts,
             'has_fiscal_year': bool(fiscalyear_count),
             'chart_template_id': False,
+            'tax_calculation_rounding_method': company.tax_calculation_rounding_method,
         }
         # update journals and sequences
         for journal_type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'):
index d7eda0a..b19c81e 100644 (file)
@@ -76,6 +76,7 @@
                         <group>
                             <field name="default_purchase_tax" domain="[('type_tax_use','=','purchase'), ('company_id','=',company_id)]"
                                 attrs="{'invisible': [('has_chart_of_accounts','=',False)]}"/>
+                            <field name="tax_calculation_rounding_method" />
                             <field name="module_account_asset"/>
                             <field name="module_account_budget"/>
                         </group>