diff --git a/addons/account/account.py b/addons/account/account.py index caf1d68c45d..29acca9fc07 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -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 diff --git a/addons/account/company.py b/addons/account/company.py index 932f7750faa..433c03c8912 100644 --- a/addons/account/company.py +++ b/addons/account/company.py @@ -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. diff --git a/addons/account/company_view.xml b/addons/account/company_view.xml index b8c595f3ca0..6fb763f686f 100644 --- a/addons/account/company_view.xml +++ b/addons/account/company_view.xml @@ -24,6 +24,7 @@ + diff --git a/addons/account/res_config.py b/addons/account/res_config.py index 8ca35426427..7a1540e6e6b 100644 --- a/addons/account/res_config.py +++ b/addons/account/res_config.py @@ -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'): diff --git a/addons/account/res_config_view.xml b/addons/account/res_config_view.xml index d7eda0a2692..b19c81e9637 100644 --- a/addons/account/res_config_view.xml +++ b/addons/account/res_config_view.xml @@ -76,6 +76,7 @@ +