Merge lp:~acsone-openerp/account-analytic/account_analytic_required-test_suite-sbi into lp:~account-core-editors/account-analytic/7.0

Proposed by Stéphane Bidoul (Acsone) on 2014-04-18
Status: Merged
Merged at revision: 18
Proposed branch: lp:~acsone-openerp/account-analytic/account_analytic_required-test_suite-sbi
Merge into: lp:~account-core-editors/account-analytic/7.0
Diff against target: 369 lines (+249/-31)
6 files modified
account_analytic_required/__init__.py (+1/-1)
account_analytic_required/__openerp__.py (+17/-9)
account_analytic_required/account.py (+59/-20)
account_analytic_required/account_view.xml (+12/-1)
account_analytic_required/tests/__init__.py (+30/-0)
account_analytic_required/tests/test_account_analytic_required.py (+130/-0)
To merge this branch: bzr merge lp:~acsone-openerp/account-analytic/account_analytic_required-test_suite-sbi
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve on 2014-04-28
Alexis de Lattre (community) code review and tests 2014-04-18 Approve on 2014-04-18
Pedro Manuel Baeza code review 2014-04-18 Approve on 2014-04-18
Review via email: mp+216451@code.launchpad.net

Description of the change

Add a test suite for account_analytic_required, and fix a small hole in the policy check (when changing analytic account after creating the move line, the policy would not be checked).

To post a comment you must log in.
Pedro Manuel Baeza (pedro.baeza) wrote :

Thanks for the work, Stéphane.

Regards.

review: Approve (code review)
Alexis de Lattre (alexis-via) wrote :

Nice update. Thank you Stefan.

I am pushing to you a branch with pep8 stuff and the additional of the field in the tree view (and not just form view).

review: Approve (code review and tests)
19. By Stéphane Bidoul (Acsone) on 2014-04-19

[MRG] flake8 long lines + add policy in tree view from Alexis de Lattre

20. By Stéphane Bidoul (Acsone) on 2014-04-19

[IMP] comments in test suite + long lines __openerp__.py

Alexis de Lattre (alexis-via) wrote :

OK, let's go and merge it in the main branch now :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_analytic_required/__init__.py'
2--- account_analytic_required/__init__.py 2012-11-21 08:56:48 +0000
3+++ account_analytic_required/__init__.py 2014-04-19 10:20:35 +0000
4@@ -21,4 +21,4 @@
5 ##############################################################################
6
7
8-import account
9+from . import account
10
11=== modified file 'account_analytic_required/__openerp__.py'
12--- account_analytic_required/__openerp__.py 2013-04-23 14:25:48 +0000
13+++ account_analytic_required/__openerp__.py 2014-04-19 10:20:35 +0000
14@@ -2,7 +2,7 @@
15 ##############################################################################
16 #
17 # Account analytic required module for OpenERP
18-# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved
19+# Copyright (C) 2011 Akretion (http://www.akretion.com)
20 # @author Alexis de Lattre <alexis.delattre@akretion.com>
21 #
22 # This program is free software: you can redistribute it and/or modify
23@@ -22,15 +22,24 @@
24
25
26 {
27- 'name': 'Account analytic required',
28+ 'name': 'Account Analytic Required',
29 'version': '0.2',
30- 'category': 'Generic Modules/Accounting',
31+ 'category': 'Analytic Accounting',
32 'license': 'AGPL-3',
33- 'description': """This module adds an option "analytic policy" on account types. You have the choice between 3 policies : always, never and optional.
34-
35-For example, if you want to have an analytic account on all your expenses, set the policy to "always" for the account type "expense" ; then, if you try to save an account move line with an account of type "expense" without analytic account, you will get an error message.
36-
37-Module developped by Alexis de Lattre <alexis.delattre@akretion.com> during the Akretion-Camptocamp code sprint of June 2011.
38+ 'description': """
39+Account Analytic Required
40+=========================
41+
42+This module adds an option *analytic policy* on account types.
43+You have the choice between 3 policies : *always*, *never* and *optional*.
44+
45+For example, if you want to have an analytic account on all your expenses,
46+set the policy to *always* for the account type *expense* ; then, if you
47+try to save an account move line with an account of type *expense*
48+without analytic account, you will get an error message.
49+
50+Module developped by Alexis de Lattre <alexis.delattre@akretion.com>
51+during the Akretion-Camptocamp code sprint of June 2011.
52 """,
53 'author': 'Akretion',
54 'website': 'http://www.akretion.com/',
55@@ -39,4 +48,3 @@
56 'installable': True,
57 'active': False,
58 }
59-
60
61=== modified file 'account_analytic_required/account.py'
62--- account_analytic_required/account.py 2013-04-23 14:25:48 +0000
63+++ account_analytic_required/account.py 2014-04-19 10:20:35 +0000
64@@ -2,7 +2,7 @@
65 ##############################################################################
66 #
67 # Account analytic required module for OpenERP
68-# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved
69+# Copyright (C) 2011 Akretion (http://www.akretion.com)
70 # @author Alexis de Lattre <alexis.delattre@akretion.com>
71 # Developped during the Akretion-Camptocamp code sprint of June 2011
72 #
73@@ -22,43 +22,82 @@
74 ##############################################################################
75
76 from openerp.osv import orm, fields
77-from tools.translate import _
78+from openerp.tools.translate import _
79
80
81 class account_account_type(orm.Model):
82 _inherit = "account.account.type"
83
84 _columns = {
85- 'analytic_policy' : fields.selection([
86+ 'analytic_policy': fields.selection([
87 ('optional', 'Optional'),
88 ('always', 'Always'),
89 ('never', 'Never')
90- ], 'Policy for analytic account', help="Set the policy for analytic accounts : if you select 'Optional', the accountant is free to put an analytic account on an account move line with this type of account ; if you select 'Always', the accountant will get an error message if there is no analytic account ; if you select 'Never', the accountant will get an error message if an analytic account is present."),
91+ ], 'Policy for analytic account',
92+ help="Set the policy for analytic accounts : if you select "
93+ "'Optional', the accountant is free to put an analytic account "
94+ "on an account move line with this type of account ; if you "
95+ "select 'Always', the accountant will get an error message if "
96+ "there is no analytic account ; if you select 'Never', the "
97+ "accountant will get an error message if an analytic account "
98+ "is present."),
99 }
100
101 _defaults = {
102- 'analytic_policy': lambda *a: 'optional',
103+ 'analytic_policy': 'optional',
104 }
105
106
107 class account_move_line(orm.Model):
108 _inherit = "account.move.line"
109
110- def check_analytic_required(self, cr, uid, vals, context=None):
111- if 'account_id' in vals and (vals.get('debit', 0.0) != 0.0 or vals.get('credit', 0.0) != 0.0):
112- account = self.pool.get('account.account').browse(cr, uid, vals['account_id'], context=context)
113- if account.user_type.analytic_policy == 'always' and not vals.get('analytic_account_id', False):
114- raise orm.except_orm(_('Error :'), _("Analytic policy is set to 'Always' with account %s '%s' but the analytic account is missing in the account move line with label '%s'." % (account.code, account.name, vals.get('name', False))))
115- elif account.user_type.analytic_policy == 'never' and vals.get('analytic_account_id', False):
116- cur_analytic_account = self.pool.get('account.analytic.account').read(cr, uid, vals['analytic_account_id'], ['name', 'code'], context=context)
117- raise orm.except_orm(_('Error :'), _("Analytic policy is set to 'Never' with account %s '%s' but the account move line with label '%s' has an analytic account %s '%s'." % (account.code, account.name, vals.get('name', False), cur_analytic_account['code'], cur_analytic_account['name'])))
118+ def check_analytic_required(self, cr, uid, ids, vals, context=None):
119+ if 'account_id' in vals or 'analytic_account_id' in vals or \
120+ 'debit' in vals or 'credit' in vals:
121+ if isinstance(ids, (int, long)):
122+ ids = [ids]
123+ for move_line in self.browse(cr, uid, ids, context):
124+ if move_line.debit == 0 and move_line.credit == 0:
125+ continue
126+ analytic_policy = \
127+ move_line.account_id.user_type.analytic_policy
128+ if analytic_policy == 'always' and \
129+ not move_line.analytic_account_id:
130+ raise orm.except_orm(
131+ _('Error :'),
132+ _("Analytic policy is set to 'Always' with account "
133+ "%s '%s' but the analytic account is missing in "
134+ "the account move line with label '%s'.")
135+ % (
136+ move_line.account_id.code,
137+ move_line.account_id.name,
138+ move_line.name))
139+ elif analytic_policy == 'never' and \
140+ move_line.analytic_account_id:
141+ raise orm.except_orm(
142+ _('Error :'),
143+ _("Analytic policy is set to 'Never' with account %s "
144+ "'%s' but the account move line with label '%s' "
145+ "has an analytic account %s '%s'.")
146+ % (
147+ move_line.account_id.code,
148+ move_line.account_id.name,
149+ move_line.name,
150+ move_line.analytic_account_id.code,
151+ move_line.analytic_account_id.name))
152 return True
153
154 def create(self, cr, uid, vals, context=None, check=True):
155- self.check_analytic_required(cr, uid, vals, context=context)
156- return super(account_move_line, self).create(cr, uid, vals, context=context, check=check)
157-
158- def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
159- self.check_analytic_required(cr, uid, vals, context=context)
160- return super(account_move_line, self).write(cr, uid, ids, vals, context=context, check=check, update_check=update_check)
161-
162+ line_id = super(account_move_line, self).create(
163+ cr, uid, vals, context=context, check=check)
164+ self.check_analytic_required(cr, uid, line_id, vals, context=context)
165+ return line_id
166+
167+ def write(
168+ self, cr, uid, ids, vals, context=None, check=True,
169+ update_check=True):
170+ res = super(account_move_line, self).write(
171+ cr, uid, ids, vals, context=context, check=check,
172+ update_check=update_check)
173+ self.check_analytic_required(cr, uid, ids, vals, context=context)
174+ return res
175
176=== modified file 'account_analytic_required/account_view.xml'
177--- account_analytic_required/account_view.xml 2012-11-21 08:56:48 +0000
178+++ account_analytic_required/account_view.xml 2014-04-19 10:20:35 +0000
179@@ -15,7 +15,18 @@
180 <field name="inherit_id" ref="account.view_account_type_form" />
181 <field name="arch" type="xml">
182 <field name="code" position="after">
183- <field name="analytic_policy" />
184+ <field name="analytic_policy" />
185+ </field>
186+ </field>
187+</record>
188+
189+<record id="view_account_type_tree" model="ir.ui.view">
190+ <field name="name">account_analytic_required.account_type_tree</field>
191+ <field name="model">account.account.type</field>
192+ <field name="inherit_id" ref="account.view_account_type_tree" />
193+ <field name="arch" type="xml">
194+ <field name="code" position="after">
195+ <field name="analytic_policy" />
196 </field>
197 </field>
198 </record>
199
200=== added directory 'account_analytic_required/tests'
201=== added file 'account_analytic_required/tests/__init__.py'
202--- account_analytic_required/tests/__init__.py 1970-01-01 00:00:00 +0000
203+++ account_analytic_required/tests/__init__.py 2014-04-19 10:20:35 +0000
204@@ -0,0 +1,30 @@
205+# -*- encoding: utf-8 -*-
206+##############################################################################
207+#
208+# Account analytic required module for OpenERP
209+# Copyright (C) 2014 Acsone (http://acsone.eu). All Rights Reserved
210+# @author Stéphane Bidoul <stephane.bidoul@acsone.eu>
211+#
212+# This program is free software: you can redistribute it and/or modify
213+# it under the terms of the GNU Affero General Public License as
214+# published by the Free Software Foundation, either version 3 of the
215+# License, or (at your option) any later version.
216+#
217+# This program is distributed in the hope that it will be useful,
218+# but WITHOUT ANY WARRANTY; without even the implied warranty of
219+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
220+# GNU Affero General Public License for more details.
221+#
222+# You should have received a copy of the GNU Affero General Public License
223+# along with this program. If not, see <http://www.gnu.org/licenses/>.
224+#
225+##############################################################################
226+
227+from . import test_account_analytic_required
228+
229+fast_suite = [
230+]
231+
232+checks = [
233+ test_account_analytic_required,
234+]
235
236=== added file 'account_analytic_required/tests/test_account_analytic_required.py'
237--- account_analytic_required/tests/test_account_analytic_required.py 1970-01-01 00:00:00 +0000
238+++ account_analytic_required/tests/test_account_analytic_required.py 2014-04-19 10:20:35 +0000
239@@ -0,0 +1,130 @@
240+# -*- encoding: utf-8 -*-
241+##############################################################################
242+#
243+# Account analytic required module for OpenERP
244+# Copyright (C) 2014 Acsone (http://acsone.eu). All Rights Reserved
245+# @author Stéphane Bidoul <stephane.bidoul@acsone.eu>
246+#
247+# This program is free software: you can redistribute it and/or modify
248+# it under the terms of the GNU Affero General Public License as
249+# published by the Free Software Foundation, either version 3 of the
250+# License, or (at your option) any later version.
251+#
252+# This program is distributed in the hope that it will be useful,
253+# but WITHOUT ANY WARRANTY; without even the implied warranty of
254+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255+# GNU Affero General Public License for more details.
256+#
257+# You should have received a copy of the GNU Affero General Public License
258+# along with this program. If not, see <http://www.gnu.org/licenses/>.
259+#
260+##############################################################################
261+
262+from datetime import datetime
263+
264+from openerp.tests import common
265+from openerp.osv import orm
266+
267+
268+class test_account_analytic_required(common.TransactionCase):
269+
270+ def setUp(self):
271+ super(test_account_analytic_required, self).setUp()
272+ self.account_obj = self.registry('account.account')
273+ self.account_type_obj = self.registry('account.account.type')
274+ self.move_obj = self.registry('account.move')
275+ self.move_line_obj = self.registry('account.move.line')
276+ self.analytic_account_obj = self.registry('account.analytic.account')
277+ self.analytic_account_id = self.analytic_account_obj.create(
278+ self.cr, self.uid, {'name': 'test aa', 'type': 'normal'})
279+
280+ def _create_move(self, with_analytic, amount=100):
281+ date = datetime.now()
282+ period_id = self.registry('account.period').find(
283+ self.cr, self.uid, date,
284+ context={'account_period_prefer_normal': True})[0]
285+ move_vals = {
286+ 'journal_id': self.ref('account.sales_journal'),
287+ 'period_id': period_id,
288+ 'date': date,
289+ }
290+ move_id = self.move_obj.create(self.cr, self.uid, move_vals)
291+ move_line_id = self.move_line_obj.create(
292+ self.cr, self.uid,
293+ {'move_id': move_id,
294+ 'name': '/',
295+ 'debit': 0,
296+ 'credit': amount,
297+ 'account_id': self.ref('account.a_sale'),
298+ 'analytic_account_id':
299+ self.analytic_account_id if with_analytic else False})
300+ self.move_line_obj.create(
301+ self.cr, self.uid,
302+ {'move_id': move_id,
303+ 'name': '/',
304+ 'debit': amount,
305+ 'credit': 0,
306+ 'account_id': self.ref('account.a_recv')})
307+ return move_line_id
308+
309+ def _set_analytic_policy(self, policy, aref='account.a_sale'):
310+ account_type = self.account_obj.browse(self.cr, self.uid,
311+ self.ref(aref)).user_type
312+ self.account_type_obj.write(self.cr, self.uid, account_type.id,
313+ {'analytic_policy': policy})
314+
315+ def test_optional(self):
316+ self._create_move(with_analytic=False)
317+ self._create_move(with_analytic=True)
318+
319+ def test_always_no_analytic(self):
320+ self._set_analytic_policy('always')
321+ with self.assertRaises(orm.except_orm):
322+ self._create_move(with_analytic=False)
323+
324+ def test_always_no_analytic_0(self):
325+ # accept missing analytic account when debit=credit=0
326+ self._set_analytic_policy('always')
327+ self._create_move(with_analytic=False, amount=0)
328+
329+ def test_always_with_analytic(self):
330+ self._set_analytic_policy('always')
331+ self._create_move(with_analytic=True)
332+
333+ def test_never_no_analytic(self):
334+ self._set_analytic_policy('never')
335+ self._create_move(with_analytic=False)
336+
337+ def test_never_with_analytic(self):
338+ self._set_analytic_policy('never')
339+ with self.assertRaises(orm.except_orm):
340+ self._create_move(with_analytic=True)
341+
342+ def test_never_with_analytic_0(self):
343+ # accept analytic when debit=credit=0
344+ self._set_analytic_policy('never')
345+ self._create_move(with_analytic=True, amount=0)
346+
347+ def test_always_remove_analytic(self):
348+ # remove partner when policy is always
349+ self._set_analytic_policy('always')
350+ line_id = self._create_move(with_analytic=True)
351+ with self.assertRaises(orm.except_orm):
352+ self.move_line_obj.write(self.cr, self.uid, line_id,
353+ {'analytic_account_id': False})
354+
355+ def test_change_account(self):
356+ self._set_analytic_policy('always', aref='account.a_expense')
357+ line_id = self._create_move(with_analytic=False)
358+ # change account to a_expense with policy always but missing
359+ # analytic_account
360+ with self.assertRaises(orm.except_orm):
361+ self.move_line_obj.write(
362+ self.cr, self.uid, line_id,
363+ {'account_id': self.ref('account.a_expense')})
364+ # change account to a_expense with policy always
365+ # with analytic account -> ok
366+ self.move_line_obj.write(
367+ self.cr, self.uid, line_id, {
368+ 'account_id': self.ref('account.a_expense'),
369+ 'analytic_account_id': self.analytic_account_id})

Subscribers

People subscribed via source and target branches

to status/vote changes: