Merge lp:~akretion-team/openobject-addons/trunk-addons-analytic-on-tax into lp:openobject-addons

Proposed by Alexis de Lattre
Status: Superseded
Proposed branch: lp:~akretion-team/openobject-addons/trunk-addons-analytic-on-tax
Merge into: lp:openobject-addons
Diff against target: 173 lines (+58/-8)
4 files modified
account/account.py (+8/-2)
account/account_invoice.py (+46/-4)
account/account_invoice_view.xml (+2/-0)
account/account_view.xml (+2/-2)
To merge this branch: bzr merge lp:~akretion-team/openobject-addons/trunk-addons-analytic-on-tax
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+114182@code.launchpad.net

This proposal supersedes a proposal from 2011-12-11.

This proposal has been superseded by a proposal from 2012-07-10.

Description of the change

Here is the real-life scenario which motivate this merge proposal :
In some companies, all expenses must have an analytic account.
When you purchase some equipments, you sometimes have to pay an eco-tax. For the company who is the end-used of the equipment, this eco-tax is considered as an expense. So we need to be able to define an analytic account on invoice tax lines.

More info about the history of this topic : https://lists.launchpad.net/openerp-expert-accounting/msg01257.html

This merge proposal :
- adds a field 'account_analytic_id' on the object account_invoice_tax.
- adds 2 fields 'account_analytic_collected_id' and 'account_analytic_paid_id' on the object account_tax so as to be able to define default analytic accounts for invoices and refunds (similar behavior as for general accounts on taxes).
- adds these 3 fields in the appropriate views
- adds the necessary code in account.py and account_invoice.py
- moves the help message "Keep empty to use the income account" from a label on the form view of account_tax to the help pop-up of the corresponding field (I made this change in order to get some room for the fields 'account_analytic_collected_id' and 'account_analytic_paid_id' next to their general accounting conterparts on the form view).

To post a comment you must log in.
Revision history for this message
Cristian Salamea (ovnicraft) wrote : Posted in a previous version of this proposal

Hello looks good but
+ 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),

is already necessary ?

Account invoice line gets by default this field.

Regards,

Revision history for this message
Alexis de Lattre (alexis-via) wrote : Posted in a previous version of this proposal

@Cristian
My merge proposal precisely consist in adding the analytic account on "invoice _tax_ lines". I know that this field in already present on "invoice lines".

Revision history for this message
Francois Degrave (fde-be) wrote : Posted in a previous version of this proposal

That is exactly what I planned to do. Too bad OpenERP has usually no interest in most external developer proposals :-(

Revision history for this message
Alexis de Lattre (alexis-via) wrote : Posted in a previous version of this proposal

@Francois Degrave
I'm very surprised to see an OpenERP S.A. employee saying this. I hope that OpenERP S.A. still has interest in proposals from external developers !! Otherwise, external contributors like me should move on to other free-software ERP projects :-(

Maybe you could help me "from the inside" to have this merge proposal reviewed, and I hope accepted. I am ready to answer all questions about it and make some changes if necessary. This merge proposal is motivated by real-life enterprise needs (Anevia in the present case).

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

I have resumbmitted an new branch that is up-to-date with current addons-trunk. I have tested this new branch and it works well with trunk. The code itself has not been changed.

Unmerged revisions

7010. By Alexis de Lattre

Add analytic account on taxes and invoice tax lines.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account/account.py'
--- account/account.py 2012-06-26 20:09:09 +0000
+++ account/account.py 2012-07-10 12:52:20 +0000
@@ -1862,8 +1862,10 @@
1862 'applicable_type': fields.selection( [('true','Always'), ('code','Given by Python Code')], 'Applicability', required=True,1862 'applicable_type': fields.selection( [('true','Always'), ('code','Given by Python Code')], 'Applicability', required=True,
1863 help="If not applicable (computed through a Python code), the tax won't appear on the invoice."),1863 help="If not applicable (computed through a Python code), the tax won't appear on the invoice."),
1864 'domain':fields.char('Domain', size=32, help="This field is only used if you develop your own module allowing developers to create specific taxes in a custom domain."),1864 'domain':fields.char('Domain', size=32, help="This field is only used if you develop your own module allowing developers to create specific taxes in a custom domain."),
1865 'account_collected_id':fields.many2one('account.account', 'Invoice Tax Account'),1865 'account_collected_id':fields.many2one('account.account', 'Invoice Tax Account', help="Set the account that will be set by default on invoice tax lines for invoices. Leave empty to use the expense account."),
1866 'account_paid_id':fields.many2one('account.account', 'Refund Tax Account'),1866 'account_paid_id':fields.many2one('account.account', 'Refund Tax Account', help="Set the account that will be set by default on invoice tax lines for refunds. Leave empty to use the expense account."),
1867 'account_analytic_collected_id':fields.many2one('account.analytic.account', 'Invoice Tax Analytic Account', help="Set the analytic account that will be used by default on the invoice tax lines for invoices. Leave empty if you don't want to use an analytic account on the invoice tax lines by default."),
1868 'account_analytic_paid_id':fields.many2one('account.analytic.account', 'Refund Tax Analytic Account', help="Set the analytic account that will be used by default on the invoice tax lines for refunds. Leave empty if you don't want to use an analytic account on the invoice tax lines by default."),
1867 'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True),1869 'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True),
1868 'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'),1870 'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'),
1869 'child_depend':fields.boolean('Tax on Children', help="Set if the tax computation is based on the computation of child taxes rather than on the total amount."),1871 'child_depend':fields.boolean('Tax on Children', help="Set if the tax computation is based on the computation of child taxes rather than on the total amount."),
@@ -2001,6 +2003,8 @@
2001 'name':tax.description and tax.description + " - " + tax.name or tax.name,2003 'name':tax.description and tax.description + " - " + tax.name or tax.name,
2002 'account_collected_id':tax.account_collected_id.id,2004 'account_collected_id':tax.account_collected_id.id,
2003 'account_paid_id':tax.account_paid_id.id,2005 'account_paid_id':tax.account_paid_id.id,
2006 'account_analytic_collected_id': tax.account_analytic_collected_id.id,
2007 'account_analytic_paid_id': tax.account_analytic_paid_id.id,
2004 'base_code_id': tax.base_code_id.id,2008 'base_code_id': tax.base_code_id.id,
2005 'ref_base_code_id': tax.ref_base_code_id.id,2009 'ref_base_code_id': tax.ref_base_code_id.id,
2006 'sequence': tax.sequence,2010 'sequence': tax.sequence,
@@ -2160,6 +2164,8 @@
2160 'amount': amount,2164 'amount': amount,
2161 'account_collected_id': tax.account_collected_id.id,2165 'account_collected_id': tax.account_collected_id.id,
2162 'account_paid_id': tax.account_paid_id.id,2166 'account_paid_id': tax.account_paid_id.id,
2167 'account_analytic_collected_id': tax.account_analytic_collected_id.id,
2168 'account_analytic_paid_id': tax.account_analytic_paid_id.id,
2163 'base_code_id': tax.base_code_id.id,2169 'base_code_id': tax.base_code_id.id,
2164 'ref_base_code_id': tax.ref_base_code_id.id,2170 'ref_base_code_id': tax.ref_base_code_id.id,
2165 'sequence': tax.sequence,2171 'sequence': tax.sequence,
21662172
=== modified file 'account/account_invoice.py'
--- account/account_invoice.py 2012-06-01 12:15:47 +0000
+++ account/account_invoice.py 2012-07-10 12:52:20 +0000
@@ -756,7 +756,7 @@
756 for tax in inv.tax_line:756 for tax in inv.tax_line:
757 if tax.manual:757 if tax.manual:
758 continue758 continue
759 key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id)759 key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id, tax.account_analytic_id.id)
760 tax_key.append(key)760 tax_key.append(key)
761 if not key in compute_taxes:761 if not key in compute_taxes:
762 raise osv.except_osv(_('Warning !'), _('Global taxes defined, but they are not in invoice lines !'))762 raise osv.except_osv(_('Warning !'), _('Global taxes defined, but they are not in invoice lines !'))
@@ -869,7 +869,7 @@
869 raise osv.except_osv(_('Error !'), _("Can not create the invoice !\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. The latest line of your payment term must be of type 'balance' to avoid rounding issues."))869 raise osv.except_osv(_('Error !'), _("Can not create the invoice !\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. The latest line of your payment term must be of type 'balance' to avoid rounding issues."))
870870
871 # one move line per tax line871 # one move line per tax line
872 iml += ait_obj.move_line_get(cr, uid, inv.id)872 iml += ait_obj._get_analytic_lines(cr, uid, inv.id)
873873
874 entry_type = ''874 entry_type = ''
875 if inv.type in ('in_invoice', 'in_refund'):875 if inv.type in ('in_invoice', 'in_refund'):
@@ -1578,6 +1578,7 @@
1578 'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),1578 'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),
1579 'name': fields.char('Tax Description', size=64, required=True),1579 'name': fields.char('Tax Description', size=64, required=True),
1580 'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),1580 'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),
1581 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),
1581 'base': fields.float('Base', digits_compute=dp.get_precision('Account')),1582 'base': fields.float('Base', digits_compute=dp.get_precision('Account')),
1582 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),1583 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
1583 'manual': fields.boolean('Manual'),1584 'manual': fields.boolean('Manual'),
@@ -1648,14 +1649,16 @@
1648 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)1649 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)
1649 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)1650 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)
1650 val['account_id'] = tax['account_collected_id'] or line.account_id.id1651 val['account_id'] = tax['account_collected_id'] or line.account_id.id
1652 val['account_analytic_id'] = tax['account_analytic_collected_id']
1651 else:1653 else:
1652 val['base_code_id'] = tax['ref_base_code_id']1654 val['base_code_id'] = tax['ref_base_code_id']
1653 val['tax_code_id'] = tax['ref_tax_code_id']1655 val['tax_code_id'] = tax['ref_tax_code_id']
1654 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)1656 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)
1655 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)1657 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)
1656 val['account_id'] = tax['account_paid_id'] or line.account_id.id1658 val['account_id'] = tax['account_paid_id'] or line.account_id.id
1659 val['account_analytic_id'] = tax['account_analytic_paid_id']
16571660
1658 key = (val['tax_code_id'], val['base_code_id'], val['account_id'])1661 key = (val['tax_code_id'], val['base_code_id'], val['account_id'], val['account_analytic_id'])
1659 if not key in tax_grouped:1662 if not key in tax_grouped:
1660 tax_grouped[key] = val1663 tax_grouped[key] = val
1661 else:1664 else:
@@ -1671,6 +1674,44 @@
1671 t['tax_amount'] = cur_obj.round(cr, uid, cur, t['tax_amount'])1674 t['tax_amount'] = cur_obj.round(cr, uid, cur, t['tax_amount'])
1672 return tax_grouped1675 return tax_grouped
16731676
1677
1678 def _get_analytic_lines(self, cr, uid, id, context=None):
1679 """Prepare the creation of tax account move lines and corresponding analytic lines.
1680 It is the equivalent of the function with the same name on the object account_invoice
1681 but for tax account move lines."""
1682 if context is None:
1683 context = {}
1684 inv_obj = self.pool.get('account.invoice')
1685 cur_obj = self.pool.get('res.currency')
1686 inv = inv_obj.browse(cr, uid, id, context=context)
1687
1688 company_currency = inv.company_id.currency_id.id
1689 if inv.type in ('out_invoice', 'in_refund'):
1690 sign = 1
1691 else:
1692 sign = -1
1693
1694 tax_lines = self.pool.get('account.invoice.tax').move_line_get(cr, uid, inv.id)
1695 for tl in tax_lines:
1696 if tl['account_analytic_id']:
1697 if inv.type in ('in_invoice', 'in_refund'):
1698 ref = inv.reference
1699 else:
1700 ref = inv_obj._convert_ref(cr, uid, inv.number)
1701 if not inv.journal_id.analytic_journal_id:
1702 raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,))
1703 tl['analytic_lines'] = [(0,0, {
1704 'name': tl['name'],
1705 'date': inv['date_invoice'],
1706 'account_id': tl['account_analytic_id'],
1707 'amount': cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, tl['tax_amount'], context={'date': inv.date_invoice}) * sign,
1708 'general_account_id': tl['account_id'],
1709 'journal_id': inv.journal_id.analytic_journal_id.id,
1710 'ref': ref,
1711 })]
1712 return tax_lines
1713
1714
1674 def move_line_get(self, cr, uid, invoice_id):1715 def move_line_get(self, cr, uid, invoice_id):
1675 res = []1716 res = []
1676 cr.execute('SELECT * FROM account_invoice_tax WHERE invoice_id=%s', (invoice_id,))1717 cr.execute('SELECT * FROM account_invoice_tax WHERE invoice_id=%s', (invoice_id,))
@@ -1687,7 +1728,8 @@
1687 'price': t['amount'] or 0.0,1728 'price': t['amount'] or 0.0,
1688 'account_id': t['account_id'],1729 'account_id': t['account_id'],
1689 'tax_code_id': t['tax_code_id'],1730 'tax_code_id': t['tax_code_id'],
1690 'tax_amount': t['tax_amount']1731 'tax_amount': t['tax_amount'],
1732 'account_analytic_id': t['account_analytic_id'],
1691 })1733 })
1692 return res1734 return res
16931735
16941736
=== modified file 'account/account_invoice_view.xml'
--- account/account_invoice_view.xml 2012-07-03 12:41:11 +0000
+++ account/account_invoice_view.xml 2012-07-10 12:52:20 +0000
@@ -98,6 +98,7 @@
98 <field name="name"/>98 <field name="name"/>
99 <field name="sequence"/>99 <field name="sequence"/>
100 <field name="account_id" groups="account.group_account_user"/>100 <field name="account_id" groups="account.group_account_user"/>
101 <field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting" />
101 <field name="manual"/>102 <field name="manual"/>
102 <field name="amount"/>103 <field name="amount"/>
103 <field name="base" readonly="0"/>104 <field name="base" readonly="0"/>
@@ -215,6 +216,7 @@
215 <tree editable="bottom" string="Taxes">216 <tree editable="bottom" string="Taxes">
216 <field name="name"/>217 <field name="name"/>
217 <field name="account_id" groups="account.group_account_invoice"/>218 <field name="account_id" groups="account.group_account_invoice"/>
219 <field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting" />
218 <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/>220 <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/>
219 <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/>221 <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/>
220222
221223
=== modified file 'account/account_view.xml'
--- account/account_view.xml 2012-07-02 11:27:50 +0000
+++ account/account_view.xml 2012-07-10 12:52:20 +0000
@@ -909,9 +909,9 @@
909 <field name="amount" attrs="{'readonly':[('type','in',('none', 'code', 'balance'))]}"/>909 <field name="amount" attrs="{'readonly':[('type','in',('none', 'code', 'balance'))]}"/>
910 <separator colspan="4" string="Accounting Information"/>910 <separator colspan="4" string="Accounting Information"/>
911 <field name="account_collected_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>911 <field name="account_collected_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
912 <label colspan="2" nolabel="1" string="Keep empty to use the income account"/>912 <field name="account_analytic_collected_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id), ('parent_id', '&lt;&gt;', False)]" groups="analytic.group_analytic_accounting" />
913 <field name="account_paid_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>913 <field name="account_paid_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
914 <label colspan="2" nolabel="1" string="Keep empty to use the expense account"/>914 <field name="account_analytic_paid_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id), ('parent_id', '&lt;&gt;', False)]" groups="analytic.group_analytic_accounting" />
915 <separator colspan="4" string="Tax Declaration: Invoices"/>915 <separator colspan="4" string="Tax Declaration: Invoices"/>
916 <field name="base_code_id"/>916 <field name="base_code_id"/>
917 <field name="base_sign"/>917 <field name="base_sign"/>

Subscribers

People subscribed via source and target branches

to all changes: