Merge lp:~akretion-team/openobject-addons/trunk-addons-analytic-on-tax into lp:openobject-addons
- trunk-addons-analytic-on-tax
- Merge into trunk
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 |
Related bugs: |
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.
Commit message
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:/
This merge proposal :
- adds a field 'account_
- adds 2 fields 'account_
- 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_
Cristian Salamea (ovnicraft) wrote : Posted in a previous version of this proposal | # |
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".
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 :-(
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).
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
1 | === modified file 'account/account.py' | |||
2 | --- account/account.py 2012-06-26 20:09:09 +0000 | |||
3 | +++ account/account.py 2012-07-10 12:52:20 +0000 | |||
4 | @@ -1862,8 +1862,10 @@ | |||
5 | 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, |
6 | 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."), |
7 | 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."), |
10 | 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."), |
11 | 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."), |
12 | 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."), | ||
13 | 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."), | ||
14 | 1867 | 'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True), | 1869 | 'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True), |
15 | 1868 | 'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'), | 1870 | 'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'), |
16 | 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."), |
17 | @@ -2001,6 +2003,8 @@ | |||
18 | 2001 | 'name':tax.description and tax.description + " - " + tax.name or tax.name, | 2003 | 'name':tax.description and tax.description + " - " + tax.name or tax.name, |
19 | 2002 | 'account_collected_id':tax.account_collected_id.id, | 2004 | 'account_collected_id':tax.account_collected_id.id, |
20 | 2003 | 'account_paid_id':tax.account_paid_id.id, | 2005 | 'account_paid_id':tax.account_paid_id.id, |
21 | 2006 | 'account_analytic_collected_id': tax.account_analytic_collected_id.id, | ||
22 | 2007 | 'account_analytic_paid_id': tax.account_analytic_paid_id.id, | ||
23 | 2004 | 'base_code_id': tax.base_code_id.id, | 2008 | 'base_code_id': tax.base_code_id.id, |
24 | 2005 | 'ref_base_code_id': tax.ref_base_code_id.id, | 2009 | 'ref_base_code_id': tax.ref_base_code_id.id, |
25 | 2006 | 'sequence': tax.sequence, | 2010 | 'sequence': tax.sequence, |
26 | @@ -2160,6 +2164,8 @@ | |||
27 | 2160 | 'amount': amount, | 2164 | 'amount': amount, |
28 | 2161 | 'account_collected_id': tax.account_collected_id.id, | 2165 | 'account_collected_id': tax.account_collected_id.id, |
29 | 2162 | 'account_paid_id': tax.account_paid_id.id, | 2166 | 'account_paid_id': tax.account_paid_id.id, |
30 | 2167 | 'account_analytic_collected_id': tax.account_analytic_collected_id.id, | ||
31 | 2168 | 'account_analytic_paid_id': tax.account_analytic_paid_id.id, | ||
32 | 2163 | 'base_code_id': tax.base_code_id.id, | 2169 | 'base_code_id': tax.base_code_id.id, |
33 | 2164 | 'ref_base_code_id': tax.ref_base_code_id.id, | 2170 | 'ref_base_code_id': tax.ref_base_code_id.id, |
34 | 2165 | 'sequence': tax.sequence, | 2171 | 'sequence': tax.sequence, |
35 | 2166 | 2172 | ||
36 | === modified file 'account/account_invoice.py' | |||
37 | --- account/account_invoice.py 2012-06-01 12:15:47 +0000 | |||
38 | +++ account/account_invoice.py 2012-07-10 12:52:20 +0000 | |||
39 | @@ -756,7 +756,7 @@ | |||
40 | 756 | for tax in inv.tax_line: | 756 | for tax in inv.tax_line: |
41 | 757 | if tax.manual: | 757 | if tax.manual: |
42 | 758 | continue | 758 | continue |
44 | 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) |
45 | 760 | tax_key.append(key) | 760 | tax_key.append(key) |
46 | 761 | if not key in compute_taxes: | 761 | if not key in compute_taxes: |
47 | 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 !')) |
48 | @@ -869,7 +869,7 @@ | |||
49 | 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.")) |
50 | 870 | 870 | ||
51 | 871 | # one move line per tax line | 871 | # one move line per tax line |
53 | 872 | iml += ait_obj.move_line_get(cr, uid, inv.id) | 872 | iml += ait_obj._get_analytic_lines(cr, uid, inv.id) |
54 | 873 | 873 | ||
55 | 874 | entry_type = '' | 874 | entry_type = '' |
56 | 875 | if inv.type in ('in_invoice', 'in_refund'): | 875 | if inv.type in ('in_invoice', 'in_refund'): |
57 | @@ -1578,6 +1578,7 @@ | |||
58 | 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), |
59 | 1579 | 'name': fields.char('Tax Description', size=64, required=True), | 1579 | 'name': fields.char('Tax Description', size=64, required=True), |
60 | 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')]), |
61 | 1581 | 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'), | ||
62 | 1581 | 'base': fields.float('Base', digits_compute=dp.get_precision('Account')), | 1582 | 'base': fields.float('Base', digits_compute=dp.get_precision('Account')), |
63 | 1582 | 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), | 1583 | 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), |
64 | 1583 | 'manual': fields.boolean('Manual'), | 1584 | 'manual': fields.boolean('Manual'), |
65 | @@ -1648,14 +1649,16 @@ | |||
66 | 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) |
67 | 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) |
68 | 1650 | val['account_id'] = tax['account_collected_id'] or line.account_id.id | 1651 | val['account_id'] = tax['account_collected_id'] or line.account_id.id |
69 | 1652 | val['account_analytic_id'] = tax['account_analytic_collected_id'] | ||
70 | 1651 | else: | 1653 | else: |
71 | 1652 | val['base_code_id'] = tax['ref_base_code_id'] | 1654 | val['base_code_id'] = tax['ref_base_code_id'] |
72 | 1653 | val['tax_code_id'] = tax['ref_tax_code_id'] | 1655 | val['tax_code_id'] = tax['ref_tax_code_id'] |
73 | 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) |
74 | 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) |
75 | 1656 | val['account_id'] = tax['account_paid_id'] or line.account_id.id | 1658 | val['account_id'] = tax['account_paid_id'] or line.account_id.id |
76 | 1659 | val['account_analytic_id'] = tax['account_analytic_paid_id'] | ||
77 | 1657 | 1660 | ||
79 | 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']) |
80 | 1659 | if not key in tax_grouped: | 1662 | if not key in tax_grouped: |
81 | 1660 | tax_grouped[key] = val | 1663 | tax_grouped[key] = val |
82 | 1661 | else: | 1664 | else: |
83 | @@ -1671,6 +1674,44 @@ | |||
84 | 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']) |
85 | 1672 | return tax_grouped | 1675 | return tax_grouped |
86 | 1673 | 1676 | ||
87 | 1677 | |||
88 | 1678 | def _get_analytic_lines(self, cr, uid, id, context=None): | ||
89 | 1679 | """Prepare the creation of tax account move lines and corresponding analytic lines. | ||
90 | 1680 | It is the equivalent of the function with the same name on the object account_invoice | ||
91 | 1681 | but for tax account move lines.""" | ||
92 | 1682 | if context is None: | ||
93 | 1683 | context = {} | ||
94 | 1684 | inv_obj = self.pool.get('account.invoice') | ||
95 | 1685 | cur_obj = self.pool.get('res.currency') | ||
96 | 1686 | inv = inv_obj.browse(cr, uid, id, context=context) | ||
97 | 1687 | |||
98 | 1688 | company_currency = inv.company_id.currency_id.id | ||
99 | 1689 | if inv.type in ('out_invoice', 'in_refund'): | ||
100 | 1690 | sign = 1 | ||
101 | 1691 | else: | ||
102 | 1692 | sign = -1 | ||
103 | 1693 | |||
104 | 1694 | tax_lines = self.pool.get('account.invoice.tax').move_line_get(cr, uid, inv.id) | ||
105 | 1695 | for tl in tax_lines: | ||
106 | 1696 | if tl['account_analytic_id']: | ||
107 | 1697 | if inv.type in ('in_invoice', 'in_refund'): | ||
108 | 1698 | ref = inv.reference | ||
109 | 1699 | else: | ||
110 | 1700 | ref = inv_obj._convert_ref(cr, uid, inv.number) | ||
111 | 1701 | if not inv.journal_id.analytic_journal_id: | ||
112 | 1702 | raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,)) | ||
113 | 1703 | tl['analytic_lines'] = [(0,0, { | ||
114 | 1704 | 'name': tl['name'], | ||
115 | 1705 | 'date': inv['date_invoice'], | ||
116 | 1706 | 'account_id': tl['account_analytic_id'], | ||
117 | 1707 | 'amount': cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, tl['tax_amount'], context={'date': inv.date_invoice}) * sign, | ||
118 | 1708 | 'general_account_id': tl['account_id'], | ||
119 | 1709 | 'journal_id': inv.journal_id.analytic_journal_id.id, | ||
120 | 1710 | 'ref': ref, | ||
121 | 1711 | })] | ||
122 | 1712 | return tax_lines | ||
123 | 1713 | |||
124 | 1714 | |||
125 | 1674 | def move_line_get(self, cr, uid, invoice_id): | 1715 | def move_line_get(self, cr, uid, invoice_id): |
126 | 1675 | res = [] | 1716 | res = [] |
127 | 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,)) |
128 | @@ -1687,7 +1728,8 @@ | |||
129 | 1687 | 'price': t['amount'] or 0.0, | 1728 | 'price': t['amount'] or 0.0, |
130 | 1688 | 'account_id': t['account_id'], | 1729 | 'account_id': t['account_id'], |
131 | 1689 | 'tax_code_id': t['tax_code_id'], | 1730 | 'tax_code_id': t['tax_code_id'], |
133 | 1690 | 'tax_amount': t['tax_amount'] | 1731 | 'tax_amount': t['tax_amount'], |
134 | 1732 | 'account_analytic_id': t['account_analytic_id'], | ||
135 | 1691 | }) | 1733 | }) |
136 | 1692 | return res | 1734 | return res |
137 | 1693 | 1735 | ||
138 | 1694 | 1736 | ||
139 | === modified file 'account/account_invoice_view.xml' | |||
140 | --- account/account_invoice_view.xml 2012-07-03 12:41:11 +0000 | |||
141 | +++ account/account_invoice_view.xml 2012-07-10 12:52:20 +0000 | |||
142 | @@ -98,6 +98,7 @@ | |||
143 | 98 | <field name="name"/> | 98 | <field name="name"/> |
144 | 99 | <field name="sequence"/> | 99 | <field name="sequence"/> |
145 | 100 | <field name="account_id" groups="account.group_account_user"/> | 100 | <field name="account_id" groups="account.group_account_user"/> |
146 | 101 | <field name="account_analytic_id" domain="[('type','<>','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting" /> | ||
147 | 101 | <field name="manual"/> | 102 | <field name="manual"/> |
148 | 102 | <field name="amount"/> | 103 | <field name="amount"/> |
149 | 103 | <field name="base" readonly="0"/> | 104 | <field name="base" readonly="0"/> |
150 | @@ -215,6 +216,7 @@ | |||
151 | 215 | <tree editable="bottom" string="Taxes"> | 216 | <tree editable="bottom" string="Taxes"> |
152 | 216 | <field name="name"/> | 217 | <field name="name"/> |
153 | 217 | <field name="account_id" groups="account.group_account_invoice"/> | 218 | <field name="account_id" groups="account.group_account_invoice"/> |
154 | 219 | <field name="account_analytic_id" domain="[('type','<>','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting" /> | ||
155 | 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"/> |
156 | 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)"/> |
157 | 220 | 222 | ||
158 | 221 | 223 | ||
159 | === modified file 'account/account_view.xml' | |||
160 | --- account/account_view.xml 2012-07-02 11:27:50 +0000 | |||
161 | +++ account/account_view.xml 2012-07-10 12:52:20 +0000 | |||
162 | @@ -909,9 +909,9 @@ | |||
163 | 909 | <field name="amount" attrs="{'readonly':[('type','in',('none', 'code', 'balance'))]}"/> | 909 | <field name="amount" attrs="{'readonly':[('type','in',('none', 'code', 'balance'))]}"/> |
164 | 910 | <separator colspan="4" string="Accounting Information"/> | 910 | <separator colspan="4" string="Accounting Information"/> |
165 | 911 | <field name="account_collected_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/> | 911 | <field name="account_collected_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/> |
167 | 912 | <label colspan="2" nolabel="1" string="Keep empty to use the income account"/> | 912 | <field name="account_analytic_collected_id" domain="[('type','<>','view'), ('company_id', '=', company_id), ('parent_id', '<>', False)]" groups="analytic.group_analytic_accounting" /> |
168 | 913 | <field name="account_paid_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/> | 913 | <field name="account_paid_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/> |
170 | 914 | <label colspan="2" nolabel="1" string="Keep empty to use the expense account"/> | 914 | <field name="account_analytic_paid_id" domain="[('type','<>','view'), ('company_id', '=', company_id), ('parent_id', '<>', False)]" groups="analytic.group_analytic_accounting" /> |
171 | 915 | <separator colspan="4" string="Tax Declaration: Invoices"/> | 915 | <separator colspan="4" string="Tax Declaration: Invoices"/> |
172 | 916 | <field name="base_code_id"/> | 916 | <field name="base_code_id"/> |
173 | 917 | <field name="base_sign"/> | 917 | <field name="base_sign"/> |
Hello looks good but analytic_ id': fields. many2one( 'account. analytic. account' , 'Analytic account'),
+ 'account_
is already necessary ?
Account invoice line gets by default this field.
Regards,