mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
[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.
This commit is contained in:
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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':
|
||||
|
||||
Reference in New Issue
Block a user