From e0094a76fb8f77e2a7fa303b1a7540adb0723379 Mon Sep 17 00:00:00 2001
From: "Pieter J. Kersten"
Date: Mon, 7 Nov 2011 23:23:48 +0100
Subject: [PATCH] [FIX] account_banking_nl_multibank: Fixed broken statement
numbering [FIX] account_banking: Payment order lines were processed twice,
once as payment_line and once as account_move_line.
[IMP] account_banking: improved string searching in matching. When search
strings are larger than the string to be searched,
reverse match.
---
account_banking/wizard/bank_import.py | 121 +++++++++++++---------
account_banking_nl_multibank/multibank.py | 2 +
2 files changed, 72 insertions(+), 51 deletions(-)
diff --git a/account_banking/wizard/bank_import.py b/account_banking/wizard/bank_import.py
index 9b1fc9ced..1cf130de3 100644
--- a/account_banking/wizard/bank_import.py
+++ b/account_banking/wizard/bank_import.py
@@ -115,6 +115,19 @@ class banking_import(wizard.interface):
# TODO: reprocess multiple matched invoices and payments afterwards
self.__multiple_matches = []
+ def _cached(self, move_line):
+ '''Check if the move_line has been cached'''
+ return move_line.id in self.__linked_invoices
+
+ def _cache(self, move_line, remaining=0.0):
+ '''Cache the move_line'''
+ self.__linked_invoices[move_line.id] = remaining
+
+ def _remaining(self, move_line):
+ '''Return the remaining amount for a previously matched move_line
+ '''
+ return self.__linked_invoices[move_line.id]
+
def _fill_results(self, *args, **kwargs):
return {'log': self._log}
@@ -218,14 +231,26 @@ class banking_import(wizard.interface):
partner_ids, bank_account_ids, log):
'''
Find the payment order belonging to this reference - if there is one
- This is the easiest part: when sending payments, the returned bank info
- should be identical to ours.
+ When sending payments, the returned bank info should be identical to
+ ours.
'''
- # TODO: Not sure what side effects are created when payments are done
- # for credited customer invoices, which will be matched later on too.
+ # TODO:
+ # 1. Not sure what side effects are created when payments are done
+ # for credited customer invoices, which will be matched later on
+ # too.
+ # 2. Have to include possible combinations of partial payments by
+ # both payment order and by hand.
+
digits = int(config['price_accuracy'])
+
+ # Check both cache of payment_lines as move_lines, as both are
+ # intertwined. Ignoring this causes double processing of the same
+ # payment line.
+
candidates = [x for x in payment_lines
- if ((x.communication and x.communication == trans.reference) or
+ if x.id not in self.__linked_payments and
+ (not self._cached(x.move_line_id)) and
+ ((x.communication and x.communication == trans.reference) or
(x.communication2 and x.communication2 == trans.message))
and round(x.amount, digits) ==
-round(trans.transferred_amount, digits)
@@ -235,19 +260,18 @@ class banking_import(wizard.interface):
]
if len(candidates) == 1:
candidate = candidates[0]
- # Check cache to prevent multiple matching of a single payment
- if candidate.id not in self.__linked_payments:
- self.__linked_payments[candidate.id] = True
- payment_line_obj = self.pool.get('payment.line')
- payment_line_obj.write(cursor, uid, [candidate.id], {
- 'export_state': 'done',
- 'date_done': trans.effective_date.strftime('%Y-%m-%d')}
+ self.__linked_payments[candidate.id] = True
+ self._cache(candidate.move_line_id)
+ payment_line_obj = self.pool.get('payment.line')
+ payment_line_obj.write(cursor, uid, [candidate.id], {
+ 'export_state': 'done',
+ 'date_done': trans.effective_date.strftime('%Y-%m-%d')}
+ )
+ return self._get_move_info(
+ cursor, uid, candidate.move_line_id,
+ partner_bank_id=\
+ bank_account_ids and bank_account_ids[0].id or False
)
- return self._get_move_info(
- cursor, uid, candidate.move_line_id,
- partner_bank_id=\
- bank_account_ids and bank_account_ids[0].id or False
- )
return False
@@ -306,39 +330,36 @@ class banking_import(wizard.interface):
Match on ID of invoice (reference, name or number, whatever
available and sensible)
'''
+ lref = len(ref); lmsg = len(msg)
if invoice.reference:
# Reference always comes first, as it is manually set for a
# reason.
iref = invoice.reference.upper()
- if iref in ref or iref in msg:
+ liref = len(iref)
+ if iref in ref or iref in msg or \
+ (liref > lref and ref in iref) or \
+ (liref > lmsg and msg in iref):
return True
if invoice.type.startswith('in_'):
# Internal numbering, no likely match on number
if invoice.name:
iname = invoice.name.upper()
- if iname in ref or iname in msg:
+ liname = len(iname)
+ if iname in ref or iname in msg or \
+ (liname > lref and ref in iname) or \
+ (liname > lmsg and msg in iname):
return True
elif invoice.type.startswith('out_'):
# External id's possible and likely
inum = invoice.number.upper()
- if inum in ref or inum in msg:
+ linum = len(inum)
+ if inum in ref or inum in msg or \
+ (linum > lref and ref in inum) or \
+ (linum > lmsg and msg in inum):
return True
return False
- def _cached(move_line):
- '''Check if the move_line has been cached'''
- return move_line.id in self.__linked_invoices
-
- def _cache(move_line, remaining=0.0):
- '''Cache the move_line'''
- self.__linked_invoices[move_line.id] = remaining
-
- def _remaining(move_line):
- '''Return the remaining amount for a previously matched move_line
- '''
- return self.__linked_invoices[move_line.id]
-
def _sign(invoice):
'''Return the direction of an invoice'''
return {'in_invoice': -1,
@@ -355,7 +376,7 @@ class banking_import(wizard.interface):
candidates = [x for x in move_lines
if x.partner_id.id in partner_ids and
str2date(x.date, '%Y-%m-%d') <= (trans.execution_date + payment_window)
- and (not _cached(x) or _remaining(x))
+ and (not self._cached(x) or self._remaining(x))
]
else:
candidates = []
@@ -375,18 +396,18 @@ class banking_import(wizard.interface):
if x.invoice and has_id_match(x.invoice, ref, msg)
and str2date(x.invoice.date_invoice, '%Y-%m-%d')
<= (trans.execution_date + payment_window)
- and (not _cached(x) or _remaining(x))
+ and (not self._cached(x) or self._remaining(x))
]
# Match on amount expected. Limit this kind of search to known
# partners.
if not candidates and partner_ids:
candidates = [x for x in move_lines
- if round(abs(x.credit or x.debit), digits) ==
- round(abs(trans.transferred_amount), digits)
+ if round(x.credit and -x.credit or x.debit, digits) ==
+ round(trans.transferred_amount, digits)
and str2date(x.date, '%Y-%m-%d') <=
(trans.execution_date + payment_window)
- and (not _cached(x) or _remaining(x))
+ and (not self._cached(x) or self._remaining(x))
]
move_line = False
@@ -396,8 +417,8 @@ class banking_import(wizard.interface):
#
# TODO: currency coercing
best = [x for x in candidates
- if round(abs(x.credit or x.debit), digits) ==
- round(abs(trans.transferred_amount), digits)
+ if round(x.credit and -x.credit or x.debit, digits) ==
+ round(trans.transferred_amount, digits)
and str2date(x.date, '%Y-%m-%d') <=
(trans.execution_date + payment_window)
]
@@ -405,11 +426,11 @@ class banking_import(wizard.interface):
# Exact match
move_line = best[0]
invoice = move_line.invoice
- if _cached(move_line):
+ if self._cached(move_line):
partial = True
- expected = _remaining(move_line)
+ expected = self._remaining(move_line)
else:
- _cache(move_line)
+ self._cache(move_line)
elif len(candidates) > 1:
# Before giving up, check cache for catching duplicate
@@ -418,7 +439,7 @@ class banking_import(wizard.interface):
if x.invoice and has_id_match(x.invoice, ref, msg)
and str2date(x.invoice.date_invoice, '%Y-%m-%d')
<= trans.execution_date
- and (_cached(x) and not _remaining(x))
+ and (self._cached(x) and not self._remaining(x))
]
if paid:
log.append(
@@ -469,11 +490,11 @@ class banking_import(wizard.interface):
})
elif abs(expected) > abs(found):
# Partial payment, reuse invoice
- _cache(move_line, expected - found)
+ self._cache(move_line, expected - found)
elif abs(expected) < abs(found):
# Possible combined payments, need to split transaction to
# verify
- _cache(move_line)
+ self._cache(move_line)
trans2 = trans.copy()
trans2.transferred_amount -= expected
trans.transferred_amount = expected
@@ -889,9 +910,7 @@ class banking_import(wizard.interface):
# Easiest match: customer id
elif transaction.remote_owner_custno:
- partner_ids = partner_obj.browse(
- cursor, uid, [transaction.remote_owner_custno]
- )
+ partner_ids = [transaction.remote_owner_custno]
iban_acc = sepa.IBAN(transaction.remote_account)
if iban_acc.valid:
domain = [('iban','=',str(iban_acc))]
@@ -991,8 +1010,8 @@ class banking_import(wizard.interface):
amount = transaction.transferred_amount,
account_id = account_id.id,
statement_id = statement_id,
- note = transaction.message,
- ref = transaction.reference,
+ note = transaction.reference and transaction.message or '',
+ ref = transaction.reference or transaction.message,
period_id = period_id,
currency = account_info.currency_id.id,
)
diff --git a/account_banking_nl_multibank/multibank.py b/account_banking_nl_multibank/multibank.py
index 68e089396..36378e999 100644
--- a/account_banking_nl_multibank/multibank.py
+++ b/account_banking_nl_multibank/multibank.py
@@ -85,6 +85,8 @@ class transaction_message(object):
self.execution_date = str2date(self.execution_date, '%d-%m-%Y')
self.effective_date = str2date(self.effective_date, '%d-%m-%Y')
self.id = str(subno).zfill(4)
+ self.statement_id = '-'.join([str(self.execution_date.year),
+ self.statement_id])
# Map outgoing payment batches from general payments. They are
# distinguished from normal payments with type_id '9722'
if self.transfer_type == 'OVB' and self.transfer_type_id == '9722':