Merge lp:~therp-nl/banking-addons/ba61-multicompany_safe_partner_search into lp:banking-addons/6.1

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 161
Proposed branch: lp:~therp-nl/banking-addons/ba61-multicompany_safe_partner_search
Merge into: lp:banking-addons/6.1
Diff against target: 133 lines (+31/-39)
2 files modified
account_banking/banking_import_transaction.py (+1/-2)
account_banking/wizard/banktools.py (+30/-37)
To merge this branch: bzr merge lp:~therp-nl/banking-addons/ba61-multicompany_safe_partner_search
Reviewer Review Type Date Requested Status
Alexandre Fayolle - camptocamp Approve
Guewen Baconnier @ Camptocamp code review, no test Approve
Ronald Portier (Therp) Approve
Review via email: mp+146795@code.launchpad.net

Description of the change

This branch fixes partner search in a multicompany database. As there are no multicompany rules on addresses, the module can trigger the 'Access prohibited by access rules' error when trying to read partners through their addresses.

Additionally:
- match by partner name is slightly improved by disregarding very short partner names.
- name of the database cursor has been standardized to 'cr' in this method.
- already disabled code for searching by address components has been removed
- renamed variable name 'filter' to 'filter_' as 'filter' is a keyword (adding trailing underscore as per pep8)
- context propagation and PEP8
- removed unused imports

To post a comment you must log in.
Revision history for this message
Ronald Portier (Therp) (rportier1962) wrote :

Why not replace filter with criteria (for example)? IMHO the trailing underscore is a pain on the eyes.

More importantly, I get the impression that the way the code is changed will result in a great multitude of false positives. Especially when searching for very common names.

Maybe I see it completely wrong, but it seems that on l.26 you empty all criteria, and then on l.46 you are going to search for ALL partners with an address in the same country. Later, on lines 59-62 you filter out all partners with a name (that should be longer then 3 positions) that is not part of the name passed.

I think the search for city and postal code are not disabled in the original code, and should not be in the adapted code.

My apologies in advance if I somehow misread your changes.

One thing more: there should no print statement left in the final code.

review: Needs Fixing
161. By Stefan Rijnhart (Opener)

[FIX] Reinstate search by zip and city
[RFR] Remove debug statement

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Well my apologies for uploading code before my second cup of coffee ;-)

You are right on all points. About the underscore, it's what PEP8 says but I don't want to hurt anyone's eyes. Should all be fixed now.

Revision history for this message
Ronald Portier (Therp) (rportier1962) wrote :

Approve LGTM

One other idea;
If multiple names are found, maybe better to take the longest, instead of the first?

Lets assume we have the following partner names:
Smith
Smithsonian
Smithsons

The function is passed the name Smithsons Ltd.

None of the partner names is ilike Smithsons Ltd., so we have to do a brute force search.
This will eliminate Smithsonian (not in Smithsons Ltd.)

Then Smithsons would seem to be the better match.

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

I notice no context is provided and therefore none is propagated.

Regarding the test 'if (not country_code) or not country_id' :

* would "if not (country_code and country_id)" be more readable? (not sure about this, and see 2nd point below)

* from the code higher in the function, we get there if a country_code was provided but the corresponding country was not found. My understanding of the execution flow leads me to think that the first part of the test is to guard against a NameError because country_id is only defined if country_code was defined. In that case, I recommend setting country_id to False at the beginning of the function, which allows to rewrite the test as "if not country_id"

review: Needs Information (code review, no test)
162. By Stefan Rijnhart (Opener)

[RFR] PEP8
[RFR] Refactor double check on country_id and country_code
[IMP] Select longest matching partner name if multiple matches
[IMP] Propagate context in get_or_create_partner

163. By Stefan Rijnhart (Opener)

[FIX] Lingering parenthesis

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

@Ronald Thanks for the suggestion, I have implemented 'longest matching partner name wins'

@Alexandre Thanks, I changed the logic around and took the opportunity to refactor this part of the code with respect to context propagation and line length. Lots of legacy issues in the rest of this module left but we'll get there piece by piece.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

LGTM

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

"we'll get there piece by piece" -> yes, that's the idea. I only came across this in this review because it showed up in the context diff... We can't really afford a code review of the whole code base, but when improvements opportunities show up, we should take advantage of them.

Thanks for the refactoring.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2012-12-18 14:42:08 +0000
+++ account_banking/banking_import_transaction.py 2013-02-07 09:58:26 +0000
@@ -1314,8 +1314,7 @@
1314 transaction.remote_owner_address,1314 transaction.remote_owner_address,
1315 transaction.remote_owner_postalcode,1315 transaction.remote_owner_postalcode,
1316 transaction.remote_owner_city,1316 transaction.remote_owner_city,
1317 country_code, results['log']1317 country_code, results['log'], context=context)
1318 )
1319 if transaction.remote_account:1318 if transaction.remote_account:
1320 partner_bank_id = create_bank_account(1319 partner_bank_id = create_bank_account(
1321 self.pool, cr, uid, partner_id,1320 self.pool, cr, uid, partner_id,
13221321
=== modified file 'account_banking/wizard/banktools.py'
--- account_banking/wizard/banktools.py 2012-12-18 14:41:15 +0000
+++ account_banking/wizard/banktools.py 2013-02-07 09:58:26 +0000
@@ -19,14 +19,11 @@
19#19#
20##############################################################################20##############################################################################
2121
22import sys
23import datetime22import datetime
24import re
25from tools.translate import _23from tools.translate import _
26from account_banking.parsers import convert24from account_banking.parsers import convert
27from account_banking import sepa25from account_banking import sepa
28from account_banking.struct import struct26from account_banking.struct import struct
29import unicodedata
3027
31__all__ = [28__all__ = [
32 'get_period', 29 'get_period',
@@ -121,71 +118,67 @@
121 except KeyError:118 except KeyError:
122 return False119 return False
123120
124def get_or_create_partner(pool, cursor, uid, name, address, postal_code, city,121def get_or_create_partner(pool, cr, uid, name, address, postal_code, city,
125 country_code, log):122 country_code, log, context=None):
126 '''123 '''
127 Get or create the partner belonging to the account holders name <name>124 Get or create the partner belonging to the account holders name <name>
128125
129 If multiple partners are found with the same name, select the first and126 If multiple partners are found with the same name, select the first and
130 add a warning to the import log.127 add a warning to the import log.
128
129 TODO: revive the search by lines from the address argument
131 '''130 '''
132 partner_obj = pool.get('res.partner')131 partner_obj = pool.get('res.partner')
133 partner_ids = partner_obj.search(cursor, uid, [('name', 'ilike', name)])132 partner_ids = partner_obj.search(cr, uid, [('name', 'ilike', name)],
133 context=context)
134 country_id = False
134 if not partner_ids:135 if not partner_ids:
135 # Try brute search on address and then match reverse136 # Try brute search on address and then match reverse
136 address_obj = pool.get('res.partner.address')137 criteria = []
137 filter = [('partner_id', '<>', None)]
138 if country_code:138 if country_code:
139 country_obj = pool.get('res.country')139 country_obj = pool.get('res.country')
140 country_ids = country_obj.search(140 country_ids = country_obj.search(
141 cursor, uid, [('code','=',country_code.upper())]141 cr, uid, [('code', '=', country_code.upper())],
142 )142 context=context)
143 country_id = country_ids and country_ids[0] or False143 country_id = country_ids and country_ids[0] or False
144 filter.append(('country_id', '=', country_id))144 criteria.append(('address.country_id', '=', country_id))
145 # disable for now. Apparently, address is an array of lines.
146 if address and False:
147 if len(address) >= 1:
148 filter.append(('street', 'ilike', address[0]))
149 if len(address) > 1:
150 filter.append(('street2', 'ilike', address[1]))
151 if city:145 if city:
152 filter.append(('city', 'ilike', city))146 criteria.append(('address.city', 'ilike', city))
153 if postal_code:147 if postal_code:
154 filter.append(('zip', 'ilike', postal_code))148 criteria.append(('address.zip', 'ilike', postal_code))
155 address_ids = address_obj.search(cursor, uid, filter)149 partner_search_ids = partner_obj.search(
150 cr, uid, criteria, context=context)
156 key = name.lower()151 key = name.lower()
157152 partners = []
158 # Make sure to get a unique list153 for partner in partner_obj.read(
159 partner_ids = list(set([x.partner_id.id154 cr, uid, partner_search_ids, ['name'], context=context):
160 for x in address_obj.browse(cursor, uid, address_ids)155 if (len(partner['name']) > 3 and partner['name'].lower() in key):
161 # Beware for dangling addresses156 partners.append(partner)
162 if _has_attr(x.partner_id, 'name') and157 partners.sort(key=lambda x: len(x['name']), reverse=True)
163 x.partner_id.name.lower() in key158 partner_ids = [x['id'] for x in partners]
164 ]))
165 if not partner_ids:159 if not partner_ids:
166 if (not country_code) or not country_id:160 if not country_id:
167 user = pool.get('res.user').browse(cursor, uid, uid)161 user = pool.get('res.user').browse(cr, uid, uid, context=context)
168 country_id = (162 country_id = (
169 user.company_id.partner_id.country and 163 user.company_id.partner_id.country and
170 user.company_id.partner_id.country.id or164 user.company_id.partner_id.country.id or
171 False165 False
172 )166 )
173 partner_id = partner_obj.create(cursor, uid, dict(167 partner_id = partner_obj.create(cr, uid, dict(
174 name=name, active=True, comment='Generated from Bank Statements Import',168 name=name, active=True,
169 comment='Generated from Bank Statements Import',
175 address=[(0,0,{170 address=[(0,0,{
176 'street': address and address[0] or '',171 'street': address and address[0] or '',
177 'street2': len(address) > 1 and address[1] or '',172 'street2': len(address) > 1 and address[1] or '',
178 'city': city,173 'city': city,
179 'zip': postal_code or '',174 'zip': postal_code or '',
180 'country_id': country_id,175 'country_id': country_id,
181 })],176 })]), context=context)
182 ))
183 else:177 else:
184 if len(partner_ids) > 1:178 if len(partner_ids) > 1:
185 log.append(179 log.append(
186 _('More than one possible match found for partner with name %(name)s')180 _('More than one possible match found for partner with '
187 % {'name': name}181 'name %(name)s') % {'name': name})
188 )
189 partner_id = partner_ids[0]182 partner_id = partner_ids[0]
190 return partner_id183 return partner_id
191184

Subscribers

People subscribed via source and target branches