[ADD] Foreporting crude support for full payment workflow including

transferral move that pays the invoices
This commit is contained in:
Stefan Rijnhart
2013-05-27 21:36:20 +02:00
parent 24261bcc73
commit 5ae5d657f8
4 changed files with 74 additions and 39 deletions

View File

@@ -810,6 +810,12 @@ class banking_import_transaction(orm.Model):
move_info['invoice_ids'][0]
)
return vals
def hook_match_payment(self, cr, uid, transaction, log, context=None):
"""
To override in module 'account_banking_payment'
"""
return False
def match(self, cr, uid, ids, results=None, context=None):
if not ids:
@@ -1020,13 +1026,13 @@ class banking_import_transaction(orm.Model):
), context=context)
# rebrowse the current record after writing
transaction = self.browse(cr, uid, transaction.id, context=context)
# Match full direct debit orders
if transaction.type == bt.DIRECT_DEBIT and has_payment:
move_info = self._match_debit_order(
cr, uid, transaction, results['log'], context)
if transaction.type == bt.STORNO and has_payment:
move_info = self._match_storno(
cr, uid, transaction, results['log'], context)
# Match payment and direct debit orders
move_info_payment = hook_match_payment(
cr, uid, transaction, results['log'], context=context)
if move_info_payment:
move_info = move_info_payment
# Allow inclusion of generated bank invoices
if transaction.type == bt.BANK_COSTS:
lines = self._match_costs(

View File

@@ -45,6 +45,7 @@ As a counter measure, all imported data is converted to SWIFT-format before usag
from account_banking.parsers import models
from account_banking.parsers.convert import str2date, to_swift
from tools.translate import _
import re
import csv
bt = models.mem_bank_transaction
@@ -105,6 +106,13 @@ class transaction_message(object):
self.date = str2date(self.date, '%Y%m%d')
if self.direction == 'A':
self.transferred_amount = -float(self.transferred_amount)
if (self.transfer_type == 'VZ'
and (not self.remote_account or self.remote_account == '0')
and (not self.message or re.match('^\s*$', self.message))
and self.remote_owner.startswith('TOTAAL ')):
self.transfer_type = 'PB'
self.message = self.remote_owner
self.remove_owner = False
else:
self.transferred_amount = float(self.transferred_amount)
self.local_account = self.local_account.zfill(10)
@@ -140,7 +148,8 @@ class transaction(models.mem_bank_transaction):
'GT': bt.ORDER,
'IC': bt.DIRECT_DEBIT,
'OV': bt.ORDER,
'VZ': bt.PAYMENT_BATCH,
'VZ': bt.ORDER,
'PB': bt.PAYMENT_BATCH,
}
def __init__(self, line, *args, **kwargs):
@@ -171,11 +180,14 @@ class transaction(models.mem_bank_transaction):
4. Cash withdrawals from banks are too not seen as a transfer between
two accounts - the cash exits the banking system. These withdrawals
have their transfer_type set to 'GM'.
5. Aggregated payment batches. These transactions have transfer type
'VZ' natively but are changed to 'PB' while parsing. These transactions
have no remote account.
'''
return bool(self.transferred_amount and self.execution_date and (
self.remote_account or
self.transfer_type in [
'DV', 'BT', 'BA', 'GM',
'DV', 'PB', 'BT', 'BA', 'GM',
]))
def refold_message(self, message):

View File

@@ -32,24 +32,30 @@ from openerp.addons.decimal_precision import decimal_precision as dp
class banking_import_transaction(orm.Model):
_inherit = 'banking.import.transaction'
def _match_debit_order(
self, cr, uid, trans, log, context=None):
def _match_payment_order(
self, cr, uid, trans, log, order_type='payment', context=None):
def is_zero(total):
def equals_order_amount(payment_order, transferred_amount):
if (not hasattr(payment_order, 'payment_order_type')
or payment_order.payment_order_type == 'payment'):
sign = 1
else:
sign = -1
total = payment_order.total + sign * transferred_amount
return self.pool.get('res.currency').is_zero(
cr, uid, trans.statement_id.currency, total)
payment_order_obj = self.pool.get('payment.order')
order_ids = payment_order_obj.search(
cr, uid, [('payment_order_type', '=', 'debit'),
cr, uid, [('payment_order_type', '=', order_type),
('state', '=', 'sent'),
('date_sent', '<=', trans.execution_date),
],
limit=0, context=context)
orders = payment_order_obj.browse(cr, uid, order_ids, context)
candidates = [x for x in orders if
is_zero(x.total - trans.transferred_amount)]
equals_order_amount(x.total - trans.transferred_amount)]
if len(candidates) > 0:
# retrieve the common account_id, if any
account_id = False
@@ -170,10 +176,6 @@ class banking_import_transaction(orm.Model):
raise orm.except_orm(
_("Cannot reconcile"),
_("Cannot reconcile: no direct debit order"))
if transaction.payment_order_id.payment_order_type != 'debit':
raise orm.except_orm(
_("Cannot reconcile"),
_("Reconcile payment order not implemented"))
reconcile_id = payment_order_obj.debit_reconcile_transfer(
cr, uid,
transaction.payment_order_id.id,
@@ -231,11 +233,7 @@ class banking_import_transaction(orm.Model):
if not transaction.payment_order_id:
raise orm.except_orm(
_("Cannot unreconcile"),
_("Cannot unreconcile: no direct debit order"))
if transaction.payment_order_id.payment_order_type != 'debit':
raise orm.except_orm(
_("Cannot unreconcile"),
_("Unreconcile payment order not implemented"))
_("Cannot unreconcile: no payment or direct debit order"))
return payment_order_obj.debit_unreconcile_transfer(
cr, uid, transaction.payment_order_id.id,
transaction.statement_line_id.reconcile_id.id,
@@ -355,11 +353,25 @@ class banking_import_transaction(orm.Model):
)
return vals
def match(self, cr, uid, ids, results=None, context=None):
res = super(banking_import_transaction, self).match(
cr, uid, ids, results=results, context=context)
return res
def hook_match_payment(cr, uid, transaction, log, context=None):
"""
Called from match() in the core module.
Match payment batches, direct debit orders and stornos
"""
move_info = False
if transaction.type == bt.PAYMENT_BATCH:
move_info = self._match_payment_order(
cr, uid, transaction, log,
order_type='payment', context=context)
elif transaction.type == bt.DIRECT_DEBIT:
move_info = self._match_payment_order(
cr, uid, transaction, log,
order_type='debit', context=context)
elif transaction.type == bt.STORNO:
move_info = self._match_storno(
cr, uid, transaction, log,
context=context)
return move_info
def __init__(self, pool, cr):
"""

View File

@@ -102,7 +102,7 @@ class payment_order(osv.osv):
if not wkf_ok:
raise osv.except_osv(
_("Cannot unreconcile"),
_("Cannot unreconcile debit order: "+
_("Cannot unreconcile payment order: "+
"Workflow will not allow it."))
return True
@@ -119,7 +119,7 @@ class payment_order(osv.osv):
return False
else:
# TODO: define conditions for 'payment' orders
return False
return True
return True
def action_sent(self, cr, uid, ids, context=None):
@@ -135,8 +135,6 @@ class payment_order(osv.osv):
account_move_line_obj = self.pool.get('account.move.line')
payment_line_obj = self.pool.get('payment.line')
for order in self.browse(cr, uid, ids, context=context):
if order.payment_order_type != 'debit':
continue
for line in order.line_ids:
# basic checks
if not line.move_line_id:
@@ -152,23 +150,28 @@ class payment_order(osv.osv):
move_id = account_move_obj.create(cr, uid, {
'journal_id': order.mode.transfer_journal_id.id,
'name': 'Debit order %s' % line.move_line_id.move_id.name,
'reference': 'DEB%s' % line.move_line_id.move_id.name,
'name': '%s order %s' % (order.payment_order_type,
line.move_line_id.move_id.name),
'reference': '%s%s' % (order.payment_order_type[:3].upper(),
line.move_line_id.move_id.name),
}, context=context)
# TODO: take multicurrency into account
# create the debit move line on the transfer account
vals = {
'name': 'Debit order for %s' % (
'name': '%s order for %s' % (
order.payment_order_type,
line.move_line_id.invoice and
line.move_line_id.invoice.number or
line.move_line_id.name),
'move_id': move_id,
'partner_id': line.partner_id.id,
'account_id': order.mode.transfer_account_id.id,
'credit': 0.0,
'debit': line.amount,
'credit': (order.payment_order_type == 'payment'
and line.amount or 0.0),
'debit': (order.payment_order_type == 'debit'
and line.amount or 0.0),
'date': time.strftime('%Y-%m-%d'),
}
transfer_move_line_id = account_move_line_obj.create(
@@ -177,8 +180,10 @@ class payment_order(osv.osv):
# create the debit move line on the receivable account
vals.update({
'account_id': line.move_line_id.account_id.id,
'credit': line.amount,
'debit': 0.0,
'credit': (order.payment_order_type == 'debit'
and line.amount or 0.0),
'debit': (order.payment_order_type == 'payment'
and line.amount or 0.0),
})
reconcile_move_line_id = account_move_line_obj.create(
cr, uid, vals, context=context)