Merge lp:~acsone-openerp/banking-addons/7.0-bug-1280814-base_completion into lp:banking-addons/bank-statement-reconcile-70

Proposed by Laurent Mignon (Acsone)
Status: Merged
Approved by: Pedro Manuel Baeza
Approved revision: 122
Merged at revision: 120
Proposed branch: lp:~acsone-openerp/banking-addons/7.0-bug-1280814-base_completion
Merge into: lp:banking-addons/bank-statement-reconcile-70
Diff against target: 173 lines (+131/-6)
4 files modified
account_statement_base_completion/__init__.py (+2/-2)
account_statement_base_completion/statement.py (+7/-4)
account_statement_base_completion/tests/__init__.py (+27/-0)
account_statement_base_completion/tests/test_base_completion.py (+95/-0)
To merge this branch: bzr merge lp:~acsone-openerp/banking-addons/7.0-bug-1280814-base_completion
Reviewer Review Type Date Requested Status
Pedro Manuel Baeza code review Approve
Alexandre Fayolle - camptocamp code review Approve
Leonardo Pistone code review Approve
Review via email: mp+206617@code.launchpad.net

Description of the change

[FIX] completion on partner name in the statement line label (lp:1280814)

To post a comment you must log in.
121. By Laurent Mignon (Acsone)

a little query optimization

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Thanks for the fix which LGTM. This code really needs some automated test though.

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Hmm not sure if your fix is really ok, though:

regexp_matches(string text, pattern text [, flags text])

it seems to me that you have either inverted the args to that function, or you end up using re.escape on the wrong parameter.

Automated test definitely needed.

review: Needs Fixing (code review, no test)
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

> Hmm not sure if your fix is really ok, though:
>
> regexp_matches(string text, pattern text [, flags text])
>
> it seems to me that you have either inverted the args to that function, or you
> end up using re.escape on the wrong parameter.
>
> Automated test definitely needed.

my bad, the automated test is there.

Revision history for this message
Laurent Mignon (Acsone) (lmi) wrote :

> my bad, the automated test is there.
Thanks for the review and, yes, automated tests have been added by the MP https://code.launchpad.net/~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-tests-no-split-lep/+merge/199835
Do you maintain your 'Needs Fixing'?
Regards,

lmi

Revision history for this message
Leonardo Pistone (lepistone) wrote :

Thanks for your work, Laurent.

@alexandre: we're green! can you imagine a new case we can test to find a problem in Laurent's code?

The fix for the typo porfile_id -> profile_id seems correct, as I can't find the wrong spelling anywhere in the code.

The fact that we had not realised that worries be a bit, though.

review: Needs Information (code review, test)
Revision history for this message
Laurent Mignon (Acsone) (lmi) wrote :

Thanks for the review Leonardo

> The fact that we had not realised that worries be a bit, though.

The type only appeared once the search has been fixed and has returned a matching partner. I ask me if this completion rule has been functional in the past.

Regards,

lmi

Revision history for this message
Leonardo Pistone (lepistone) wrote :

Thanks Laurent.

I lift my objection on the typo then, and I leave Alexandre with his remark on the regexp.

review: Approve (code review)
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

>
> > my bad, the automated test is there.
> Thanks for the review and, yes, automated tests have been added by the MP
> https://code.launchpad.net/~camptocamp/banking-addons/bank-statement-
> reconcile-7.0-add-tests-no-split-lep/+merge/199835
> Do you maintain your 'Needs Fixing'?
> Regards,
>
> lmi

my understanding of regexp_matches is that arg 1 is the string we want to check, and arg 2 is the regular expression against which we to the matching (http://www.postgresql.org/docs/9.1/static/functions-matching.html)

In the code you propose to merge, you pass a regular expression ('.*' + re.escape(str) + '.*') as the first argument, and a string from the db (which may contain unescaped regular expression special characters such as .) as the regexp value. So this needs to be fixed : at the very least the convertsion of st_line['name'] to a regexp should be removed. And I'm interested in a test in which a partner has name "jh..doe" and a statement line has value 'jheudoe'.

Revision history for this message
Laurent Mignon (Acsone) (lmi) wrote :

Hi Alexandre,

I'll review the code according to your comments.

lmi

122. By Laurent Mignon (Acsone)

[FIX] escape res_partner.name column as second arg of regexp_matches and keep the first one as unescaped. Add a lot of tests for completion based on the res_partner name

Revision history for this message
Laurent Mignon (Acsone) (lmi) wrote :

> my understanding of regexp_matches is that arg 1 is the string we want to
> check, and arg 2 is the regular expression against which we to the matching
> (http://www.postgresql.org/docs/9.1/static/functions-matching.html)
>
> In the code you propose to merge, you pass a regular expression ('.*' +
> re.escape(str) + '.*') as the first argument, and a string from the db (which
> may contain unescaped regular expression special characters such as .) as the
> regexp value. So this needs to be fixed : at the very least the convertsion of
> st_line['name'] to a regexp should be removed. And I'm interested in a test in
> which a partner has name "jh..doe" and a statement line has value 'jheudoe'.

Hi Alexandre,

The code has been modified according to your review.

lmi

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Thanks for the code update.

LGTM

review: Approve (code review)
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Thanks for the fix!

review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_statement_base_completion/__init__.py'
2--- account_statement_base_completion/__init__.py 2012-12-20 13:37:01 +0000
3+++ account_statement_base_completion/__init__.py 2014-02-17 17:24:16 +0000
4@@ -19,5 +19,5 @@
5 #
6 ##############################################################################
7
8-import statement
9-import partner
10+from . import partner
11+from . import statement
12
13=== modified file 'account_statement_base_completion/statement.py'
14--- account_statement_base_completion/statement.py 2014-02-02 10:58:40 +0000
15+++ account_statement_base_completion/statement.py 2014-02-17 17:24:16 +0000
16@@ -319,9 +319,12 @@
17 if not context['partner_memoizer']:
18 return res
19 st_obj = self.pool.get('account.bank.statement.line')
20- sql = "SELECT id FROM res_partner WHERE name ~* %s and id in %s"
21- pattern = ".*%s.*" % re.escape(st_line['name'])
22- cr.execute(sql, (pattern, context['partner_memoizer']))
23+ # regexp_replace(name,'([^a-zA-Z0-9 -])', '\\\1', 'g'), 'i') escape the column name to avoid false positive. (ex 'jho..doe' -> 'joh\.\.doe'
24+ sql = """SELECT id FROM (
25+ SELECT id, regexp_matches(%s, regexp_replace(name,'([^[:alpha:]0-9 -])', %s, 'g'), 'i') AS name_match FROM res_partner
26+ WHERE id IN %s) AS res_patner_matcher
27+ WHERE name_match IS NOT NULL"""
28+ cr.execute(sql, (st_line['name'], r"\\\1", context['partner_memoizer']))
29 result = cr.fetchall()
30 if not result:
31 return res
32@@ -332,7 +335,7 @@
33 res['partner_id'] = result[0][0]
34 st_vals = st_obj.get_values_for_line(cr,
35 uid,
36- profile_id=st_line['porfile_id'],
37+ profile_id=st_line['profile_id'],
38 master_account_id=st_line['master_account_id'],
39 partner_id=res['partner_id'],
40 line_type=False,
41
42=== added directory 'account_statement_base_completion/tests'
43=== added file 'account_statement_base_completion/tests/__init__.py'
44--- account_statement_base_completion/tests/__init__.py 1970-01-01 00:00:00 +0000
45+++ account_statement_base_completion/tests/__init__.py 2014-02-17 17:24:16 +0000
46@@ -0,0 +1,27 @@
47+# -*- coding: utf-8 -*-
48+#
49+#
50+# Authors: Laurent Mignon
51+# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
52+# All Rights Reserved
53+#
54+# This program is free software: you can redistribute it and/or modify
55+# it under the terms of the GNU Affero General Public License as
56+# published by the Free Software Foundation, either version 3 of the
57+# License, or (at your option) any later version.
58+#
59+# This program is distributed in the hope that it will be useful,
60+# but WITHOUT ANY WARRANTY; without even the implied warranty of
61+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62+# GNU Affero General Public License for more details.
63+#
64+# You should have received a copy of the GNU Affero General Public License
65+# along with this program. If not, see <http://www.gnu.org/licenses/>.
66+#
67+#
68+
69+from . import test_base_completion
70+
71+checks = [
72+ test_base_completion
73+]
74
75=== added file 'account_statement_base_completion/tests/test_base_completion.py'
76--- account_statement_base_completion/tests/test_base_completion.py 1970-01-01 00:00:00 +0000
77+++ account_statement_base_completion/tests/test_base_completion.py 2014-02-17 17:24:16 +0000
78@@ -0,0 +1,95 @@
79+# -*- coding: utf-8 -*-
80+#
81+#
82+# Authors: Laurent Mignon
83+# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
84+# All Rights Reserved
85+#
86+# This program is free software: you can redistribute it and/or modify
87+# it under the terms of the GNU Affero General Public License as
88+# published by the Free Software Foundation, either version 3 of the
89+# License, or (at your option) any later version.
90+#
91+# This program is distributed in the hope that it will be useful,
92+# but WITHOUT ANY WARRANTY; without even the implied warranty of
93+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94+# GNU Affero General Public License for more details.
95+#
96+# You should have received a copy of the GNU Affero General Public License
97+# along with this program. If not, see <http://www.gnu.org/licenses/>.
98+#
99+#
100+from openerp.tests import common
101+import time
102+from collections import namedtuple
103+
104+name_completion_case = namedtuple("name_completion_case", ["partner_name", "line_label", "should_match"])
105+NAMES_COMPLETION_CASES = [
106+ name_completion_case("Acsone", "Line for Acsone SA", True),
107+ name_completion_case("Acsone", "Line for Acsone", True),
108+ name_completion_case("Acsone", "Acsone for line", True),
109+ name_completion_case("acsone", "Acsone for line", True),
110+ name_completion_case("Acsone SA", "Line for Acsone SA test", True),
111+ name_completion_case("Ac..ne", "Acsone for line", False),
112+ name_completion_case("é@|r{}", "Acsone é@|r{} for line", True),
113+ name_completion_case("Acsone", "A..one for line", False),
114+ name_completion_case("A.one SA", "A.one SA for line", True),
115+ name_completion_case("Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False),
116+ name_completion_case("Acsone ([^a-zA-Z0-9 -]) SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", True),
117+ ]
118+
119+
120+class base_completion(common.TransactionCase):
121+
122+ def setUp(self):
123+ super(base_completion, self).setUp()
124+ self.company_a = self.browse_ref('base.main_company')
125+ self.profile_obj = self.registry("account.statement.profile")
126+ self.partner_obj = self.registry("res.partner")
127+ self.account_bank_statement_obj = self.registry("account.bank.statement")
128+ self.account_bank_statement_line_obj = self.registry("account.bank.statement.line")
129+ self.journal_id = self.ref("account.bank_journal")
130+ self.partner_id = self.ref('base.main_partner')
131+ self.account_id = self.ref("account.a_recv")
132+ self.partner_id = self.ref("base.res_partner_12")
133+
134+ def test_name_completion(self):
135+ """Test complete partner_id from statement line label
136+ Test the automatic completion of the partner_id based if the name of the partner appears in
137+ the statement line label
138+ """
139+ self.completion_rule_id = self.ref('account_statement_base_completion.bank_statement_completion_rule_3')
140+ # Create the profile
141+ self.profile_id = self.profile_obj.create(self.cr, self.uid, {
142+ "name": "TEST",
143+ "commission_account_id": self.account_id,
144+ "journal_id": self.journal_id,
145+ "rule_ids": [(6, 0, [self.completion_rule_id])]})
146+ # Create a bank statement
147+ self.statement_id = self.account_bank_statement_obj.create(self.cr, self.uid, {
148+ "balance_end_real": 0.0,
149+ "balance_start": 0.0,
150+ "date": time.strftime('%Y-%m-%d'),
151+ "journal_id": self.journal_id,
152+ "profile_id": self.profile_id
153+ })
154+
155+ for case in NAMES_COMPLETION_CASES:
156+ self.partner_obj.write(self.cr, self.uid, self.partner_id, {'name': case.partner_name})
157+ statement_line_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, {
158+ 'amount': 1000.0,
159+ 'name': case.line_label,
160+ 'ref': 'My ref',
161+ 'statement_id': self.statement_id,
162+ })
163+ statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, statement_line_id)
164+ self.assertFalse(statement_line.partner_id, "Partner_id must be blank before completion")
165+ statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id)
166+ statement_obj.button_auto_completion()
167+ statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, statement_line_id)
168+ if case.should_match:
169+ self.assertEquals(self.partner_id, statement_line.partner_id['id'],
170+ "Missing expected partner id after completion (partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label))
171+ else:
172+ self.assertNotEquals(self.partner_id, statement_line.partner_id['id'],
173+ "Partner id should be empty after completion(partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label))

Subscribers

People subscribed via source and target branches