Merge lp:~acsone-openerp/account-financial-tools/account_partner_required-sbi into lp:~account-core-editors/account-financial-tools/7.0

Proposed by Stéphane Bidoul (Acsone)
Status: Merged
Merged at revision: 188
Proposed branch: lp:~acsone-openerp/account-financial-tools/account_partner_required-sbi
Merge into: lp:~account-core-editors/account-financial-tools/7.0
Diff against target: 382 lines (+351/-0)
6 files modified
account_partner_required/__init__.py (+23/-0)
account_partner_required/__openerp__.py (+46/-0)
account_partner_required/account.py (+96/-0)
account_partner_required/account_view.xml (+35/-0)
account_partner_required/tests/__init__.py (+30/-0)
account_partner_required/tests/test_account_partner_required.py (+121/-0)
To merge this branch: bzr merge lp:~acsone-openerp/account-financial-tools/account_partner_required-sbi
Reviewer Review Type Date Requested Status
Omar (Pexego) code review Approve
Joël Grand-Guillaume @ camptocamp code review, no tests Approve
Lorenzo Battistini (community) code review Approve
Frederic Clementi - Camptocamp Pending
Review via email: mp+216442@code.launchpad.net

Description of the change

New module to control the partner field in account move lines.

In many cases, it is desirable to enforce the presence of the
partner field in account move lines, but not always.

This module provides such a mechanism based on the account user type.

Cfr mailing list discussion for reference.

[1] https://lists.launchpad.net/openerp-community/msg05502.html

To post a comment you must log in.
175. By Stéphane Bidoul (Acsone)

[IMP] add policy column in account type tree view

176. By Stéphane Bidoul (Acsone)

[IMP] local import

177. By Stéphane Bidoul (Acsone)

[IMP] header comments

Revision history for this message
Lorenzo Battistini (elbati) wrote :

Hello Stéphane,

why not using '_constraints' member instead of overriding create and write methods?

Is there any technical reason to avoid YAML tests?

Thanks!

review: Needs Information
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

Hello Lorenzo,

About the constraints. This module is heavily inspired by account_analytic_required which used the same technique. I must confess I did not question the approach. Initially account_analytic_required was working mainly on the vals dictionary so it would have been faster than constraints. While working on account_partner_required I identified a bug in account_analytic_required which required a refactoring [1] which possibly rendered the optimization less obvious. Now since there are really two constraints to be checked based on the policy, the current approach is probably still slightly faster.

Would you agree to keep the current approach and postpone a possible performance test / refactoring with constraints to another MP?

Regarding yml vs unittest, it's only a matter of personal taste in this case. I notice the unittest2 framework seems better documented [2]. But hey, at least I have tests, right :)

[1] https://code.launchpad.net/~acsone-openerp/account-analytic/account_analytic_required-test_suite-sbi
[2] https://doc.openerp.com/trunk/server/05_test_framework/

Revision history for this message
Lorenzo Battistini (elbati) wrote :

Ok :-)

review: Approve (code review)
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Hi Stéphane,

Thanks for the contrib, and as usual, thanks for providing tests :)

LGMT,

Regards,

Joël

review: Approve (code review, no tests)
Revision history for this message
Omar (Pexego) (omar7r) wrote :

LGTM

review: Approve (code review)

Preview Diff

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

Subscribers

People subscribed via source and target branches