Add Tax rounding configuration
issue4106 review11401002
This commit is contained in:
1 parent
561151b719
commit
ffbc7a3432
8 files changed
+167
-21
No files matched your search
@@ -1,3 +1,5 @@
|
||||
* Add Tax rounding configuration
|
||||
|
||||
Version 3.2.0 - 2014-04-21
|
||||
* Bug fixes (see mercurial logs for details)
|
||||
* Use account of write-off journal as default
|
||||
|
||||
@@ -27,6 +27,8 @@ def register():
|
||||
Period,
|
||||
Move,
|
||||
Reconciliation,
|
||||
Configuration,
|
||||
ConfigurationTaxRounding,
|
||||
module='account_invoice', type_='model')
|
||||
Pool.register(
|
||||
PrintInvoice,
|
||||
|
||||
+54
-2
@@ -1,12 +1,64 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import fields
|
||||
from trytond.model import ModelSQL, ModelView, MatchMixin, fields
|
||||
from trytond.pyson import Eval
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['FiscalYear', 'Period', 'Move', 'Reconciliation']
|
||||
__all__ = ['Configuration', 'ConfigurationTaxRounding',
|
||||
'FiscalYear', 'Period', 'Move', 'Reconciliation']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
tax_roundings = [
|
||||
('document', 'Per Document'),
|
||||
('line', 'Per Line'),
|
||||
]
|
||||
|
||||
|
||||
class Configuration:
|
||||
__name__ = 'account.configuration'
|
||||
tax_rounding = fields.Function(fields.Selection(tax_roundings,
|
||||
'Tax Rounding'), 'on_change_with_tax_rounding')
|
||||
tax_roundings = fields.One2Many('account.configuration.tax_rounding',
|
||||
'configuration', 'Tax Roundings')
|
||||
|
||||
@fields.depends('tax_roundings')
|
||||
def on_change_with_tax_rounding(self, name=None, pattern=None):
|
||||
context = Transaction().context
|
||||
if pattern is None:
|
||||
pattern = {}
|
||||
pattern = pattern.copy()
|
||||
pattern['company'] = context.get('company')
|
||||
|
||||
for line in self.tax_roundings:
|
||||
if line.match(pattern):
|
||||
return line.method
|
||||
return 'document'
|
||||
|
||||
|
||||
class ConfigurationTaxRounding(ModelSQL, ModelView, MatchMixin):
|
||||
'Account Configuration Tax Rounding'
|
||||
__name__ = 'account.configuration.tax_rounding'
|
||||
configuration = fields.Many2One('account.configuration', 'Configuration',
|
||||
required=True, ondelete='CASCADE')
|
||||
sequence = fields.Integer('Sequence')
|
||||
company = fields.Many2One('company.company', 'Company')
|
||||
method = fields.Selection(tax_roundings, 'Method', required=True)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ConfigurationTaxRounding, cls).__setup__()
|
||||
cls._order.insert(0, ('sequence', 'ASC'))
|
||||
|
||||
@staticmethod
|
||||
def order_sequence(tables):
|
||||
table, _ = tables[None]
|
||||
return [table.sequence == None, table.sequence]
|
||||
|
||||
@staticmethod
|
||||
def default_method():
|
||||
return 'document'
|
||||
|
||||
|
||||
class FiscalYear:
|
||||
__name__ = 'account.fiscalyear'
|
||||
|
||||
+36
@@ -3,6 +3,42 @@
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="configuration_view_form">
|
||||
<field name="model">account.configuration</field>
|
||||
<field name="inherit" ref="account.configuration_view_form"/>
|
||||
<field name="name">configuration_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="configuration_tax_rounding_view_form">
|
||||
<field name="model">account.configuration.tax_rounding</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">configuration_tax_rounding_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="configuration_tax_rounding_view_list">
|
||||
<field name="model">account.configuration.tax_rounding</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">configuration_tax_rounding_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_configuration_tax_rounding">
|
||||
<field name="model"
|
||||
search="[('model', '=', 'account.configuration.tax_rounding')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access"
|
||||
id="access_configuration_tax_rounding_account_admin">
|
||||
<field name="model"
|
||||
search="[('model', '=', 'account.configuration.tax_rounding')]"/>
|
||||
<field name="group" ref="account.group_account_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="fiscalyear_view_form">
|
||||
<field name="model">account.fiscalyear</field>
|
||||
<field name="inherit" ref="account.fiscalyear_view_form"/>
|
||||
|
||||
+40
-19
@@ -436,6 +436,10 @@ class Invoice(Workflow, ModelSQL, ModelView):
|
||||
InvoiceTax = pool.get('account.invoice.tax')
|
||||
Account = pool.get('account.account')
|
||||
TaxCode = pool.get('account.tax.code')
|
||||
Configuration = pool.get('account.configuration')
|
||||
|
||||
config = Configuration(1)
|
||||
|
||||
res = {
|
||||
'untaxed_amount': Decimal('0.0'),
|
||||
'tax_amount': Decimal('0.0'),
|
||||
@@ -443,6 +447,13 @@ class Invoice(Workflow, ModelSQL, ModelView):
|
||||
'taxes': {},
|
||||
}
|
||||
computed_taxes = {}
|
||||
|
||||
def round_taxes():
|
||||
if self.currency:
|
||||
for value in computed_taxes.itervalues():
|
||||
for field in ('base', 'amount'):
|
||||
value[field] = self.currency.round(value[field])
|
||||
|
||||
if self.lines:
|
||||
context = self.get_tax_context()
|
||||
for line in self.lines:
|
||||
@@ -457,16 +468,16 @@ class Invoice(Workflow, ModelSQL, ModelView):
|
||||
for tax in taxes:
|
||||
key, val = self._compute_tax(tax,
|
||||
self.type or 'out_invoice')
|
||||
if not key in computed_taxes:
|
||||
if key not in computed_taxes:
|
||||
computed_taxes[key] = val
|
||||
else:
|
||||
computed_taxes[key]['base'] += val['base']
|
||||
computed_taxes[key]['amount'] += val['amount']
|
||||
if self.currency:
|
||||
for key in computed_taxes:
|
||||
for field in ('base', 'amount'):
|
||||
computed_taxes[key][field] = self.currency.round(
|
||||
computed_taxes[key][field])
|
||||
if config.tax_rounding == 'line':
|
||||
round_taxes()
|
||||
if config.tax_rounding == 'document':
|
||||
round_taxes()
|
||||
|
||||
tax_keys = []
|
||||
for tax in (self.taxes or []):
|
||||
if tax.manual:
|
||||
@@ -808,31 +819,41 @@ class Invoice(Workflow, ModelSQL, ModelView):
|
||||
return key, val
|
||||
|
||||
def _compute_taxes(self):
|
||||
Tax = Pool().get('account.tax')
|
||||
pool = Pool()
|
||||
Tax = pool.get('account.tax')
|
||||
Configuration = pool.get('account.configuration')
|
||||
|
||||
config = Configuration(1)
|
||||
|
||||
context = self.get_tax_context()
|
||||
|
||||
res = {}
|
||||
taxes = {}
|
||||
|
||||
def round_taxes():
|
||||
for value in taxes.itervalues():
|
||||
for field in ('base', 'amount'):
|
||||
value[field] = self.currency.round(value[field])
|
||||
|
||||
for line in self.lines:
|
||||
# Don't round on each line to handle rounding error
|
||||
if line.type != 'line':
|
||||
continue
|
||||
with Transaction().set_context(**context):
|
||||
taxes = Tax.compute(line.taxes, line.unit_price,
|
||||
tax_list = Tax.compute(line.taxes, line.unit_price,
|
||||
line.quantity,
|
||||
date=self.accounting_date or self.invoice_date)
|
||||
for tax in taxes:
|
||||
for tax in tax_list:
|
||||
key, val = self._compute_tax(tax, self.type)
|
||||
val['invoice'] = self.id
|
||||
if not key in res:
|
||||
res[key] = val
|
||||
if key not in taxes:
|
||||
taxes[key] = val
|
||||
else:
|
||||
res[key]['base'] += val['base']
|
||||
res[key]['amount'] += val['amount']
|
||||
for key in res:
|
||||
for field in ('base', 'amount'):
|
||||
res[key][field] = self.currency.round(res[key][field])
|
||||
return res
|
||||
taxes[key]['base'] += val['base']
|
||||
taxes[key]['amount'] += val['amount']
|
||||
if config.tax_rounding == 'line':
|
||||
round_taxes()
|
||||
if config.tax_rounding == 'document':
|
||||
round_taxes()
|
||||
return taxes
|
||||
|
||||
@classmethod
|
||||
def update_taxes(cls, invoices, exception=False):
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/field[@name='default_account_payable']" position="after">
|
||||
<group id="tax_roundings" col="2" colspan="4">
|
||||
<field name="tax_roundings" colspan="2"/>
|
||||
<label name="tax_rounding"/>
|
||||
<field name="tax_rounding"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<form string="Account Configuration Tax Rounding" cursor="company">
|
||||
<label name="configuration"/>
|
||||
<field name="configuration"/>
|
||||
<label name="sequence"/>
|
||||
<field name="sequence"/>
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="method"/>
|
||||
<field name="method"/>
|
||||
</form>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tree string="Account Configuration Tax Roundings" sequence="sequence">
|
||||
<field name="configuration"/>
|
||||
<field name="company"/>
|
||||
<field name="method" expand="1"/>
|
||||
</tree>
|
||||
Reference in new issue
Block a user