PEP8 on account_banking

This commit is contained in:
Sandy Carter
2014-09-02 12:36:36 -04:00
parent 07729d6a80
commit 1a6763368e
22 changed files with 917 additions and 668 deletions

View File

@@ -11,8 +11,8 @@
# garantees and support are strongly adviced to contract EduSense BV # garantees and support are strongly adviced to contract EduSense BV
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -24,6 +24,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
import sepa import sepa
import record import record
import banking_import_transaction import banking_import_transaction
@@ -33,5 +34,3 @@ import wizard
import res_partner import res_partner
import res_bank import res_bank
import res_partner_bank import res_partner_bank
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -70,7 +70,8 @@
+ IBAN accounts are the standard in the SEPA countries + IBAN accounts are the standard in the SEPA countries
+ local accounts are derived from SEPA (excluding Turkey) but are + local accounts are derived from SEPA (excluding Turkey) but are
considered to be identical to the corresponding SEPA account. considered to be identical to the corresponding SEPA account.
+ Banks are identified with either Country + Bank code + Branch code or BIC + Banks are identified with either Country + Bank code + Branch code or
BIC
+ Each bank can have its own pace in introducing SEPA into their + Each bank can have its own pace in introducing SEPA into their
communication with their customers. communication with their customers.
+ National online databases can be used to convert BBAN's to IBAN's. + National online databases can be used to convert BBAN's to IBAN's.

View File

@@ -86,10 +86,10 @@ class account_banking_account_settings(orm.Model):
string='Partner'), string='Partner'),
'default_credit_account_id': fields.many2one( 'default_credit_account_id': fields.many2one(
'account.account', 'Default credit account', select=True, 'account.account', 'Default credit account', select=True,
help=('The account to use when an unexpected payment was signaled. ' help=('The account to use when an unexpected payment was signaled.'
'This can happen when a direct debit payment is cancelled ' ' This can happen when a direct debit payment is cancelled '
'by a customer, or when no matching payment can be found. ' 'by a customer, or when no matching payment can be found. '
' Mind that you can correct movements before confirming them.' 'Mind that you can correct movements before confirming them.'
), ),
required=True required=True
), ),
@@ -98,8 +98,8 @@ class account_banking_account_settings(orm.Model):
select=True, required=True, select=True, required=True,
help=('The account to use when an unexpected payment is received. ' help=('The account to use when an unexpected payment is received. '
'This can be needed when a customer pays in advance or when ' 'This can be needed when a customer pays in advance or when '
'no matching invoice can be found. Mind that you can correct ' 'no matching invoice can be found. Mind that you can '
'movements before confirming them.' 'correct movements before confirming them.'
), ),
), ),
'costs_account_id': fields.many2one( 'costs_account_id': fields.many2one(
@@ -196,7 +196,7 @@ class account_banking_account_settings(orm.Model):
values['journal_id'] = bank['journal_id'][0] values['journal_id'] = bank['journal_id'][0]
return {'value': values} return {'value': values}
def onchange_company_id ( def onchange_company_id(
self, cr, uid, ids, company_id=False, context=None): self, cr, uid, ids, company_id=False, context=None):
if not company_id: if not company_id:
return {} return {}
@@ -229,35 +229,57 @@ class account_banking_imported_file(orm.Model):
_description = __doc__ _description = __doc__
_rec_name = 'date' _rec_name = 'date'
_columns = { _columns = {
'company_id': fields.many2one('res.company', 'Company', 'company_id': fields.many2one(
select=True, readonly=True 'res.company',
'Company',
select=True,
readonly=True,
), ),
'date': fields.datetime('Import Date', readonly=True, select=True, 'date': fields.datetime(
states={'draft': [('readonly', False)]} 'Import Date',
readonly=True,
select=True,
states={'draft': [('readonly', False)]},
), ),
'format': fields.char('File Format', size=20, readonly=True, 'format': fields.char(
states={'draft': [('readonly', False)]} 'File Format',
size=20,
readonly=True,
states={'draft': [('readonly', False)]},
), ),
'file': fields.binary('Raw Data', readonly=True, 'file': fields.binary(
states={'draft': [('readonly', False)]} 'Raw Data',
readonly=True,
states={'draft': [('readonly', False)]},
), ),
'file_name': fields.char('File name', size=256), 'file_name': fields.char('File name', size=256),
'log': fields.text('Import Log', readonly=True, 'log': fields.text(
states={'draft': [('readonly', False)]} 'Import Log',
readonly=True,
states={'draft': [('readonly', False)]},
), ),
'user_id': fields.many2one('res.users', 'Responsible User', 'user_id': fields.many2one(
readonly=True, select=True, 'res.users',
states={'draft': [('readonly', False)]} 'Responsible User',
readonly=True,
select=True,
states={'draft': [('readonly', False)]},
), ),
'state': fields.selection( 'state': fields.selection(
[('unfinished', 'Unfinished'), [
('unfinished', 'Unfinished'),
('error', 'Error'), ('error', 'Error'),
('review', 'Review'), ('review', 'Review'),
('ready', 'Finished'), ('ready', 'Finished'),
], 'State', select=True, readonly=True ],
'State',
select=True,
readonly=True,
), ),
'statement_ids': fields.one2many('account.bank.statement', 'statement_ids': fields.one2many(
'banking_id', 'Statements', 'account.bank.statement',
'banking_id',
'Statements',
readonly=False, readonly=False,
), ),
} }
@@ -284,10 +306,16 @@ class account_bank_statement(orm.Model):
_inherit = 'account.bank.statement' _inherit = 'account.bank.statement'
_columns = { _columns = {
'period_id': fields.many2one('account.period', 'Period', 'period_id': fields.many2one(
required=False, readonly=True), 'account.period',
'banking_id': fields.many2one('account.banking.imported.file', 'Period',
'Imported File', readonly=True, required=False,
readonly=True,
),
'banking_id': fields.many2one(
'account.banking.imported.file',
'Imported File',
readonly=True,
), ),
} }
@@ -321,7 +349,7 @@ class account_bank_statement(orm.Model):
_constraints = [ _constraints = [
(_check_company_id, (_check_company_id,
'The journal and period chosen have to belong to the same company.', 'The journal and period chosen have to belong to the same company.',
['journal_id','period_id']), ['journal_id', 'period_id']),
] ]
def _get_period(self, cr, uid, date=False, context=None): def _get_period(self, cr, uid, date=False, context=None):
@@ -419,9 +447,10 @@ class account_bank_statement(orm.Model):
('account_id', '=', st_line.account_id.id)], ('account_id', '=', st_line.account_id.id)],
context=context) context=context)
account_move_line_obj.write(cr, uid, torec, { account_move_line_obj.write(cr, uid, torec, {
(st_line.reconcile_id.line_partial_ids and (st_line.reconcile_id.line_partial_ids
'reconcile_partial_id' or 'reconcile_id'): and 'reconcile_partial_id'
st_line.reconcile_id.id }, context=context) or 'reconcile_id'): st_line.reconcile_id.id
}, context=context)
for move_line in (st_line.reconcile_id.line_id or []) + ( for move_line in (st_line.reconcile_id.line_id or []) + (
st_line.reconcile_id.line_partial_ids or []): st_line.reconcile_id.line_partial_ids or []):
netsvc.LocalService("workflow").trg_trigger( netsvc.LocalService("workflow").trg_trigger(
@@ -438,7 +467,7 @@ class account_bank_statement(orm.Model):
if ids and isinstance(ids, (int, long)): if ids and isinstance(ids, (int, long)):
ids = [ids] ids = [ids]
noname_ids = self.search( noname_ids = self.search(
cr, uid, [('id', 'in', ids),('name', '=', '/')], cr, uid, [('id', 'in', ids), ('name', '=', '/')],
context=context) context=context)
for st in self.browse(cr, uid, noname_ids, context=context): for st in self.browse(cr, uid, noname_ids, context=context):
if st.journal_id.sequence_id: if st.journal_id.sequence_id:
@@ -464,7 +493,7 @@ class account_voucher(orm.Model):
context = {} context = {}
if not context.get('period_id') and context.get('move_line_ids'): if not context.get('period_id') and context.get('move_line_ids'):
move_line = self.pool.get('account.move.line').browse( move_line = self.pool.get('account.move.line').browse(
cr, uid , context.get('move_line_ids')[0], context=context) cr, uid, context.get('move_line_ids')[0], context=context)
return move_line.period_id.id return move_line.period_id.id
return super(account_voucher, self)._get_period(cr, uid, context) return super(account_voucher, self)._get_period(cr, uid, context)
@@ -498,8 +527,8 @@ class account_bank_statement_line(orm.Model):
which is inaccessible from within this method. which is inaccessible from within this method.
''' '''
res_users_obj = self.pool.get('res.users') res_users_obj = self.pool.get('res.users')
return res_users_obj.browse(cr, uid, uid, return res_users_obj.browse(
context=context).company_id.currency_id.id cr, uid, uid, context=context).company_id.currency_id.id
def _get_invoice_id(self, cr, uid, ids, name, args, context=None): def _get_invoice_id(self, cr, uid, ids, name, args, context=None):
res = {} res = {}
@@ -519,35 +548,69 @@ class account_bank_statement_line(orm.Model):
_columns = { _columns = {
# Redefines. Todo: refactor away to view attrs # Redefines. Todo: refactor away to view attrs
'amount': fields.float('Amount', readonly=True, 'amount': fields.float(
digits_compute=dp.get_precision('Account'), 'Amount',
states={'draft': [('readonly', False)]}),
'ref': fields.char('Ref.', size=32, readonly=True,
states={'draft': [('readonly', False)]}),
'name': fields.char('Name', size=64, required=False, readonly=True,
states={'draft': [('readonly', False)]}),
'date': fields.date('Date', required=True, readonly=True,
states={'draft': [('readonly', False)]}),
# New columns
'trans': fields.char('Bank Transaction ID', size=15, required=False,
readonly=True, readonly=True,
states={'draft':[('readonly', False)]}, digits_compute=dp.get_precision('Account'),
states={'draft': [('readonly', False)]},
), ),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account', 'ref': fields.char(
required=False, readonly=True, 'Ref.',
states={'draft':[('readonly', False)]}, size=32,
readonly=True,
states={'draft': [('readonly', False)]},
),
'name': fields.char(
'Name',
size=64,
required=False,
readonly=True,
states={'draft': [('readonly', False)]},
),
'date': fields.date(
'Date',
required=True,
readonly=True,
states={'draft': [('readonly', False)]},
),
# New columns
'trans': fields.char(
'Bank Transaction ID',
size=15,
required=False,
readonly=True,
states={'draft': [('readonly', False)]},
),
'partner_bank_id': fields.many2one(
'res.partner.bank',
'Bank Account',
required=False,
readonly=True,
states={'draft': [('readonly', False)]},
),
'period_id': fields.many2one(
'account.period',
'Period',
required=True,
states={'confirmed': [('readonly', True)]},
),
'currency': fields.many2one(
'res.currency',
'Currency',
required=True,
states={'confirmed': [('readonly', True)]},
), ),
'period_id': fields.many2one('account.period', 'Period', required=True,
states={'confirmed': [('readonly', True)]}),
'currency': fields.many2one('res.currency', 'Currency', required=True,
states={'confirmed': [('readonly', True)]}),
'reconcile_id': fields.many2one( 'reconcile_id': fields.many2one(
'account.move.reconcile', 'Reconciliation', readonly=True 'account.move.reconcile',
'Reconciliation',
readonly=True,
), ),
'invoice_id': fields.function( 'invoice_id': fields.function(
_get_invoice_id, method=True, string='Linked Invoice', _get_invoice_id,
type='many2one', relation='account.invoice' method=True,
string='Linked Invoice',
type='many2one',
relation='account.invoice',
), ),
} }
@@ -600,8 +663,6 @@ class invoice(orm.Model):
) )
} }
invoice()
class account_move_line(orm.Model): class account_move_line(orm.Model):
_inherit = "account.move.line" _inherit = "account.move.line"
@@ -620,6 +681,3 @@ class account_move_line(orm.Model):
cr, uid, ids, ['debit', 'credit'], context=context): cr, uid, ids, ['debit', 'credit'], context=context):
total += (line['debit'] or 0.0) - (line['credit'] or 0.0) total += (line['debit'] or 0.0) - (line['credit'] or 0.0)
return total return total
account_move_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -30,7 +30,6 @@ from openerp.tools.translate import _
from openerp.addons.decimal_precision import decimal_precision as dp from openerp.addons.decimal_precision import decimal_precision as dp
from openerp.addons.account_banking.parsers import models from openerp.addons.account_banking.parsers import models
from openerp.addons.account_banking.parsers import convert from openerp.addons.account_banking.parsers import convert
from openerp.addons.account_banking import sepa
from openerp.addons.account_banking.wizard import banktools from openerp.addons.account_banking.wizard import banktools
bt = models.mem_bank_transaction bt = models.mem_bank_transaction
@@ -48,8 +47,9 @@ class banking_import_transaction(orm.Model):
_description = 'Bank import transaction' _description = 'Bank import transaction'
_rec_name = 'transaction' _rec_name = 'transaction'
# This variable is used to match supplier invoices with an invoice date after # This variable is used to match supplier invoices with an invoice date
# the real payment date. This can occur with online transactions (web shops). # after the real payment date. This can occur with online transactions
# (web shops).
# TODO: Convert this to a proper configuration variable # TODO: Convert this to a proper configuration variable
payment_window = datetime.timedelta(days=10) payment_window = datetime.timedelta(days=10)
@@ -65,7 +65,9 @@ class banking_import_transaction(orm.Model):
amount = round(abs(trans.statement_line_id.amount), digits) amount = round(abs(trans.statement_line_id.amount), digits)
# Make sure to be able to pinpoint our costs invoice for later # Make sure to be able to pinpoint our costs invoice for later
# matching # matching
reference = '%s.%s: %s' % (trans.statement, trans.transaction, trans.reference) reference = '%s.%s: %s' % (trans.statement,
trans.transaction,
trans.reference)
# search supplier invoice # search supplier invoice
invoice_obj = self.pool.get('account.invoice') invoice_obj = self.pool.get('account.invoice')
@@ -85,28 +87,29 @@ class banking_import_transaction(orm.Model):
# create supplier invoice # create supplier invoice
partner_obj = self.pool.get('res.partner') partner_obj = self.pool.get('res.partner')
invoice_lines = [(0, 0, dict( invoice_lines = [(0, 0, dict(
amount = 1, amount=1,
price_unit = amount, price_unit=amount,
name = trans.message or trans.reference, name=trans.message or trans.reference,
account_id = account_info.costs_account_id.id account_id=account_info.costs_account_id.id
))] ))]
invoice_address_id = partner_obj.address_get( invoice_address_id = partner_obj.address_get(
cr, uid, [account_info.bank_partner_id.id], ['invoice'] cr, uid, [account_info.bank_partner_id.id], ['invoice']
) )
invoice_id = invoice_obj.create(cr, uid, dict( invoice_id = invoice_obj.create(cr, uid, dict(
type = 'in_invoice', type='in_invoice',
company_id = account_info.company_id.id, company_id=account_info.company_id.id,
partner_id = account_info.bank_partner_id.id, partner_id=account_info.bank_partner_id.id,
address_invoice_id = invoice_address_id['invoice'], address_invoice_id=invoice_address_id['invoice'],
period_id = period_id, period_id=period_id,
journal_id = account_info.invoice_journal_id.id, journal_id=account_info.invoice_journal_id.id,
account_id = account_info.bank_partner_id.property_account_payable.id, account_id=(
date_invoice = trans.execution_date, account_info.bank_partner_id.property_account_payable.id),
reference_type = 'none', date_invoice=trans.execution_date,
reference = reference, reference_type='none',
name = trans.reference or trans.message, reference=reference,
check_total = amount, name=trans.reference or trans.message,
invoice_line = invoice_lines, check_total=amount,
invoice_line=invoice_lines,
)) ))
invoice = invoice_obj.browse(cr, uid, invoice_id) invoice = invoice_obj.browse(cr, uid, invoice_id)
# Create workflow # Create workflow
@@ -129,8 +132,8 @@ class banking_import_transaction(orm.Model):
Use the sales journal to check. Use the sales journal to check.
Challenges we're facing: Challenges we're facing:
1. The sending or receiving party is not necessarily the same as the 1. The sending or receiving party is not necessarily the same as
partner the payment relates to. the partner the payment relates to.
2. References can be messed up during manual encoding and inexact 2. References can be messed up during manual encoding and inexact
matching can link the wrong invoices. matching can link the wrong invoices.
3. Amounts can or can not match the expected amount. 3. Amounts can or can not match the expected amount.
@@ -138,8 +141,8 @@ class banking_import_transaction(orm.Model):
.. There are countless more, but these we'll try to address. .. There are countless more, but these we'll try to address.
Assumptions for matching: Assumptions for matching:
1. There are no payments for invoices not sent. These are dealt with 1. There are no payments for invoices not sent. These are dealt
later on. with later on.
2. Debit amounts are either customer invoices or credited supplier 2. Debit amounts are either customer invoices or credited supplier
invoices. invoices.
3. Credit amounts are either supplier invoices or credited customer 3. Credit amounts are either supplier invoices or credited customer
@@ -152,8 +155,8 @@ class banking_import_transaction(orm.Model):
1. No match was made. 1. No match was made.
No harm done. Proceed with manual matching as usual. No harm done. Proceed with manual matching as usual.
2. The wrong match was made. 2. The wrong match was made.
Statements are encoded in draft. You will have the opportunity to Statements are encoded in draft. You will have the opportunity
manually correct the wrong assumptions. to manually correct the wrong assumptions.
TODO: REVISE THIS DOC TODO: REVISE THIS DOC
#Return values: #Return values:
@@ -170,8 +173,10 @@ class banking_import_transaction(orm.Model):
''' '''
Return the eyecatcher for an invoice Return the eyecatcher for an invoice
''' '''
return invoice.type.startswith('in_') and invoice.name or \ if invoice.type.startswith('in_'):
invoice.number return invoice.name or invoice.number
else:
return invoice.number
def has_id_match(invoice, ref, msg): def has_id_match(invoice, ref, msg):
''' '''
@@ -197,7 +202,8 @@ class banking_import_transaction(orm.Model):
iname = invoice.name.upper() iname = invoice.name.upper()
if iname in ref or iname in msg: if iname in ref or iname in msg:
return True return True
if invoice.supplier_invoice_number and len(invoice.supplier_invoice_number) > 2: if (invoice.supplier_invoice_number
and len(invoice.supplier_invoice_number) > 2):
supp_ref = invoice.supplier_invoice_number.upper() supp_ref = invoice.supplier_invoice_number.upper()
if supp_ref in ref or supp_ref in msg: if supp_ref in ref or supp_ref in msg:
return True return True
@@ -214,8 +220,8 @@ class banking_import_transaction(orm.Model):
# the interactive wizard # the interactive wizard
return False return False
#'''Check if the move_line has been cached''' # '''Check if the move_line has been cached'''
#return move_line.id in linked_invoices # return move_line.id in linked_invoices
def _cache(move_line, remaining=0.0): def _cache(move_line, remaining=0.0):
'''Cache the move_line''' '''Cache the move_line'''
@@ -228,7 +234,8 @@ class banking_import_transaction(orm.Model):
def _sign(invoice): def _sign(invoice):
'''Return the direction of an invoice''' '''Return the direction of an invoice'''
return {'in_invoice': -1, return {
'in_invoice': -1,
'in_refund': 1, 'in_refund': 1,
'out_invoice': 1, 'out_invoice': 1,
'out_refund': -1 'out_refund': -1
@@ -256,9 +263,9 @@ class banking_import_transaction(orm.Model):
# Next on reference/invoice number. Mind that this uses the invoice # Next on reference/invoice number. Mind that this uses the invoice
# itself, as the move_line references have been fiddled with on invoice # itself, as the move_line references have been fiddled with on invoice
# creation. This also enables us to search for the invoice number in the # creation. This also enables us to search for the invoice number in
# reference instead of the other way around, as most human interventions # the reference instead of the other way around, as most human
# *add* text. # interventions *add* text.
ref = trans.reference.upper() ref = trans.reference.upper()
msg = trans.message.upper() msg = trans.message.upper()
if len(candidates) > 1 or not candidates: if len(candidates) > 1 or not candidates:
@@ -297,7 +304,8 @@ class banking_import_transaction(orm.Model):
# amounts expected and received. # amounts expected and received.
# #
# TODO: currency coercing # TODO: currency coercing
best = [x for x in candidates best = [
x for x in candidates
if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) - if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) -
trans.statement_line_id.amount) trans.statement_line_id.amount)
and convert.str2date(x.date, '%Y-%m-%d') <= and convert.str2date(x.date, '%Y-%m-%d') <=
@@ -317,7 +325,8 @@ class banking_import_transaction(orm.Model):
elif len(candidates) > 1: elif len(candidates) > 1:
# Before giving up, check cache for catching duplicate # Before giving up, check cache for catching duplicate
# transfers first # transfers first
paid = [x for x in move_lines paid = [
x for x in move_lines
if x.invoice and has_id_match(x.invoice, ref, msg) if x.invoice and has_id_match(x.invoice, ref, msg)
and convert.str2date(x.invoice.date_invoice, '%Y-%m-%d') and convert.str2date(x.invoice.date_invoice, '%Y-%m-%d')
<= convert.str2date(trans.execution_date, '%Y-%m-%d') <= convert.str2date(trans.execution_date, '%Y-%m-%d')
@@ -328,10 +337,10 @@ class banking_import_transaction(orm.Model):
_('Unable to link transaction id %(trans)s ' _('Unable to link transaction id %(trans)s '
'(ref: %(ref)s) to invoice: ' '(ref: %(ref)s) to invoice: '
'invoice %(invoice)s was already paid') % { 'invoice %(invoice)s was already paid') % {
'trans': '%s.%s' % (trans.statement, trans.transaction), 'trans': '%s.%s' % (trans.statement,
trans.transaction),
'ref': trans.reference, 'ref': trans.reference,
'invoice': eyecatcher(paid[0].invoice) 'invoice': eyecatcher(paid[0].invoice)})
})
else: else:
# Multiple matches # Multiple matches
# TODO select best bank account in this case # TODO select best bank account in this case
@@ -356,8 +365,8 @@ class banking_import_transaction(orm.Model):
# Last partial payment will not flag invoice paid without # Last partial payment will not flag invoice paid without
# manual assistence # manual assistence
# Stefan: disabled this here for the interactive method # Stefan: disabled this here for the interactive method
# Handled this with proper handling of partial reconciliation # Handled this with proper handling of partial
# and the workflow service # reconciliation and the workflow service
# invoice_obj = self.pool.get('account.invoice') # invoice_obj = self.pool.get('account.invoice')
# invoice_obj.write(cr, uid, [invoice.id], { # invoice_obj.write(cr, uid, [invoice.id], {
# 'state': 'paid' # 'state': 'paid'
@@ -396,7 +405,8 @@ class banking_import_transaction(orm.Model):
_("Cannot link transaction %s with invoice") % _("Cannot link transaction %s with invoice") %
transaction.statement_line_id.name, transaction.statement_line_id.name,
(transaction.invoice_ids and (transaction.invoice_ids and
(_("Please select one of the matches in transaction %s.%s") or (_("Please select one of the matches in transaction "
"%s.%s") or
_("No match found for transaction %s.%s")) % ( _("No match found for transaction %s.%s")) % (
transaction.statement_line_id.statement_id.name, transaction.statement_line_id.statement_id.name,
transaction.statement_line_id.name transaction.statement_line_id.name
@@ -406,7 +416,8 @@ class banking_import_transaction(orm.Model):
_("Cannot link transaction %s with accounting entry") % _("Cannot link transaction %s with accounting entry") %
transaction.statement_line_id.name, transaction.statement_line_id.name,
(transaction.move_line_ids and (transaction.move_line_ids and
(_("Please select one of the matches in transaction %s.%s") or (_("Please select one of the matches in transaction "
"%s.%s") or
_("No match found for transaction %s.%s")) % ( _("No match found for transaction %s.%s")) % (
transaction.statement_line_id.statement_id.name, transaction.statement_line_id.statement_id.name,
transaction.statement_line_id.name transaction.statement_line_id.name
@@ -458,9 +469,10 @@ class banking_import_transaction(orm.Model):
# Define the voucher # Define the voucher
voucher = { voucher = {
'journal_id': st_line.statement_id.journal_id.id, 'journal_id': st_line.statement_id.journal_id.id,
'partner_id': st_line.partner_id and st_line.partner_id.id or False, 'partner_id': (
st_line.partner_id and st_line.partner_id.id or False),
'company_id': st_line.company_id.id, 'company_id': st_line.company_id.id,
'type':voucher_type, 'type': voucher_type,
'account_id': account_id, 'account_id': account_id,
'amount': abs(st_line.amount), 'amount': abs(st_line.amount),
'writeoff_amount': writeoff, 'writeoff_amount': writeoff,
@@ -470,12 +482,12 @@ class banking_import_transaction(orm.Model):
'date': st_line.date, 'date': st_line.date,
'date_due': st_line.date, 'date_due': st_line.date,
'period_id': period_id, 'period_id': period_id,
'payment_rate_currency_id':to_curr_id, 'payment_rate_currency_id': to_curr_id,
} }
# Define the voucher line # Define the voucher line
vch_line = { vch_line = {
#'voucher_id': v_id, # 'voucher_id': v_id,
'move_line_id': transaction.move_line_id.id, 'move_line_id': transaction.move_line_id.id,
'reconcile': True, 'reconcile': True,
'amount': line_amount, 'amount': line_amount,
@@ -490,7 +502,8 @@ class banking_import_transaction(orm.Model):
{'voucher_id': voucher_id}, context=context) {'voucher_id': voucher_id}, context=context)
transaction.refresh() transaction.refresh()
def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None): def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency,
context=None):
""" """
Legacy method. Allow for canceling bank statement lines that Legacy method. Allow for canceling bank statement lines that
were confirmed using earlier versions of the interactive wizard branch. were confirmed using earlier versions of the interactive wizard branch.
@@ -508,9 +521,14 @@ class banking_import_transaction(orm.Model):
reconcile_obj = self.pool.get('account.move.reconcile') reconcile_obj = self.pool.get('account.move.reconcile')
is_zero = lambda amount: self.pool.get('res.currency').is_zero( is_zero = lambda amount: self.pool.get('res.currency').is_zero(
cr, uid, currency, amount) cr, uid, currency, amount)
move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context) move_lines = move_line_obj.browse(cr, uid, move_line_ids,
reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id context=context)
line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids] reconcile = (move_lines[0].reconcile_id
or move_lines[0].reconcile_partial_id)
line_ids = [
x.id
for x in reconcile.line_id or reconcile.line_partial_ids
]
for move_line_id in move_line_ids: for move_line_id in move_line_ids:
line_ids.remove(move_line_id) line_ids.remove(move_line_id)
if len(line_ids) > 1: if len(line_ids) > 1:
@@ -522,7 +540,7 @@ class banking_import_transaction(orm.Model):
line_ids = [] line_ids = []
reconcile_obj.write( reconcile_obj.write(
cr, uid, reconcile.id, cr, uid, reconcile.id,
{ 'line_partial_ids': [(6, 0, line_partial_ids)], {'line_partial_ids': [(6, 0, line_partial_ids)],
'line_id': [(6, 0, line_ids)], 'line_id': [(6, 0, line_ids)],
}, context=context) }, context=context)
else: else:
@@ -531,7 +549,9 @@ class banking_import_transaction(orm.Model):
if move_line.invoice: if move_line.invoice:
# reopening the invoice # reopening the invoice
netsvc.LocalService('workflow').trg_validate( netsvc.LocalService('workflow').trg_validate(
uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr) uid, 'account.invoice', move_line.invoice.id, 'undo_paid',
cr
)
return True return True
def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None): def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None):
@@ -550,8 +570,7 @@ class banking_import_transaction(orm.Model):
context=context) context=context)
return True return True
def _legacy_cancel_move( def _legacy_cancel_move(self, cr, uid, transaction, context=None):
self, cr, uid, transaction, context=None):
""" """
Legacy method to support upgrades from older installations Legacy method to support upgrades from older installations
of the interactive wizard branch. of the interactive wizard branch.
@@ -590,16 +609,15 @@ class banking_import_transaction(orm.Model):
cr, uid, transaction.statement_line_id.id, cr, uid, transaction.statement_line_id.id,
{'reconcile_id': False}, context=context) {'reconcile_id': False}, context=context)
def _cancel_voucher( def _cancel_voucher(self, cr, uid, transaction_id, context=None):
self, cr, uid, transaction_id, context=None):
voucher_pool = self.pool.get('account.voucher') voucher_pool = self.pool.get('account.voucher')
transaction = self.browse(cr, uid, transaction_id, context=context) transaction = self.browse(cr, uid, transaction_id, context=context)
st_line = transaction.statement_line_id st_line = transaction.statement_line_id
if transaction.match_type: if transaction.match_type:
if st_line.voucher_id: if st_line.voucher_id:
# Although vouchers can be associated with statement lines # Although vouchers can be associated with statement lines
# in standard OpenERP, we consider ourselves owner of the voucher # in standard OpenERP, we consider ourselves owner of the
# if the line has an associated transaction # voucher if the line has an associated transaction
# Upon canceling of the statement line/transaction, # Upon canceling of the statement line/transaction,
# we cancel and delete the vouchers. # we cancel and delete the vouchers.
# Otherwise, the statement line will leave the voucher # Otherwise, the statement line will leave the voucher
@@ -610,7 +628,8 @@ class banking_import_transaction(orm.Model):
cr, uid, [st_line.voucher_id.id], context=context) cr, uid, [st_line.voucher_id.id], context=context)
voucher_pool.unlink( voucher_pool.unlink(
cr, uid, [st_line.voucher_id.id], context=context) cr, uid, [st_line.voucher_id.id], context=context)
if transaction.move_line_id and transaction.move_line_id.invoice: if (transaction.move_line_id
and transaction.move_line_id.invoice):
# reopening the invoice # reopening the invoice
netsvc.LocalService('workflow').trg_validate( netsvc.LocalService('workflow').trg_validate(
uid, 'account.invoice', uid, 'account.invoice',
@@ -639,7 +658,9 @@ class banking_import_transaction(orm.Model):
_("No method found to cancel this type")) _("No method found to cancel this type"))
self.cancel_map[transaction.match_type]( self.cancel_map[transaction.match_type](
self, cr, uid, transaction.id, context) self, cr, uid, transaction.id, context)
self._legacy_clear_up_writeoff(cr, uid, transaction, context=context) self._legacy_clear_up_writeoff(
cr, uid, transaction, context=context
)
return True return True
confirm_map = { confirm_map = {
@@ -665,7 +686,7 @@ class banking_import_transaction(orm.Model):
if transaction.match_type not in ('invoice', 'move', 'manual'): if transaction.match_type not in ('invoice', 'move', 'manual'):
raise orm.except_orm( raise orm.except_orm(
_("Cannot reconcile"), _("Cannot reconcile"),
_("Bank transaction %s: write off not implemented for " + _("Bank transaction %s: write off not implemented for "
"this match type.") % "this match type.") %
transaction.statement_line_id.name transaction.statement_line_id.name
) )
@@ -723,7 +744,7 @@ class banking_import_transaction(orm.Model):
pass pass
def _get_move_info(self, cr, uid, move_line_ids, partner_bank_id=False, def _get_move_info(self, cr, uid, move_line_ids, partner_bank_id=False,
partial=False, match_type = False): partial=False, match_type=False, context=None):
type_map = { type_map = {
'out_invoice': 'customer', 'out_invoice': 'customer',
'in_invoice': 'supplier', 'in_invoice': 'supplier',
@@ -738,7 +759,9 @@ class banking_import_transaction(orm.Model):
'match_type': match_type, 'match_type': match_type,
'account_id': False, 'account_id': False,
} }
move_lines = self.pool.get('account.move.line').browse(cr, uid, move_line_ids) move_lines = self.pool.get('account.move.line').browse(
cr, uid, move_line_ids, context=context
)
for move_line in move_lines: for move_line in move_lines:
if move_line.partner_id: if move_line.partner_id:
if retval['partner_id']: if retval['partner_id']:
@@ -780,7 +803,7 @@ class banking_import_transaction(orm.Model):
if move_lines and len(move_lines) == 1: if move_lines and len(move_lines) == 1:
retval['reference'] = move_lines[0].ref retval['reference'] = move_lines[0].ref
if retval['match_type'] == 'invoice': if retval['match_type'] == 'invoice':
retval['invoice_ids'] = list(set([x.invoice.id for x in move_lines])) retval['invoice_ids'] = list(set(x.invoice.id for x in move_lines))
retval['type'] = type_map[move_lines[0].invoice.type] retval['type'] = type_map[move_lines[0].invoice.type]
return retval return retval
@@ -791,13 +814,11 @@ class banking_import_transaction(orm.Model):
vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])] vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])]
vals['move_line_id'] = (move_info.get('move_line_ids', False) and vals['move_line_id'] = (move_info.get('move_line_ids', False) and
len(move_info['move_line_ids']) == 1 and len(move_info['move_line_ids']) == 1 and
move_info['move_line_ids'][0] move_info['move_line_ids'][0])
)
if move_info['match_type'] == 'invoice': if move_info['match_type'] == 'invoice':
vals['invoice_id'] = (move_info.get('invoice_ids', False) and vals['invoice_id'] = (move_info.get('invoice_ids', False) and
len(move_info['invoice_ids']) == 1 and len(move_info['invoice_ids']) == 1 and
move_info['invoice_ids'][0] move_info['invoice_ids'][0])
)
return vals return vals
def hook_match_payment(self, cr, uid, transaction, log, context=None): def hook_match_payment(self, cr, uid, transaction, log, context=None):
@@ -824,12 +845,12 @@ class banking_import_transaction(orm.Model):
# Results # Results
if results is None: if results is None:
results = dict( results = dict(
trans_loaded_cnt = 0, trans_loaded_cnt=0,
trans_skipped_cnt = 0, trans_skipped_cnt=0,
trans_matched_cnt = 0, trans_matched_cnt=0,
bank_costs_invoice_cnt = 0, bank_costs_invoice_cnt=0,
error_cnt = 0, error_cnt=0,
log = [], log=[],
) )
# Caching # Caching
@@ -849,7 +870,8 @@ class banking_import_transaction(orm.Model):
payment_line_ids = payment_line_obj.search( payment_line_ids = payment_line_obj.search(
cr, uid, [ cr, uid, [
('order_id.state', '=', 'sent'), ('order_id.state', '=', 'sent'),
('date_done', '=', False)], context=context) ('date_done', '=', False)
], context=context)
payment_lines = payment_line_obj.browse( payment_lines = payment_line_obj.browse(
cr, uid, payment_line_ids) cr, uid, payment_line_ids)
@@ -885,25 +907,30 @@ class banking_import_transaction(orm.Model):
# Get interesting journals once # Get interesting journals once
# Added type 'general' to capture fund transfers # Added type 'general' to capture fund transfers
journal_ids = journal_obj.search(cr, uid, [ journal_ids = journal_obj.search(
('type', 'in', ('general', 'sale','purchase', cr, uid, [
'purchase_refund','sale_refund')), ('type', 'in', ('general', 'sale', 'purchase',
'purchase_refund', 'sale_refund')),
('company_id', '=', company.id), ('company_id', '=', company.id),
]) ],
)
# Get all unreconciled moves # Get all unreconciled moves
move_line_ids = move_line_obj.search(cr, uid, [ move_line_ids = move_line_obj.search(
cr, uid, [
('reconcile_id', '=', False), ('reconcile_id', '=', False),
('journal_id', 'in', journal_ids), ('journal_id', 'in', journal_ids),
('account_id.reconcile', '=', True), ('account_id.reconcile', '=', True),
('date', '<=', transaction.execution_date), ('date', '<=', transaction.execution_date),
]) ],
)
if move_line_ids: if move_line_ids:
move_lines = move_line_obj.browse(cr, uid, move_line_ids) move_lines = move_line_obj.browse(cr, uid, move_line_ids)
else: else:
move_lines = [] move_lines = []
# Create fallback currency code # Create fallback currency code
currency_code = transaction.local_currency or company.currency_id.name currency_code = (transaction.local_currency
or company.currency_id.name)
# Check cache for account info/currency # Check cache for account info/currency
if transaction.local_account in info and \ if transaction.local_account in info and \
@@ -917,7 +944,8 @@ class banking_import_transaction(orm.Model):
) )
if not account_info: if not account_info:
results['log'].append( results['log'].append(
_('Transaction found for unknown account %(bank_account)s') % _('Transaction found for unknown account '
'%(bank_account)s') %
{'bank_account': transaction.local_account} {'bank_account': transaction.local_account}
) )
error_accounts[transaction.local_account] = True error_accounts[transaction.local_account] = True
@@ -941,12 +969,14 @@ class banking_import_transaction(orm.Model):
currency_code = account_info.currency_id.name currency_code = account_info.currency_id.name
# Cache results # Cache results
if not transaction.local_account in info: if transaction.local_account not in info:
info[transaction.local_account] = { info[transaction.local_account] = {
currency_code: account_info currency_code: account_info
} }
else: else:
info[transaction.local_account][currency_code] = account_info info[transaction.local_account][currency_code] = (
account_info
)
# Link accounting period # Link accounting period
period_id = banktools.get_period( period_id = banktools.get_period(
@@ -965,7 +995,8 @@ class banking_import_transaction(orm.Model):
_("Cannot perform match on a confirmed transction")) _("Cannot perform match on a confirmed transction"))
else: else:
values = { values = {
'name': '%s.%s' % (transaction.statement, transaction.transaction), 'name': '%s.%s' % (transaction.statement,
transaction.transaction),
'date': transaction.execution_date, 'date': transaction.execution_date,
'amount': transaction.transferred_amount, 'amount': transaction.transferred_amount,
'statement_id': transaction.statement_id.id, 'statement_id': transaction.statement_id.id,
@@ -979,7 +1010,9 @@ class banking_import_transaction(orm.Model):
account_info.default_credit_account_id.id or account_info.default_credit_account_id.id or
account_info.default_debit_account_id.id), account_info.default_debit_account_id.id),
} }
statement_line_id = statement_line_obj.create(cr, uid, values, context) statement_line_id = statement_line_obj.create(
cr, uid, values, context
)
results['trans_loaded_cnt'] += 1 results['trans_loaded_cnt'] += 1
transaction.write({'statement_line_id': statement_line_id}) transaction.write({'statement_line_id': statement_line_id})
transaction.refresh() transaction.refresh()
@@ -991,8 +1024,9 @@ class banking_import_transaction(orm.Model):
and account_info.currency_id.name != transaction.local_currency: and account_info.currency_id.name != transaction.local_currency:
# TODO: convert currencies? # TODO: convert currencies?
results['log'].append( results['log'].append(
_('transaction %(statement_id)s.%(transaction_id)s for account %(bank_account)s' _('transaction %(statement_id)s.%(transaction_id)s for '
' uses different currency than the defined bank journal.' 'account %(bank_account)s uses different currency than '
'the defined bank journal.'
) % { ) % {
'bank_account': transactions.local_account, 'bank_account': transactions.local_account,
'statement_id': transaction.statement, 'statement_id': transaction.statement,
@@ -1006,17 +1040,18 @@ class banking_import_transaction(orm.Model):
continue continue
# When bank costs are part of transaction itself, split it. # When bank costs are part of transaction itself, split it.
if transaction.type != bt.BANK_COSTS and transaction.provision_costs: if (transaction.type != bt.BANK_COSTS
and transaction.provision_costs):
# Create new transaction for bank costs # Create new transaction for bank costs
cost_id = self.copy( cost_id = self.copy(
cr, uid, transaction.id, cr, uid, transaction.id,
dict( dict(
type = bt.BANK_COSTS, type=bt.BANK_COSTS,
transaction = '%s-prov' % transaction.transaction, transaction='%s-prov' % transaction.transaction,
transferred_amount = transaction.provision_costs, transferred_amount=transaction.provision_costs,
remote_currency = transaction.provision_costs_currency, remote_currency=transaction.provision_costs_currency,
message = transaction.provision_costs_description, message=transaction.provision_costs_description,
parent_id = transaction.id, parent_id=transaction.id,
), context) ), context)
injected.append(self.browse(cr, uid, cost_id, context)) injected.append(self.browse(cr, uid, cost_id, context))
@@ -1028,14 +1063,17 @@ class banking_import_transaction(orm.Model):
self.write( self.write(
cr, uid, transaction.id, cr, uid, transaction.id,
dict( dict(
transferred_amount = transferred_amount=(
transaction.transferred_amount - transaction.provision_costs, transaction.transferred_amount -
provision_costs = False, transaction.provision_costs),
provision_costs_currency = False, provision_costs=False,
provision_costs_description = False, provision_costs_currency=False,
provision_costs_description=False,
), context=context) ), context=context)
# rebrowse the current record after writing # rebrowse the current record after writing
transaction = self.browse(cr, uid, transaction.id, context=context) transaction = self.browse(
cr, uid, transaction.id, context=context
)
# Match payment and direct debit orders # Match payment and direct debit orders
move_info_payment = self.hook_match_payment( move_info_payment = self.hook_match_payment(
@@ -1088,7 +1126,8 @@ class banking_import_transaction(orm.Model):
# Credit means payment... isn't it? # Credit means payment... isn't it?
if (not move_info if (not move_info
and transaction.statement_line_id.amount < 0 and payment_lines): and transaction.statement_line_id.amount < 0
and payment_lines):
# Link open payment - if any # Link open payment - if any
# Note that _match_payment is defined in the # Note that _match_payment is defined in the
# account_banking_payment module which should be installed # account_banking_payment module which should be installed
@@ -1146,10 +1185,13 @@ class banking_import_transaction(orm.Model):
values['type'] = move_info['type'] values['type'] = move_info['type']
else: else:
values['partner_id'] = values['partner_bank_id'] = False values['partner_id'] = values['partner_bank_id'] = False
if not values['partner_id'] and partner_ids and len(partner_ids) == 1: if (not values['partner_id']
and partner_ids
and len(partner_ids) == 1):
values['partner_id'] = partner_ids[0] values['partner_id'] = partner_ids[0]
if (not values['partner_bank_id'] and partner_banks and if (not values['partner_bank_id']
len(partner_banks) == 1): and partner_banks
and len(partner_banks) == 1):
values['partner_bank_id'] = partner_banks[0].id values['partner_bank_id'] = partner_banks[0].id
statement_line_obj.write( statement_line_obj.write(
@@ -1158,7 +1200,7 @@ class banking_import_transaction(orm.Model):
if not injected: if not injected:
i += 1 i += 1
#recompute statement end_balance for validation # recompute statement end_balance for validation
if imported_statement_ids: if imported_statement_ids:
statement_obj.button_dummy( statement_obj.button_dummy(
cr, uid, imported_statement_ids, context=context) cr, uid, imported_statement_ids, context=context)
@@ -1214,22 +1256,32 @@ class banking_import_transaction(orm.Model):
Write values in argument 'vals', but clear all match Write values in argument 'vals', but clear all match
related values first related values first
""" """
write_vals = (dict([(x, False) for x in [ write_vals = (
dict([
(x, False)
for x in [
'match_type', 'match_type',
'move_line_id', 'move_line_id',
'invoice_id', 'invoice_id',
]] + ]
[(x, [(6, 0, [])]) for x in [ ] + [
(x, [(6, 0, [])])
for x in [
'move_line_ids', 'move_line_ids',
'invoice_ids', 'invoice_ids',
]])) ]
]
)
)
write_vals.update(vals or {}) write_vals.update(vals or {})
return self.write(cr, uid, ids, write_vals, context=context) return self.write(cr, uid, ids, write_vals, context=context)
def _get_move_amount(self, cr, uid, ids, name, args, context=None): def _get_move_amount(self, cr, uid, ids, name, args, context=None):
""" """
Need to get the residual amount on the move (invoice) in the bank statement currency. Need to get the residual amount on the move (invoice) in the bank
This will be used to calculate the write-off amount (in statement currency). statement currency.
This will be used to calculate the write-off amount
(in statement currency).
""" """
if not ids: if not ids:
return {} return {}
@@ -1240,20 +1292,25 @@ class banking_import_transaction(orm.Model):
for transaction in self.browse(cr, uid, ids, context): for transaction in self.browse(cr, uid, ids, context):
if transaction.move_line_id: if transaction.move_line_id:
move_line_amount = transaction.move_line_id.amount_residual_currency move_line_amount = (
transaction.move_line_id.amount_residual_currency)
statement = transaction.statement_line_id.statement_id
to_curr_id = ( to_curr_id = (
transaction.statement_line_id.statement_id.journal_id.currency statement.journal_id.currency
and transaction.statement_line_id.statement_id.journal_id.currency.id and statement.journal_id.currency.id
or transaction.statement_line_id.statement_id.company_id.currency_id.id or statement.company_id.currency_id.id
) )
from_curr_id = ( from_curr_id = (
transaction.move_line_id.currency_id transaction.move_line_id.currency_id
and transaction.move_line_id.currency_id.id and transaction.move_line_id.currency_id.id
or transaction.statement_line_id.statement_id.company_id.currency_id.id or statement.company_id.currency_id.id
) )
if from_curr_id != to_curr_id: if from_curr_id != to_curr_id:
amount_currency = stline_pool._convert_currency(cr, uid, from_curr_id, to_curr_id, move_line_amount, round=True, amount_currency = stline_pool._convert_currency(
date=transaction.statement_line_id.date, context=context) cr, uid, from_curr_id, to_curr_id, move_line_amount,
round=True, date=transaction.statement_line_id.date,
context=context
)
else: else:
amount_currency = move_line_amount amount_currency = move_line_amount
sign = 1 sign = 1
@@ -1261,7 +1318,8 @@ class banking_import_transaction(orm.Model):
if transaction.move_line_id.amount_currency < 0: if transaction.move_line_id.amount_currency < 0:
sign = -1 sign = -1
else: else:
if (transaction.move_line_id.debit - transaction.move_line_id.credit) < 0: if (transaction.move_line_id.debit
- transaction.move_line_id.credit) < 0:
sign = -1 sign = -1
res[transaction.id] = sign * amount_currency res[transaction.id] = sign * amount_currency
@@ -1274,10 +1332,12 @@ class banking_import_transaction(orm.Model):
for this in self.browse(cr, uid, ids, context): for this in self.browse(cr, uid, ids, context):
if this.parent_id: if this.parent_id:
this.parent_id.write( this.parent_id.write(
{'transferred_amount': {
this.parent_id.transferred_amount + \ 'transferred_amount':
this.parent_id.transferred_amount +
this.transferred_amount, this.transferred_amount,
}) }
)
this.parent_id.refresh() this.parent_id.refresh()
return super(banking_import_transaction, self).unlink( return super(banking_import_transaction, self).unlink(
cr, uid, ids, context=context) cr, uid, ids, context=context)
@@ -1307,8 +1367,14 @@ class banking_import_transaction(orm.Model):
'remote_owner': fields.char('remote_owner', size=128), 'remote_owner': fields.char('remote_owner', size=128),
'remote_owner_address': fields.char('remote_owner_address', size=256), 'remote_owner_address': fields.char('remote_owner_address', size=256),
'remote_owner_city': fields.char('remote_owner_city', size=128), 'remote_owner_city': fields.char('remote_owner_city', size=128),
'remote_owner_postalcode': fields.char('remote_owner_postalcode', size=24), 'remote_owner_postalcode': fields.char(
'remote_owner_country_code': fields.char('remote_owner_country_code', size=24), 'remote_owner_postalcode',
size=24,
),
'remote_owner_country_code': fields.char(
'remote_owner_country_code',
size=24,
),
'remote_owner_custno': fields.char('remote_owner_custno', size=24), 'remote_owner_custno': fields.char('remote_owner_custno', size=24),
'remote_bank_bic': fields.char('remote_bank_bic', size=24), 'remote_bank_bic': fields.char('remote_bank_bic', size=24),
'remote_bank_bei': fields.char('remote_bank_bei', size=24), 'remote_bank_bei': fields.char('remote_bank_bei', size=24),
@@ -1318,8 +1384,14 @@ class banking_import_transaction(orm.Model):
'remote_bank_duns': fields.char('remote_bank_duns', size=24), 'remote_bank_duns': fields.char('remote_bank_duns', size=24),
'remote_bank_tax_id': fields.char('remote_bank_tax_id', size=24), 'remote_bank_tax_id': fields.char('remote_bank_tax_id', size=24),
'provision_costs': fields.float('provision_costs', size=24), 'provision_costs': fields.float('provision_costs', size=24),
'provision_costs_currency': fields.char('provision_costs_currency', size=64), 'provision_costs_currency': fields.char(
'provision_costs_description': fields.char('provision_costs_description', size=24), 'provision_costs_currency',
size=64,
),
'provision_costs_description': fields.char(
'provision_costs_description',
size=24,
),
'error_message': fields.char('error_message', size=1024), 'error_message': fields.char('error_message', size=1024),
'storno_retry': fields.boolean('storno_retry'), 'storno_retry': fields.boolean('storno_retry'),
# end of mem_bank_transaction_fields # end of mem_bank_transaction_fields
@@ -1341,7 +1413,7 @@ class banking_import_transaction(orm.Model):
'banking.import.transaction', 'Split off from this transaction'), 'banking.import.transaction', 'Split off from this transaction'),
# match fields # match fields
'match_type': fields.selection([ 'match_type': fields.selection([
('move','Move'), ('move', 'Move'),
('invoice', 'Invoice'), ('invoice', 'Invoice'),
('payment', 'Payment line'), ('payment', 'Payment line'),
('payment_order', 'Payment order'), ('payment_order', 'Payment order'),
@@ -1366,13 +1438,16 @@ class banking_import_transaction(orm.Model):
'residual': fields.function( 'residual': fields.function(
_get_residual, method=True, string='Residual', type='float'), _get_residual, method=True, string='Residual', type='float'),
'writeoff_account_id': fields.many2one( 'writeoff_account_id': fields.many2one(
'account.account', 'Write-off account', 'account.account',
domain=[('type', '!=', 'view')]), 'Write-off account',
'payment_option':fields.selection( domain=[('type', '!=', 'view')]
),
'payment_option': fields.selection(
[ [
('without_writeoff', 'Keep Open'), ('without_writeoff', 'Keep Open'),
('with_writeoff', 'Reconcile Payment Balance') ('with_writeoff', 'Reconcile Payment Balance')
], 'Payment Difference', ],
'Payment Difference',
required=True, required=True,
help=("This field helps you to choose what you want to do with " help=("This field helps you to choose what you want to do with "
"the eventual difference between the paid amount and the " "the eventual difference between the paid amount and the "
@@ -1387,18 +1462,20 @@ class banking_import_transaction(orm.Model):
'writeoff_analytic_id': fields.many2one( 'writeoff_analytic_id': fields.many2one(
'account.analytic.account', 'Write off analytic account'), 'account.analytic.account', 'Write off analytic account'),
'move_currency_amount': fields.function( 'move_currency_amount': fields.function(
_get_move_amount, method=True, string='Match Amount', type='float'), _get_move_amount,
method=True,
string='Match Amount',
type='float',
),
} }
_defaults = { _defaults = {
'company_id': lambda s,cr,uid,c: 'company_id': lambda s, cr, uid, c:
s.pool.get('res.company')._company_default_get( s.pool.get('res.company')._company_default_get(
cr, uid, 'bank.import.transaction', context=c), cr, uid, 'bank.import.transaction', context=c),
'payment_option': 'without_writeoff', 'payment_option': 'without_writeoff',
} }
banking_import_transaction()
class account_bank_statement_line(orm.Model): class account_bank_statement_line(orm.Model):
_inherit = 'account.bank.statement.line' _inherit = 'account.bank.statement.line'
@@ -1436,7 +1513,7 @@ class account_bank_statement_line(orm.Model):
'match_type': fields.related( 'match_type': fields.related(
'import_transaction_id', 'match_type', type='selection', 'import_transaction_id', 'match_type', type='selection',
selection=[ selection=[
('move','Move'), ('move', 'Move'),
('invoice', 'Invoice'), ('invoice', 'Invoice'),
('payment', 'Payment line'), ('payment', 'Payment line'),
('payment_order', 'Payment order'), ('payment_order', 'Payment order'),
@@ -1449,8 +1526,10 @@ class account_bank_statement_line(orm.Model):
'state': fields.selection( 'state': fields.selection(
[('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
readonly=True, required=True), readonly=True, required=True),
'parent_id': fields.many2one('account.bank.statement.line', 'parent_id': fields.many2one(
'Parent'), 'account.bank.statement.line',
'Parent',
),
'link_partner_ok': fields.function( 'link_partner_ok': fields.function(
_get_link_partner_ok, type='boolean', _get_link_partner_ok, type='boolean',
string='Can link partner'), string='Can link partner'),
@@ -1471,7 +1550,9 @@ class account_bank_statement_line(orm.Model):
wizard_obj = self.pool.get('banking.transaction.wizard') wizard_obj = self.pool.get('banking.transaction.wizard')
res_id = wizard_obj.create( res_id = wizard_obj.create(
cr, uid, {'statement_line_id': ids[0]}, context=context) cr, uid, {'statement_line_id': ids[0]}, context=context)
res = wizard_obj.create_act_window(cr, uid, res_id, context=context) res = wizard_obj.create_act_window(
cr, uid, res_id, context=context
)
return res return res
def link_partner(self, cr, uid, ids, context=None): def link_partner(self, cr, uid, ids, context=None):
@@ -1499,8 +1580,8 @@ class account_bank_statement_line(orm.Model):
{'partner_id': statement_line.partner_bank_id.partner_id.id}) {'partner_id': statement_line.partner_bank_id.partner_id.id})
return True return True
if (not statement_line.import_transaction_id or if (not statement_line.import_transaction_id
not statement_line.import_transaction_id.remote_account): or not statement_line.import_transaction_id.remote_account):
raise orm.except_orm( raise orm.except_orm(
_("Error"), _("Error"),
_("No bank account available to link partner to")) _("No bank account available to link partner to"))
@@ -1555,8 +1636,9 @@ class account_bank_statement_line(orm.Model):
""" """
Create (or update) a voucher for each statement line, and then generate Create (or update) a voucher for each statement line, and then generate
the moves by posting the voucher. the moves by posting the voucher.
If a line does not have a move line against it, but has an account, then If a line does not have a move line against it, but has an account,
generate a journal entry that moves the line amount to the specified account. then generate a journal entry that moves the line amount to the
specified account.
""" """
statement_pool = self.pool.get('account.bank.statement') statement_pool = self.pool.get('account.bank.statement')
obj_seq = self.pool.get('ir.sequence') obj_seq = self.pool.get('ir.sequence')
@@ -1576,7 +1658,8 @@ class account_bank_statement_line(orm.Model):
raise orm.except_orm( raise orm.except_orm(
_('No Analytic Journal !'), _('No Analytic Journal !'),
_("You have to define an analytic journal on the '%s' " _("You have to define an analytic journal on the '%s' "
"journal!") % (st_line.statement_id.journal_id.name,)) "journal!") % st_line.statement_id.journal_id.name
)
if not st_line.amount: if not st_line.amount:
continue continue
if not st_line.period_id: if not st_line.period_id:
@@ -1594,10 +1677,16 @@ class account_bank_statement_line(orm.Model):
if st.journal_id.sequence_id: if st.journal_id.sequence_id:
period = st.period_id or st_line.period_id period = st.period_id or st_line.period_id
c = {'fiscalyear_id': period.fiscalyear_id.id} c = {'fiscalyear_id': period.fiscalyear_id.id}
st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c) st_number = obj_seq.next_by_id(
cr, uid, st.journal_id.sequence_id.id, context=c
)
else: else:
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement') st_number = obj_seq.next_by_code(
statement_pool.write(cr, uid, [st.id], {'name': st_number}, context=context) cr, uid, 'account.bank.statement'
)
statement_pool.write(
cr, uid, [st.id], {'name': st_number}, context=context
)
if st_line.import_transaction_id: if st_line.import_transaction_id:
import_transaction_obj.confirm( import_transaction_obj.confirm(
@@ -1607,7 +1696,9 @@ class account_bank_statement_line(orm.Model):
cr, uid, st_number, st_line, context) cr, uid, st_number, st_line, context)
company_currency_id = st.journal_id.company_id.currency_id.id company_currency_id = st.journal_id.company_id.currency_id.id
statement_pool.create_move_from_st_line( statement_pool.create_move_from_st_line(
cr, uid, st_line.id, company_currency_id, st_line_number, context) cr, uid, st_line.id, company_currency_id, st_line_number,
context
)
self.write( self.write(
cr, uid, st_line.id, {'state': 'confirmed'}, context) cr, uid, st_line.id, {'state': 'confirmed'}, context)
return True return True
@@ -1626,15 +1717,17 @@ class account_bank_statement_line(orm.Model):
if st_line.statement_id.state != 'draft': if st_line.statement_id.state != 'draft':
raise orm.except_orm( raise orm.except_orm(
_("Cannot cancel bank transaction"), _("Cannot cancel bank transaction"),
_("The bank statement that this transaction belongs to has " _("The bank statement that this transaction belongs to "
"already been confirmed")) "has already been confirmed"))
if st_line.import_transaction_id: if st_line.import_transaction_id:
# Cancel transaction immediately. # Cancel transaction immediately.
# If it has voucher, this will clean up # If it has voucher, this will clean up
# the moves on the st_line. # the moves on the st_line.
import_transaction_obj.cancel( import_transaction_obj.cancel(
cr, uid, [st_line.import_transaction_id.id], context=context) cr, uid, [st_line.import_transaction_id.id],
context=context
)
st_line.refresh() st_line.refresh()
for line in st_line.move_ids: for line in st_line.move_ids:
# We allow for people canceling and removing # We allow for people canceling and removing
@@ -1650,7 +1743,6 @@ class account_bank_statement_line(orm.Model):
cr, uid, set_draft_ids, {'state': 'draft'}, context=context) cr, uid, set_draft_ids, {'state': 'draft'}, context=context)
return True return True
def unlink(self, cr, uid, ids, context=None): def unlink(self, cr, uid, ids, context=None):
""" """
Don't allow deletion of a confirmed statement line Don't allow deletion of a confirmed statement line
@@ -1669,13 +1761,13 @@ class account_bank_statement_line(orm.Model):
line.parent_id.write( line.parent_id.write(
{ {
'amount': line.parent_id.amount + line.amount, 'amount': line.parent_id.amount + line.amount,
}) }
)
line.parent_id.refresh() line.parent_id.refresh()
return super(account_bank_statement_line, self).unlink( return super(account_bank_statement_line, self).unlink(
cr, uid, ids, context=context) cr, uid, ids, context=context)
def create_instant_transaction( def create_instant_transaction(self, cr, uid, ids, context=None):
self, cr, uid, ids, context=None):
""" """
Check for existance of import transaction on the Check for existance of import transaction on the
bank statement lines. Create instant items if appropriate. bank statement lines. Create instant items if appropriate.
@@ -1696,8 +1788,7 @@ class account_bank_statement_line(orm.Model):
context = {} context = {}
localcontext = context.copy() localcontext = context.copy()
localcontext['transaction_no_duplicate_search'] = True localcontext['transaction_no_duplicate_search'] = True
for line in self.browse( for line in self.browse(cr, uid, ids, context=context):
cr, uid, ids, context=context):
if line.state != 'confirmed' and not line.import_transaction_id: if line.state != 'confirmed' and not line.import_transaction_id:
res = import_transaction_pool.create( res = import_transaction_pool.create(
cr, uid, { cr, uid, {
@@ -1723,20 +1814,20 @@ class account_bank_statement_line(orm.Model):
child_statement_ids = [] child_statement_ids = []
for this in self.browse(cr, uid, ids, context): for this in self.browse(cr, uid, ids, context):
transaction_data = transaction_pool.copy_data( transaction_data = transaction_pool.copy_data(
cr, uid, this.import_transaction_id.id) cr, uid, this.import_transaction_id.id
)
transaction_data['transferred_amount'] = amount transaction_data['transferred_amount'] = amount
transaction_data['message'] = ( transaction_data['message'] = ((transaction_data['message'] or '')
(transaction_data['message'] or '') + _(' (split)')) + _(' (split)'))
transaction_data['parent_id'] = this.import_transaction_id.id transaction_data['parent_id'] = this.import_transaction_id.id
transaction_id = transaction_pool.create( transaction_id = transaction_pool.create(
cr, cr,
uid, uid,
transaction_data, transaction_data,
context=dict( context=dict(context, transaction_no_duplicate_search=True)
context, transaction_no_duplicate_search=True)) )
statement_line_data = self.copy_data( statement_line_data = self.copy_data(cr, uid, this.id)
cr, uid, this.id)
statement_line_data['amount'] = amount statement_line_data['amount'] = amount
statement_line_data['name'] = ( statement_line_data['name'] = (
(statement_line_data['name'] or '') + _(' (split)')) (statement_line_data['name'] or '') + _(' (split)'))
@@ -1785,35 +1876,43 @@ class account_bank_statement(orm.Model):
line_obj = self.pool.get('account.bank.statement.line') line_obj = self.pool.get('account.bank.statement.line')
for st in self.browse(cr, uid, ids, context=context): for st in self.browse(cr, uid, ids, context=context):
j_type = st.journal_id.type j_type = st.journal_id.type
if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): if not self.check_status_condition(
cr, uid, st.state, journal_type=j_type):
continue continue
self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) self.balance_check(cr, uid, st.id, journal_type=j_type,
context=context)
if (not st.journal_id.default_credit_account_id) \ if (not st.journal_id.default_credit_account_id) \
or (not st.journal_id.default_debit_account_id): or (not st.journal_id.default_debit_account_id):
raise orm.except_orm(_('Configuration Error !'), raise orm.except_orm(
_('Please verify that an account is defined in the journal.')) _('Configuration Error !'),
_('Please verify that an account is defined in the '
'journal.')
)
# protect against misguided manual changes # protect against misguided manual changes
for line in st.move_line_ids: for line in st.move_line_ids:
if line.state != 'valid': if line.state != 'valid':
raise orm.except_orm(_('Error !'), raise orm.except_orm(
_('The account entries lines are not in valid state.')) _('Error !'),
_('The account entries lines are not in valid state.')
)
line_obj.confirm(cr, uid, [line.id for line in st.line_ids], context) line_obj.confirm(cr, uid, [line.id for line in st.line_ids],
context)
st.refresh() st.refresh()
self.message_post( self.message_post(
cr, uid, [st.id], cr, uid, [st.id],
body=_('Statement %s confirmed, journal items were created.') body=_('Statement %s confirmed, journal items were created.')
% (st.name,), context=context) % (st.name,), context=context)
return self.write(cr, uid, ids, {'state':'confirm'}, context=context) return self.write(cr, uid, ids, {'state': 'confirm'}, context=context)
def button_cancel(self, cr, uid, ids, context=None): def button_cancel(self, cr, uid, ids, context=None):
""" """
Do nothing but write the state. Delegate all actions to the statement Do nothing but write the state. Delegate all actions to the statement
line workflow instead. line workflow instead.
""" """
self.write(cr, uid, ids, {'state':'draft'}, context=context) self.write(cr, uid, ids, {'state': 'draft'}, context=context)
def unlink(self, cr, uid, ids, context=None): def unlink(self, cr, uid, ids, context=None):
""" """
@@ -1841,5 +1940,3 @@ class account_bank_statement(orm.Model):
'balance_end': fields.function( 'balance_end': fields.function(
_end_balance, method=True, store=True, string='Balance'), _end_balance, method=True, store=True, string='Balance'),
} }
account_bank_statement()

View File

@@ -4,8 +4,8 @@
# Copyright (C) 2011 Therp BV (<http://therp.nl>) # Copyright (C) 2011 Therp BV (<http://therp.nl>)
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -24,8 +24,9 @@ __name__ = ("account.bank.statement.line:: set new field 'state' to "
"confirmed for all statement lines belonging to confirmed " "confirmed for all statement lines belonging to confirmed "
"statements") "statements")
def migrate(cr, version): def migrate(cr, version):
cr.execute ("UPDATE account_bank_statement_line as sl " cr.execute("UPDATE account_bank_statement_line as sl "
" SET state = 'confirmed'" " SET state = 'confirmed'"
" FROM account_bank_statement as s " " FROM account_bank_statement as s "
" WHERE sl.statement_id = s.id " " WHERE sl.statement_id = s.id "

View File

@@ -19,6 +19,7 @@
# #
############################################################################## ##############################################################################
def migrate(cr, version): def migrate(cr, version):
if not version: if not version:
return return

View File

@@ -19,6 +19,7 @@
# #
############################################################################## ##############################################################################
def migrate(cr, version): def migrate(cr, version):
if not version: if not version:
return return

View File

@@ -19,6 +19,7 @@
# #
############################################################################## ##############################################################################
def table_exists(cr, table): def table_exists(cr, table):
""" Check whether a certain table or view exists """ """ Check whether a certain table or view exists """
cr.execute( cr.execute(
@@ -26,6 +27,7 @@ def table_exists(cr, table):
(table,)) (table,))
return cr.fetchone()[0] == 1 return cr.fetchone()[0] == 1
def migrate(cr, version): def migrate(cr, version):
""" """
Migration script for semantic changes in account_banking_payment_export. Migration script for semantic changes in account_banking_payment_export.

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -19,6 +19,6 @@
# #
############################################################################## ##############################################################################
import models from . import models
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -29,14 +29,17 @@ try:
except AttributeError: except AttributeError:
from mx import DateTime as datetime from mx import DateTime as datetime
def str2date(datestr, format='%d/%m/%y'): def str2date(datestr, format='%d/%m/%y'):
'''Convert a string to a datatime object''' '''Convert a string to a datatime object'''
return datetime.strptime(datestr, format) return datetime.strptime(datestr, format)
def date2str(date, format='%Y-%m-%d'): def date2str(date, format='%Y-%m-%d'):
'''Convert a datetime object to a string''' '''Convert a datetime object to a string'''
return date.strftime(format) return date.strftime(format)
def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'): def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'):
''' '''
Convert a date in a string to another string, in a different Convert a date in a string to another string, in a different
@@ -44,7 +47,9 @@ def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'):
''' '''
return date2str(str2date(datestr, fromfmt), tofmt) return date2str(str2date(datestr, fromfmt), tofmt)
_SWIFT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-?:().,'+ " _SWIFT = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"/-?:().,'+ ")
def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']): def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']):
''' '''

View File

@@ -22,6 +22,7 @@
import re import re
from openerp.tools.translate import _ from openerp.tools.translate import _
class mem_bank_statement(object): class mem_bank_statement(object):
''' '''
A mem_bank_statement is a real life projection of a bank statement paper A mem_bank_statement is a real life projection of a bank statement paper
@@ -34,9 +35,15 @@ class mem_bank_statement(object):
''' '''
# Lock attributes to enable parsers to trigger non-conformity faults # Lock attributes to enable parsers to trigger non-conformity faults
__slots__ = [ __slots__ = [
'start_balance','end_balance', 'date', 'local_account', 'start_balance',
'local_currency', 'id', 'transactions' 'end_balance',
'date',
'local_account',
'local_currency',
'id',
'transactions'
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(mem_bank_statement, self).__init__(*args, **kwargs) super(mem_bank_statement, self).__init__(*args, **kwargs)
self.id = '' self.id = ''
@@ -59,6 +66,7 @@ class mem_bank_statement(object):
check += float(transaction.transferred_amount) check += float(transaction.transferred_amount)
return abs(check - float(self.end_balance)) < 0.0001 return abs(check - float(self.end_balance)) < 0.0001
class mem_bank_transaction(object): class mem_bank_transaction(object):
''' '''
A mem_bank_transaction is a real life copy of a bank transfer. Mapping to A mem_bank_transaction is a real life copy of a bank transfer. Mapping to
@@ -126,7 +134,8 @@ class mem_bank_transaction(object):
# The other parties postal code belonging to the address # The other parties postal code belonging to the address
'remote_owner_country_code', 'remote_owner_country_code',
# The other parties two letter ISO country code belonging to the previous # The other parties two letter ISO country code belonging to the
# previous
'remote_owner_custno', 'remote_owner_custno',
# The other parties customer number # The other parties customer number
@@ -270,7 +279,7 @@ class mem_bank_transaction(object):
if value in self.types: if value in self.types:
self.transfer_type = value self.transfer_type = value
else: else:
raise ValueError, _('Invalid value for transfer_type') raise ValueError(_('Invalid value for transfer_type'))
type = property(_get_type, _set_type) type = property(_get_type, _set_type)
@@ -282,6 +291,7 @@ class mem_bank_transaction(object):
return (self.execution_date and self.remote_account return (self.execution_date and self.remote_account
and self.transferred_amount and True) or False and self.transferred_amount and True) or False
class parser_type(type): class parser_type(type):
''' '''
Meta annex factory class for house keeping and collecting parsers. Meta annex factory class for house keeping and collecting parsers.
@@ -314,11 +324,13 @@ class parser_type(type):
keys.sort() keys.sort()
return [(parsers[x].code, parsers[x].name) for x in keys] return [(parsers[x].code, parsers[x].name) for x in keys]
def create_parser(code): def create_parser(code):
if code in parser_type.parser_by_code: if code in parser_type.parser_by_code:
return parser_type.parser_by_code[code]() return parser_type.parser_by_code[code]()
return None return None
class parser(object): class parser(object):
''' '''
A parser delivers the interface for any parser object. Inherit from A parser delivers the interface for any parser object. Inherit from
@@ -408,5 +420,3 @@ class parser(object):
raise NotImplementedError( raise NotImplementedError(
_('This is a stub. Please implement your own.') _('This is a stub. Please implement your own.')
) )
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -31,16 +31,19 @@ from datetime import datetime, date
# Correct python2.4 issues # Correct python2.4 issues
try: try:
datetime.strptime datetime.strptime
def strpdate(str, format): def strpdate(str, format):
return datetime.strptime(str, format).date() return datetime.strptime(str, format).date()
except AttributeError: except AttributeError:
import time import time
def strpdate(str, format): def strpdate(str, format):
tm = time.strptime(str, format) tm = time.strptime(str, format)
return date(tm.tm_year, tm.tm_mon, tm.tm_mday) return date(tm.tm_year, tm.tm_mon, tm.tm_mday)
import unicodedata import unicodedata
class Field(object): class Field(object):
'''Base Field class - fixed length left aligned string field in a record''' '''Base Field class - fixed length left aligned string field in a record'''
def __init__(self, name, length=1, fillchar=' ', cast=str): def __init__(self, name, length=1, fillchar=' ', cast=str):
@@ -57,11 +60,14 @@ class Field(object):
def take(self, buffer): def take(self, buffer):
offset = hasattr(self, 'offset') and self.offset or 0 offset = hasattr(self, 'offset') and self.offset or 0
return self.cast(buffer[offset:offset + self.length].rstrip(self.fillchar)) return self.cast(buffer[offset:offset + self.length].rstrip(
self.fillchar)
)
def __repr__(self): def __repr__(self):
return '%s "%s"' % (self.__class__.__name__, self.name) return '%s "%s"' % (self.__class__.__name__, self.name)
class Filler(Field): class Filler(Field):
'''Constant value field''' '''Constant value field'''
def __init__(self, name, length=1, value=' '): def __init__(self, name, length=1, value=' '):
@@ -73,9 +79,10 @@ class Filler(Field):
def format(self, value): def format(self, value):
return super(Filler, self).format( return super(Filler, self).format(
self.value * (self.length / len(self.value) +1) self.value * (self.length / len(self.value) + 1)
) )
class DateField(Field): class DateField(Field):
'''Variable date field''' '''Variable date field'''
def __init__(self, name, format='%Y-%m-%d', auto=False, cast=str): def __init__(self, name, format='%Y-%m-%d', auto=False, cast=str):
@@ -98,6 +105,7 @@ class DateField(Field):
return strpdate(value, self.dateformat) return strpdate(value, self.dateformat)
return self.auto and date.today() or None return self.auto and date.today() or None
class RightAlignedField(Field): class RightAlignedField(Field):
'''Deviation of Field: right aligned''' '''Deviation of Field: right aligned'''
def format(self, value): def format(self, value):
@@ -107,7 +115,10 @@ class RightAlignedField(Field):
def take(self, buffer): def take(self, buffer):
offset = hasattr(self, 'offset') and self.offset or 0 offset = hasattr(self, 'offset') and self.offset or 0
return self.cast(buffer[offset:offset + self.length].lstrip(self.fillchar)) return self.cast(buffer[offset:offset + self.length].lstrip(
self.fillchar)
)
class NumberField(RightAlignedField): class NumberField(RightAlignedField):
'''Deviation of Field: left zero filled''' '''Deviation of Field: left zero filled'''
@@ -118,6 +129,7 @@ class NumberField(RightAlignedField):
def format(self, value): def format(self, value):
return super(NumberField, self).format(self.cast(value or '')) return super(NumberField, self).format(self.cast(value or ''))
class RecordType(object): class RecordType(object):
fields = [] fields = []
@@ -130,7 +142,7 @@ class RecordType(object):
offset += field.length offset += field.length
def __len__(self): def __len__(self):
return reduce(lambda x,y: x+y.length, self.fields, 0) return reduce(lambda x, y: x + y.length, self.fields, 0)
def __contains__(self, key): def __contains__(self, key):
return any(lambda x, y=key: x.name == y, self.fields) return any(lambda x, y=key: x.name == y, self.fields)
@@ -139,7 +151,7 @@ class RecordType(object):
for field in self.fields: for field in self.fields:
if field.name == key: if field.name == key:
return field return field
raise KeyError, 'No such field: %s' % key raise KeyError('No such field: %s' % key)
def format(self, buffer): def format(self, buffer):
result = [] result = []
@@ -152,6 +164,7 @@ class RecordType(object):
[x.take(buffer) for x in self.fields] [x.take(buffer) for x in self.fields]
)) ))
class Record(object): class Record(object):
_recordtype = None _recordtype = None
@@ -159,7 +172,7 @@ class Record(object):
if hasattr(self, '_fields') and self._fields: if hasattr(self, '_fields') and self._fields:
self._recordtype = RecordType(self._fields) self._recordtype = RecordType(self._fields)
if not self._recordtype and not recordtype: if not self._recordtype and not recordtype:
raise ValueError, 'No recordtype specified' raise ValueError('No recordtype specified')
if not self._recordtype: if not self._recordtype:
self._recordtype = recordtype() self._recordtype = recordtype()
self._length = len(self._recordtype) self._length = len(self._recordtype)
@@ -173,9 +186,11 @@ class Record(object):
super(Record, self).__setattr__(attr, value) super(Record, self).__setattr__(attr, value)
else: else:
field = self._recordtype[attr] field = self._recordtype[attr]
self._value = self._value[:field.offset] + \ self._value = (
field.format(value) + \ self._value[:field.offset] +
field.format(value) +
self._value[field.offset + field.length:] self._value[field.offset + field.length:]
)
def __getattr__(self, attr): def __getattr__(self, attr):
if attr.startswith('_'): if attr.startswith('_'):
@@ -189,7 +204,6 @@ class Record(object):
def __unicode__(self): def __unicode__(self):
return unicode(self.cast(self)) return unicode(self.cast(self))
def asciify(str): def asciify(str):
return unicodedata.normalize('NFKD', str).encode('ascii', 'ignore') return unicodedata.normalize('NFKD', str).encode('ascii', 'ignore')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -44,6 +44,7 @@
__all__ = ['IBAN', 'BBAN'] __all__ = ['IBAN', 'BBAN']
def modulo_97_base10(abuffer): def modulo_97_base10(abuffer):
''' '''
Calculate the modulo 97 value of a string in base10 Calculate the modulo 97 value of a string in base10
@@ -55,6 +56,7 @@ def modulo_97_base10(abuffer):
checksum %= 97 checksum %= 97
return checksum return checksum
def base36_to_base10str(abuffer): def base36_to_base10str(abuffer):
''' '''
Convert a base36 string value to a string of base10 digits. Convert a base36 string value to a string of base10 digits.
@@ -67,6 +69,7 @@ def base36_to_base10str(abuffer):
result += digit result += digit
return result return result
class BBANFormat(object): class BBANFormat(object):
''' '''
A BBANFormat is an auxilliary class for IBAN. It represents the composition A BBANFormat is an auxilliary class for IBAN. It represents the composition
@@ -178,6 +181,7 @@ class BBANFormat(object):
i += 1 i += 1
return res return res
class IBAN(str): class IBAN(str):
''' '''
A IBAN string represents a SEPA bank account number. This class provides A IBAN string represents a SEPA bank account number. This class provides
@@ -272,7 +276,7 @@ class IBAN(str):
if item.isalnum(): if item.isalnum():
init += item init += item
elif item not in ' \t.-': elif item not in ' \t.-':
raise ValueError, 'Invalid chars found in IBAN number' raise ValueError('Invalid chars found in IBAN number')
return str.__new__(cls, init) return str.__new__(cls, init)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -287,8 +291,7 @@ class IBAN(str):
@classmethod @classmethod
def create(cls, BIC=None, countrycode=None, BBAN=None, bankcode=None, def create(cls, BIC=None, countrycode=None, BBAN=None, bankcode=None,
branchcode=None, account=None branchcode=None, account=None):
):
''' '''
Create a IBAN number from a BBAN and a country code. Optionaly create Create a IBAN number from a BBAN and a country code. Optionaly create
a BBAN from BBAN components before generation. a BBAN from BBAN components before generation.
@@ -304,20 +307,17 @@ class IBAN(str):
if countrycode: if countrycode:
countrycode = countrycode.upper() countrycode = countrycode.upper()
else: else:
raise ValueError, \ raise ValueError('Either BIC or countrycode is required')
'Either BIC or countrycode is required'
if countrycode not in cls.countries: if countrycode not in cls.countries:
raise ValueError, \ raise ValueError('%s is not a SEPA country' % countrycode)
'%s is not a SEPA country' % countrycode
format = cls.BBAN_formats[countrycode] format = cls.BBAN_formats[countrycode]
if BBAN: if BBAN:
if len(BBAN) == len(format._iban): if len(BBAN) == len(format._iban):
ibanno = cls(countrycode + '00' + BBAN) ibanno = cls(countrycode + '00' + BBAN)
return cls(countrycode + ibanno.checksum + BBAN) return cls(countrycode + ibanno.checksum + BBAN)
raise ValueError, \ raise ValueError('Insufficient data to generate IBAN')
'Insufficient data to generate IBAN'
@property @property
def valid(self): def valid(self):
@@ -325,8 +325,10 @@ class IBAN(str):
Check if the string + check digits deliver a valid checksum Check if the string + check digits deliver a valid checksum
''' '''
_buffer = self[4:] + self[:4] _buffer = self[4:] + self[:4]
return self.countrycode in self.countries and \ return (
int(base36_to_base10str(_buffer)) % 97 == 1 self.countrycode in self.countries
and int(base36_to_base10str(_buffer)) % 97 == 1
)
def __repr__(self): def __repr__(self):
''' '''
@@ -421,6 +423,7 @@ class IBAN(str):
''' '''
return self[4:] return self[4:]
class BBAN(object): class BBAN(object):
''' '''
Class to reformat a local BBAN account number to IBAN specs. Class to reformat a local BBAN account number to IBAN specs.
@@ -433,10 +436,11 @@ class BBAN(object):
Internal method to calculate the length of a parameter in a Internal method to calculate the length of a parameter in a
formatted string formatted string
''' '''
i = 0; max_i = len(fmt._iban) i = 0
max_i = len(fmt._iban)
while i < max_i: while i < max_i:
if fmt._iban[i] == element: if fmt._iban[i] == element:
next = i +1 next = i + 1
while next < max_i and fmt._iban[next] == element: while next < max_i and fmt._iban[next] == element:
next += 1 next += 1
return next - i return next - i
@@ -453,7 +457,10 @@ class BBAN(object):
if countrycode.upper() in IBAN.countries: if countrycode.upper() in IBAN.countries:
self._fmt = IBAN.BBAN_formats[countrycode.upper()] self._fmt = IBAN.BBAN_formats[countrycode.upper()]
res = '' res = ''
i = 0; j = 0; max_i = len(self._fmt._bban); max_j = len(bban) i = 0
j = 0
max_i = len(self._fmt._bban)
max_j = len(bban)
while i < max_i and j < max_j: while i < max_i and j < max_j:
while bban[j] in ' \t' and j < max_j: while bban[j] in ' \t' and j < max_j:
j += 1 j += 1
@@ -512,15 +519,16 @@ class BBAN(object):
'''Simple check if BBAN is in the right format''' '''Simple check if BBAN is in the right format'''
return self._bban and True or False return self._bban and True or False
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
iban = IBAN(arg) iban = IBAN(arg)
print 'IBAN:', iban print('IBAN:', iban)
print 'country code:', iban.countrycode print('country code:', iban.countrycode)
print 'bank code:', iban.bankcode print('bank code:', iban.bankcode)
print 'branch code:', iban.branchcode print('branch code:', iban.branchcode)
print 'BBAN:', iban.BBAN print('BBAN:', iban.BBAN)
print 'localized BBAN:', iban.localized_BBAN print('localized BBAN:', iban.localized_BBAN)
print 'check digits:', iban.checkdigits print('check digits:', iban.checkdigits)
print 'checksum:', iban.checksum print('checksum:', iban.checksum)

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -27,6 +27,7 @@ import re
__all__ = ['split', 'get', 'PostalCode'] __all__ = ['split', 'get', 'PostalCode']
class PostalCode(object): class PostalCode(object):
''' '''
The PostalCode class is a wrapper around PostCodeFormat and an internal The PostalCode class is a wrapper around PostCodeFormat and an internal
@@ -46,8 +47,8 @@ class PostalCode(object):
''' '''
# Sort formats on length, longest first # Sort formats on length, longest first
formats = [(len(x), x) for x in format.split('|')] formats = [(len(x), x) for x in format.split('|')]
formats = [x[1] for x in sorted(formats, lambda x,y: -cmp(x,y))] formats = [x[1] for x in sorted(formats, lambda x, y: -cmp(x, y))]
self.res = [re.compile(x.replace('#', '\\d').replace('@','[A-Z]')) self.res = [re.compile(x.replace('#', '\\d').replace('@', '[A-Z]'))
for x in formats for x in formats
] ]
@@ -99,7 +100,8 @@ class PostalCode(object):
'IM': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA', 'IM': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
'IL': '#####', 'IT': '####', 'JM': '', 'JP': '###-####', 'IL': '#####', 'IT': '####', 'JM': '', 'JP': '###-####',
'JE': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA', 'JE': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
'JO': '#####', 'KZ': '######', 'KE': '#####', 'KI': '', 'KP': '###-###', 'JO': '#####', 'KZ': '######', 'KE': '#####', 'KI': '',
'KP': '###-###',
'KR': 'SEOUL ###-###', 'KW': '#####', 'KG': '######', 'LA': '#####', 'KR': 'SEOUL ###-###', 'KW': '#####', 'KG': '######', 'LA': '#####',
'LV': 'LV-####', 'LB': '#### ####|####', 'LS': '###', 'LR': '####', 'LV': 'LV-####', 'LB': '#### ####|####', 'LS': '###', 'LR': '####',
'LY': '', 'LI': '####', 'LT': 'LT-#####', 'LU': '####', 'MO': '', 'LY': '', 'LI': '####', 'LT': 'LT-#####', 'LU': '####', 'MO': '',
@@ -155,14 +157,12 @@ class PostalCode(object):
# Find optimum (= max length postalcode) when iso code is unknown # Find optimum (= max length postalcode) when iso code is unknown
all = {} all = {}
opt_iso = ''
max_l = 0 max_l = 0
for key in cls._formats.iterkeys(): for key in cls._formats.iterkeys():
i, p, c = cls.split(str_, key) i, p, c = cls.split(str_, key)
l = len(p) l = len(p)
if l > max_l: if l > max_l:
max_l = l max_l = l
opt_iso = i
if l in all: if l in all:
all[l].append((i, p, c)) all[l].append((i, p, c))
else: else:

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
''' '''
Define a struct class which behaves like a dict, but allows using Define a struct class which behaves like a dict, but allows using
object.attr alongside object['attr']. object.attr alongside object['attr'].
@@ -25,6 +26,7 @@ object.attr alongside object['attr'].
__all__ = ['struct'] __all__ = ['struct']
class struct(dict): class struct(dict):
''' '''
Ease working with dicts. Allow dict.key alongside dict['key'] Ease working with dicts. Allow dict.key alongside dict['key']
@@ -52,4 +54,4 @@ class struct(dict):
else: else:
fmt = '%*.*s%%s: %%s' % (indent, indent, '') fmt = '%*.*s%%s: %%s' % (indent, indent, '')
for item in self.iteritems(): for item in self.iteritems():
print fmt % item print(fmt % item)

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -18,8 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
import bank_import
import banking_transaction_wizard
import link_partner
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: from . import bank_import
from . import banking_transaction_wizard
from . import link_partner

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -23,11 +23,13 @@
# Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes # Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes
# Stefan Rijnhart (Therp): bugreport and bugfix # Stefan Rijnhart (Therp): bugreport and bugfix
# #
''' '''
This module contains the business logic of the wizard account_banking_import. This module contains the business logic of the wizard account_banking_import.
The parsing is done in the parser modules. Every parser module is required to The parsing is done in the parser modules. Every parser module is required to
use parser.models as a mean of communication with the business logic. use parser.models as a mean of communication with the business logic.
''' '''
import base64 import base64
import datetime import datetime
from openerp.osv import orm, fields from openerp.osv import orm, fields
@@ -44,6 +46,7 @@ bt = models.mem_bank_transaction
# the real payment date. This can occur with online transactions (web shops). # the real payment date. This can occur with online transactions (web shops).
payment_window = datetime.timedelta(days=10) payment_window = datetime.timedelta(days=10)
def parser_types(*args, **kwargs): def parser_types(*args, **kwargs):
'''Delay evaluation of parser types until start of wizard, to allow '''Delay evaluation of parser types until start of wizard, to allow
depending modules to initialize and add their parsers to the list depending modules to initialize and add their parsers to the list
@@ -57,18 +60,26 @@ class banking_import_line(orm.TransientModel):
_columns = { _columns = {
'name': fields.char('Name', size=64), 'name': fields.char('Name', size=64),
'date': fields.date('Date', readonly=True), 'date': fields.date('Date', readonly=True),
'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), 'amount': fields.float(
'Amount',
digits_compute=dp.get_precision('Account'),
),
'statement_line_id': fields.many2one( 'statement_line_id': fields.many2one(
'account.bank.statement.line', 'account.bank.statement.line',
'Resulting statement line', readonly=True), 'Resulting statement line', readonly=True),
'type': fields.selection([ 'type': fields.selection([
('supplier','Supplier'), ('supplier', 'Supplier'),
('customer','Customer'), ('customer', 'Customer'),
('general','General') ('general', 'General')
], 'Type', required=True), ], 'Type', required=True),
'partner_id': fields.many2one('res.partner', 'Partner'), 'partner_id': fields.many2one('res.partner', 'Partner'),
'statement_id': fields.many2one('account.bank.statement', 'Statement', 'statement_id': fields.many2one(
select=True, required=True, ondelete='cascade'), 'account.bank.statement',
'Statement',
select=True,
required=True,
ondelete='cascade',
),
'ref': fields.char('Reference', size=32), 'ref': fields.char('Reference', size=32),
'note': fields.text('Notes'), 'note': fields.text('Notes'),
'period_id': fields.many2one('account.period', 'Period'), 'period_id': fields.many2one('account.period', 'Period'),
@@ -83,13 +94,16 @@ class banking_import_line(orm.TransientModel):
'account.invoice', 'banking_import_line_invoice_rel', 'account.invoice', 'banking_import_line_invoice_rel',
'line_id', 'invoice_id'), 'line_id', 'invoice_id'),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'), 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
'transaction_type': fields.selection([ 'transaction_type': fields.selection(
[
# TODO: payment terminal etc... # TODO: payment terminal etc...
('invoice', 'Invoice payment'), ('invoice', 'Invoice payment'),
('storno', 'Canceled debit order'), ('storno', 'Canceled debit order'),
('bank_costs', 'Bank costs'), ('bank_costs', 'Bank costs'),
('unknown', 'Unknown'), ('unknown', 'Unknown'),
], 'Transaction type'), ],
'Transaction type',
),
'duplicate': fields.boolean('Duplicate'), 'duplicate': fields.boolean('Duplicate'),
} }
@@ -119,7 +133,8 @@ class banking_import(orm.TransientModel):
if not parser: if not parser:
raise orm.except_orm( raise orm.except_orm(
_('ERROR!'), _('ERROR!'),
_('Unable to import parser %(parser)s. Parser class not found.') % _('Unable to import parser %(parser)s. Parser class not '
'found.') %
{'parser': parser_code} {'parser': parser_code}
) )
@@ -133,16 +148,17 @@ class banking_import(orm.TransientModel):
if any([x for x in statements if not x.is_valid()]): if any([x for x in statements if not x.is_valid()]):
raise orm.except_orm( raise orm.except_orm(
_('ERROR!'), _('ERROR!'),
_('The imported statements appear to be invalid! Check your file.') _('The imported statements appear to be invalid! Check your '
'file.')
) )
# Create the file now, as the statements need to be linked to it # Create the file now, as the statements need to be linked to it
import_id = statement_file_obj.create(cr, uid, dict( import_id = statement_file_obj.create(cr, uid, dict(
company_id = company.id, company_id=company.id,
file = statements_file, file=statements_file,
file_name = banking_import.file_name, file_name=banking_import.file_name,
state = 'unfinished', state='unfinished',
format = parser.name, format=parser.name,
)) ))
bank_country_code = False bank_country_code = False
@@ -151,14 +167,14 @@ class banking_import(orm.TransientModel):
# Results # Results
results = struct( results = struct(
stat_loaded_cnt = 0, stat_loaded_cnt=0,
trans_loaded_cnt = 0, trans_loaded_cnt=0,
stat_skipped_cnt = 0, stat_skipped_cnt=0,
trans_skipped_cnt = 0, trans_skipped_cnt=0,
trans_matched_cnt = 0, trans_matched_cnt=0,
bank_costs_invoice_cnt = 0, bank_costs_invoice_cnt=0,
error_cnt = 0, error_cnt=0,
log = [], log=[],
) )
# Caching # Caching
@@ -175,7 +191,9 @@ class banking_import(orm.TransientModel):
continue continue
# Create fallback currency code # Create fallback currency code
currency_code = statement.local_currency or company.currency_id.name currency_code = (
statement.local_currency or company.currency_id.name
)
# Check cache for account info/currency # Check cache for account info/currency
if statement.local_account in info and \ if statement.local_account in info and \
@@ -190,8 +208,10 @@ class banking_import(orm.TransientModel):
) )
if not account_info: if not account_info:
results.log.append( results.log.append(
_('Statements found for unknown account %(bank_account)s') % _('Statements found for unknown account '
{'bank_account': statement.local_account} '%(bank_account)s') % {
'bank_account': statement.local_account
}
) )
error_accounts[statement.local_account] = True error_accounts[statement.local_account] = True
results.error_cnt += 1 results.error_cnt += 1
@@ -210,7 +230,7 @@ class banking_import(orm.TransientModel):
currency_code = account_info.currency_id.name currency_code = account_info.currency_id.name
# Cache results # Cache results
if not statement.local_account in info: if statement.local_account not in info:
info[statement.local_account] = { info[statement.local_account] = {
currency_code: account_info currency_code: account_info
} }
@@ -251,7 +271,8 @@ class banking_import(orm.TransientModel):
) )
continue continue
# Get the period for the statement (as bank statement object checks this) # Get the period for the statement (as bank statement object
# checks this)
period_ids = period_obj.search( period_ids = period_obj.search(
cr, uid, [ cr, uid, [
('company_id', '=', company.id), ('company_id', '=', company.id),
@@ -272,17 +293,17 @@ class banking_import(orm.TransientModel):
# Create the bank statement record # Create the bank statement record
statement_id = statement_obj.create(cr, uid, dict( statement_id = statement_obj.create(cr, uid, dict(
name = statement.id, name=statement.id,
journal_id = account_info.journal_id.id, journal_id=account_info.journal_id.id,
date = convert.date2str(statement.date), date=convert.date2str(statement.date),
balance_start = statement.start_balance, balance_start=statement.start_balance,
balance_end_real = statement.end_balance, balance_end_real=statement.end_balance,
balance_end = statement.end_balance, balance_end=statement.end_balance,
state = 'draft', state='draft',
user_id = uid, user_id=uid,
banking_id = import_id, banking_id=import_id,
company_id = company.id, company_id=company.id,
period_id = period_ids[0], period_id=period_ids[0],
)) ))
imported_statement_ids.append(statement_id) imported_statement_ids.append(statement_id)
@@ -294,7 +315,8 @@ class banking_import(orm.TransientModel):
values = {} values = {}
for attr in transaction.__slots__ + ['type']: for attr in transaction.__slots__ + ['type']:
if attr in import_transaction_obj.column_map: if attr in import_transaction_obj.column_map:
values[import_transaction_obj.column_map[attr]] = eval('transaction.%s' % attr) values[import_transaction_obj.column_map[attr]] = \
eval('transaction.%s' % attr)
elif attr in import_transaction_obj._columns: elif attr in import_transaction_obj._columns:
values[attr] = eval('transaction.%s' % attr) values[attr] = eval('transaction.%s' % attr)
values['statement_id'] = statement_id values['statement_id'] = statement_id
@@ -308,32 +330,14 @@ class banking_import(orm.TransientModel):
results.stat_loaded_cnt += 1 results.stat_loaded_cnt += 1
import_transaction_obj.match(cr, uid, transaction_ids, results=results, context=context) import_transaction_obj.match(
cr, uid, transaction_ids, results=results, context=context
)
#recompute statement end_balance for validation # recompute statement end_balance for validation
statement_obj.button_dummy( statement_obj.button_dummy(
cr, uid, imported_statement_ids, context=context) cr, uid, imported_statement_ids, context=context)
# Original code. Didn't take workflow logistics into account...
#
#cr.execute(
# "UPDATE payment_order o "
# "SET state = 'done', "
# "date_done = '%s' "
# "FROM payment_line l "
# "WHERE o.state = 'sent' "
# "AND o.id = l.order_id "
# "AND l.id NOT IN ("
# "SELECT DISTINCT id FROM payment_line "
# "WHERE date_done IS NULL "
# "AND id IN (%s)"
# ")" % (
# time.strftime('%Y-%m-%d'),
# ','.join([str(x) for x in payment_line_ids])
# )
#)
report = [ report = [
'%s: %s' % (_('Total number of statements'), '%s: %s' % (_('Total number of statements'),
results.stat_skipped_cnt + results.stat_loaded_cnt), results.stat_skipped_cnt + results.stat_loaded_cnt),
@@ -360,14 +364,17 @@ class banking_import(orm.TransientModel):
text_log = '\n'.join(report + results.log) text_log = '\n'.join(report + results.log)
state = results.error_cnt and 'error' or 'ready' state = results.error_cnt and 'error' or 'ready'
statement_file_obj.write(cr, uid, import_id, dict( statement_file_obj.write(cr, uid, import_id, dict(
state = state, log = text_log, state=state,
log=text_log,
), context) ), context)
if not imported_statement_ids or not results.trans_loaded_cnt: if not imported_statement_ids or not results.trans_loaded_cnt:
# file state can be 'ready' while import state is 'error' # file state can be 'ready' while import state is 'error'
state = 'error' state = 'error'
self.write(cr, uid, [ids[0]], dict( self.write(cr, uid, [ids[0]], dict(
import_id = import_id, log = text_log, state = state, import_id=import_id,
statement_ids = [(6, 0, imported_statement_ids)], log=text_log,
state=state,
statement_ids=[(6, 0, imported_statement_ids)],
), context) ), context)
return { return {
'name': (state == 'ready' and _('Review Bank Statements') or 'name': (state == 'ready' and _('Review Bank Statements') or
@@ -393,13 +400,15 @@ class banking_import(orm.TransientModel):
), ),
'file_name': fields.char('File name', size=256), 'file_name': fields.char('File name', size=256),
'file': fields.binary( 'file': fields.binary(
'Statements File', required=True, 'Statements File',
help = ('The Transactions File to import. Please note that while it is ' required=True,
'perfectly safe to reload the same file multiple times or to load in ' help=('The Transactions File to import. Please note that while it '
'timeframe overlapping statements files, there are formats that may ' 'is perfectly safe to reload the same file multiple times '
'introduce different sequencing, which may create double entries.\n\n' 'or to load in timeframe overlapping statements files, '
'To stay on the safe side, always load bank statements files using the ' 'there are formats that may introduce different '
'same format.'), 'sequencing, which may create double entries.\n\n'
'To stay on the safe side, always load bank statements '
'files using the same format.'),
states={ states={
'ready': [('readonly', True)], 'ready': [('readonly', True)],
'error': [('readonly', True)], 'error': [('readonly', True)],
@@ -435,7 +444,7 @@ class banking_import(orm.TransientModel):
_defaults = { _defaults = {
'state': 'init', 'state': 'init',
'company': lambda s,cr,uid,c: 'company': lambda s, cr, uid, c:
s.pool.get('res.company')._company_default_get( s.pool.get('res.company')._company_default_get(
cr, uid, 'bank.import.transaction', context=c), cr, uid, 'bank.import.transaction', context=c),
'parser': _default_parser_type, 'parser': _default_parser_type,

View File

@@ -7,8 +7,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -128,10 +128,15 @@ class banking_transaction_wizard(orm.TransientModel):
wiz.import_transaction_id.invoice_id): wiz.import_transaction_id.invoice_id):
transaction_obj.write( transaction_obj.write(
cr, uid, wiz.import_transaction_id.id, cr, uid, wiz.import_transaction_id.id,
{ 'move_line_id': move_line.id, }, context=context) {'move_line_id': move_line.id, },
context=context
)
statement_line_obj.write( statement_line_obj.write(
cr, uid, wiz.import_transaction_id.statement_line_id.id, cr, uid,
{ 'partner_id': move_line.partner_id.id or False, wiz.import_transaction_id.statement_line_id.id,
{
'partner_id': (
move_line.partner_id.id or False),
'account_id': move_line.account_id.id, 'account_id': move_line.account_id.id,
}, context=context) }, context=context)
found = True found = True
@@ -150,15 +155,16 @@ class banking_transaction_wizard(orm.TransientModel):
# Rewrite *2many directive notation # Rewrite *2many directive notation
if manual_invoice_ids: if manual_invoice_ids:
manual_invoice_ids = ( manual_invoice_ids = (
[i[1] for i in manual_invoice_ids if i[0]==4] + [i[1] for i in manual_invoice_ids if i[0] == 4] +
[j for i in manual_invoice_ids if i[0]==6 for j in i[2]]) [j for i in manual_invoice_ids if i[0] == 6 for j in i[2]])
if manual_move_line_ids: if manual_move_line_ids:
manual_move_line_ids = ( manual_move_line_ids = (
[i[1] for i in manual_move_line_ids if i[0]==4] + [i[1] for i in manual_move_line_ids if i[0] == 4] +
[j for i in manual_move_line_ids if i[0]==6 for j in i[2]]) [j for i in manual_move_line_ids
if i[0] == 6 for j in i[2]])
for wiz in self.browse(cr, uid, ids, context=context): for wiz in self.browse(cr, uid, ids, context=context):
#write can be called multiple times for the same values # write can be called multiple times for the same values
#that doesn't hurt above, but it does here # that doesn't hurt above, but it does here
if wiz.match_type and ( if wiz.match_type and (
len(manual_move_line_ids) > 1 or len(manual_move_line_ids) > 1 or
len(manual_invoice_ids) > 1): len(manual_invoice_ids) > 1):
@@ -171,7 +177,8 @@ class banking_transaction_wizard(orm.TransientModel):
found_move_line = False found_move_line = False
if invoice.move_id: if invoice.move_id:
for line in invoice.move_id.line_id: for line in invoice.move_id.line_id:
if line.account_id.type in ('receivable', 'payable'): if line.account_id.type in ('receivable',
'payable'):
todo.append((invoice.id, line.id)) todo.append((invoice.id, line.id))
found_move_line = True found_move_line = True
break break
@@ -181,12 +188,13 @@ class banking_transaction_wizard(orm.TransientModel):
_("No entry found for the selected invoice. ")) _("No entry found for the selected invoice. "))
for move_line_id in manual_move_line_ids: for move_line_id in manual_move_line_ids:
todo_entry = [False, move_line_id] todo_entry = [False, move_line_id]
move_line=move_line_obj.read( move_line = move_line_obj.read(
cr, cr,
uid, uid,
move_line_id, move_line_id,
['invoice'], ['invoice'],
context=context) context=context
)
if move_line['invoice']: if move_line['invoice']:
todo_entry[0] = move_line['invoice'][0] todo_entry[0] = move_line['invoice'][0]
todo.append(todo_entry) todo.append(todo_entry)
@@ -205,14 +213,16 @@ class banking_transaction_wizard(orm.TransientModel):
cr, cr,
uid, uid,
statement_line_id, statement_line_id,
context=context).import_transaction_id.id context=context
).import_transaction_id.id
vals = { vals = {
'move_line_id': todo_entry[1], 'move_line_id': todo_entry[1],
'move_line_ids': [(6, 0, [todo_entry[1]])], 'move_line_ids': [(6, 0, [todo_entry[1]])],
'invoice_id': todo_entry[0], 'invoice_id': todo_entry[0],
'invoice_ids': [(6, 0, 'invoice_ids': [
[todo_entry[0]] if todo_entry[0] else [])], (6, 0, [todo_entry[0]] if todo_entry[0] else [])
],
'match_type': 'manual', 'match_type': 'manual',
} }
@@ -255,22 +265,19 @@ class banking_transaction_wizard(orm.TransientModel):
# Get the bank account setting record, to reset the account # Get the bank account setting record, to reset the account
account_id = False account_id = False
journal_id = wiz.statement_line_id.statement_id.journal_id.id journal_id = wiz.statement_line_id.statement_id.journal_id.id
setting_ids = settings_pool.find(cr, uid, journal_id, context=context) setting_ids = settings_pool.find(
cr, uid, journal_id, context=context
)
# Restore partner id from the bank account or else reset # Restore partner id from the bank account or else reset
partner_id = False partner_id = False
if (wiz.statement_line_id.partner_bank_id and if (wiz.statement_line_id.partner_bank_id and
wiz.statement_line_id.partner_bank_id.partner_id): wiz.statement_line_id.partner_bank_id.partner_id):
partner_id = wiz.statement_line_id.partner_bank_id.partner_id.id partner_id = (
wiz.statement_line_id.partner_bank_id.partner_id.id
)
wiz.write({'partner_id': partner_id}) wiz.write({'partner_id': partner_id})
# Select account type by parter customer or supplier,
# or default based on amount sign
if wiz.amount < 0:
account_type = 'payable'
else:
account_type = 'receivable'
bank_partner = False bank_partner = False
if partner_id: if partner_id:
bank_partner = wiz.statement_line_id.partner_bank_id.partner_id bank_partner = wiz.statement_line_id.partner_bank_id.partner_id
@@ -295,13 +302,18 @@ class banking_transaction_wizard(orm.TransientModel):
wiz.statement_line_id.write({'account_id': account_id}) wiz.statement_line_id.write({'account_id': account_id})
if wiz.statement_line_id: if wiz.statement_line_id:
#delete splits causing an unsplit if this is a split # delete splits causing an unsplit if this is a split
#transaction # transaction
statement_pool.unlink(cr, uid, statement_pool.unlink(
statement_pool.search(cr, uid, cr,
uid,
statement_pool.search(
cr, uid,
[('parent_id', '=', wiz.statement_line_id.id)], [('parent_id', '=', wiz.statement_line_id.id)],
context=context), context=context
context=context) ),
context=context
)
if wiz.import_transaction_id: if wiz.import_transaction_id:
wiz.import_transaction_id.clear_and_write() wiz.import_transaction_id.clear_and_write()
@@ -363,8 +375,12 @@ class banking_transaction_wizard(orm.TransientModel):
'import_transaction_id', 'invoice_ids', string="Matching invoices", 'import_transaction_id', 'invoice_ids', string="Matching invoices",
type='many2many', relation='account.invoice'), type='many2many', relation='account.invoice'),
'invoice_id': fields.related( 'invoice_id': fields.related(
'import_transaction_id', 'invoice_id', string="Invoice to reconcile", 'import_transaction_id',
type='many2one', relation='account.invoice'), 'invoice_id',
string="Invoice to reconcile",
type='many2one',
relation='account.invoice',
),
'move_line_ids': fields.related( 'move_line_ids': fields.related(
'import_transaction_id', 'move_line_ids', string="Entry lines", 'import_transaction_id', 'move_line_ids', string="Entry lines",
type='many2many', relation='account.move.line'), type='many2many', relation='account.move.line'),
@@ -372,15 +388,20 @@ class banking_transaction_wizard(orm.TransientModel):
'import_transaction_id', 'move_line_id', string="Entry line", 'import_transaction_id', 'move_line_id', string="Entry line",
type='many2one', relation='account.move.line'), type='many2one', relation='account.move.line'),
'duplicate': fields.related( 'duplicate': fields.related(
'import_transaction_id', 'duplicate', string='Flagged as duplicate', 'import_transaction_id',
type='boolean'), 'duplicate',
string='Flagged as duplicate',
type='boolean',
),
'match_multi': fields.related( 'match_multi': fields.related(
'import_transaction_id', 'match_multi', 'import_transaction_id', 'match_multi',
type="boolean", string='Multiple matches'), type="boolean", string='Multiple matches'),
'match_type': fields.related( 'match_type': fields.related(
'import_transaction_id', 'match_type', type='selection', 'import_transaction_id',
'match_type',
type='selection',
selection=[ selection=[
('move','Move'), ('move', 'Move'),
('invoice', 'Invoice'), ('invoice', 'Invoice'),
('payment', 'Payment line'), ('payment', 'Payment line'),
('payment_order', 'Payment order'), ('payment_order', 'Payment order'),
@@ -389,7 +410,9 @@ class banking_transaction_wizard(orm.TransientModel):
('payment_manual', 'Payment line (manual)'), ('payment_manual', 'Payment line (manual)'),
('payment_order_manual', 'Payment order (manual)'), ('payment_order_manual', 'Payment order (manual)'),
], ],
string='Match type', readonly=True), string='Match type',
readonly=True,
),
'manual_invoice_ids': fields.many2many( 'manual_invoice_ids': fields.many2many(
'account.invoice', 'account.invoice',
'banking_transaction_wizard_account_invoice_rel', 'banking_transaction_wizard_account_invoice_rel',
@@ -401,8 +424,17 @@ class banking_transaction_wizard(orm.TransientModel):
'wizard_id', 'move_line_id', string='Or match one or more entries', 'wizard_id', 'move_line_id', string='Or match one or more entries',
domain=[('account_id.reconcile', '=', True), domain=[('account_id.reconcile', '=', True),
('reconcile_id', '=', False)]), ('reconcile_id', '=', False)]),
'payment_option': fields.related('import_transaction_id','payment_option', string='Payment Difference', type='selection', required=True, 'payment_option': fields.related(
selection=[('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')]), 'import_transaction_id',
'payment_option',
string='Payment Difference',
type='selection',
required=True,
selection=[
('without_writeoff', 'Keep Open'),
('with_writeoff', 'Reconcile Payment Balance')
],
),
'writeoff_analytic_id': fields.related( 'writeoff_analytic_id': fields.related(
'import_transaction_id', 'writeoff_analytic_id', 'import_transaction_id', 'writeoff_analytic_id',
type='many2one', relation='account.analytic.account', type='many2one', relation='account.analytic.account',
@@ -411,9 +443,11 @@ class banking_transaction_wizard(orm.TransientModel):
'statement_line_id', 'analytic_account_id', 'statement_line_id', 'analytic_account_id',
type='many2one', relation='account.analytic.account', type='many2one', relation='account.analytic.account',
string="Analytic Account"), string="Analytic Account"),
'move_currency_amount': fields.related('import_transaction_id','move_currency_amount', 'move_currency_amount': fields.related(
type='float', string='Match Currency Amount', readonly=True), 'import_transaction_id',
'move_currency_amount',
type='float',
string='Match Currency Amount',
readonly=True,
),
} }
banking_transaction_wizard()

View File

@@ -5,8 +5,8 @@
# All Rights Reserved # All Rights Reserved
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published
# the Free Software Foundation, either version 3 of the License, or # by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
@@ -32,6 +32,7 @@ __all__ = [
'create_bank_account', 'create_bank_account',
] ]
def get_period(pool, cr, uid, date, company, log=None): def get_period(pool, cr, uid, date, company, log=None):
''' '''
Wrapper over account_period.find() to log exceptions of Wrapper over account_period.find() to log exceptions of
@@ -43,7 +44,7 @@ def get_period(pool, cr, uid, date, company, log=None):
try: try:
period_ids = pool.get('account.period').find( period_ids = pool.get('account.period').find(
cr, uid, dt=date, context=context) cr, uid, dt=date, context=context)
except Exception, e: except Exception as e:
if log is None: if log is None:
raise raise
else: else:
@@ -51,6 +52,7 @@ def get_period(pool, cr, uid, date, company, log=None):
return False return False
return period_ids[0] return period_ids[0]
def get_bank_accounts(pool, cr, uid, account_number, log, fail=False): def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
''' '''
Get the bank account with account number account_number Get the bank account with account number account_number
@@ -72,6 +74,7 @@ def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
return [] return []
return partner_bank_obj.browse(cr, uid, bank_account_ids) return partner_bank_obj.browse(cr, uid, bank_account_ids)
def _has_attr(obj, attr): def _has_attr(obj, attr):
# Needed for dangling addresses and a weird exception scheme in # Needed for dangling addresses and a weird exception scheme in
# OpenERP's orm. # OpenERP's orm.
@@ -80,6 +83,7 @@ def _has_attr(obj, attr):
except KeyError: except KeyError:
return False return False
def get_partner(pool, cr, uid, name, address, postal_code, city, def get_partner(pool, cr, uid, name, address, postal_code, city,
country_id, log, context=None): country_id, log, context=None):
''' '''
@@ -115,7 +119,8 @@ def get_partner(pool, cr, uid, name, address, postal_code, city,
key = name.lower() key = name.lower()
partners = [] partners = []
for partner in partner_obj.read( for partner in partner_obj.read(
cr, uid, partner_search_ids, ['name', 'commercial_partner_id'], context=context): cr, uid, partner_search_ids, ['name', 'commercial_partner_id'],
context=context):
if (len(partner['name']) > 3 and partner['name'].lower() in key): if (len(partner['name']) > 3 and partner['name'].lower() in key):
partners.append(partner) partners.append(partner)
partners.sort(key=lambda x: len(x['name']), reverse=True) partners.sort(key=lambda x: len(x['name']), reverse=True)
@@ -126,6 +131,7 @@ def get_partner(pool, cr, uid, name, address, postal_code, city,
'name %(name)s') % {'name': name}) 'name %(name)s') % {'name': name})
return partner_ids and partner_ids[0] or False return partner_ids and partner_ids[0] or False
def get_company_bank_account(pool, cr, uid, account_number, currency, def get_company_bank_account(pool, cr, uid, account_number, currency,
company, log): company, log):
''' '''
@@ -139,15 +145,15 @@ def get_company_bank_account(pool, cr, uid, account_number, currency,
return False return False
elif len(bank_accounts) != 1: elif len(bank_accounts) != 1:
log.append( log.append(
_('More than one bank account was found with the same number %(account_no)s') _('More than one bank account was found with the same number '
% dict(account_no = account_number) '%(account_no)s') % dict(account_no=account_number)
) )
return False return False
if bank_accounts[0].partner_id.id != company.partner_id.id: if bank_accounts[0].partner_id.id != company.partner_id.id:
log.append( log.append(
_('Account %(account_no)s is not owned by %(partner)s') _('Account %(account_no)s is not owned by %(partner)s')
% dict(account_no = account_number, % dict(account_no=account_number,
partner = company.partner_id.name, partner=company.partner_id.name,
)) ))
return False return False
results.account = bank_accounts[0] results.account = bank_accounts[0]
@@ -189,8 +195,9 @@ def get_company_bank_account(pool, cr, uid, account_number, currency,
return results return results
def get_or_create_bank(pool, cr, uid, bic, online=False, code=None, def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
name=None): name=None, context=None):
''' '''
Find or create the bank with the provided BIC code. Find or create the bank with the provided BIC code.
When online, the SWIFT database will be consulted in order to When online, the SWIFT database will be consulted in order to
@@ -231,30 +238,33 @@ def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
bank_id = False bank_id = False
if online: if online:
info, address = bank_obj.online_bank_info(cr, uid, bic, context=context) info, address = bank_obj.online_bank_info(
cr, uid, bic, context=context
)
if info: if info:
bank_id = bank_obj.create(cr, uid, dict( bank_id = bank_obj.create(cr, uid, dict(
code = info.code, code=info.code,
name = info.name, name=info.name,
street = address.street, street=address.street,
street2 = address.street2, street2=address.street2,
zip = address.zip, zip=address.zip,
city = address.city, city=address.city,
country = country_id, country=country_id,
bic = info.bic[:8], bic=info.bic[:8],
)) ))
else: else:
info = struct(name=name, code=code) info = struct(name=name, code=code)
if not online or not bank_id: if not online or not bank_id:
bank_id = bank_obj.create(cr, uid, dict( bank_id = bank_obj.create(cr, uid, dict(
code = info.code or 'UNKNOW', code=info.code or 'UNKNOW', # FIXME: Typo?
name = info.name or _('Unknown Bank'), name=info.name or _('Unknown Bank'),
country = country_id, country=country_id,
bic = bic, bic=bic,
)) ))
return bank_id, country_id return bank_id, country_id
def get_country_id(pool, cr, uid, transaction, context=None): def get_country_id(pool, cr, uid, transaction, context=None):
""" """
Derive a country id from the info on the transaction. Derive a country id from the info on the transaction.
@@ -283,6 +293,7 @@ def get_country_id(pool, cr, uid, transaction, context=None):
country_id = company.partner_id.country.id country_id = company.partner_id.country.id
return country_id return country_id
def create_bank_account(pool, cr, uid, partner_id, def create_bank_account(pool, cr, uid, partner_id,
account_number, holder_name, address, city, account_number, holder_name, address, city,
country_id, bic=False, country_id, bic=False,
@@ -291,9 +302,9 @@ def create_bank_account(pool, cr, uid, partner_id,
Create a matching bank account with this holder for this partner. Create a matching bank account with this holder for this partner.
''' '''
values = struct( values = struct(
partner_id = partner_id, partner_id=partner_id,
owner_name = holder_name, owner_name=holder_name,
country_id = country_id, country_id=country_id,
) )
# Are we dealing with IBAN? # Are we dealing with IBAN?
@@ -325,5 +336,3 @@ def create_bank_account(pool, cr, uid, partner_id,
# Create bank account and return # Create bank account and return
return pool.get('res.partner.bank').create( return pool.get('res.partner.bank').create(
cr, uid, values, context=context) cr, uid, values, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -24,6 +24,7 @@ from openerp.tools.translate import _
from openerp.addons.account_banking.wizard import banktools from openerp.addons.account_banking.wizard import banktools
import ast import ast
class link_partner(orm.TransientModel): class link_partner(orm.TransientModel):
_name = 'banking.link_partner' _name = 'banking.link_partner'
_description = 'Link partner' _description = 'Link partner'
@@ -205,5 +206,3 @@ class link_partner(orm.TransientModel):
'res_id': ids[0], 'res_id': ids[0],
'nodestroy': nodestroy, 'nodestroy': nodestroy,
} }