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
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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/>.
#
##############################################################################
import sepa
import record
import banking_import_transaction
@@ -33,5 +34,3 @@ import wizard
import res_partner
import res_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
+ local accounts are derived from SEPA (excluding Turkey) but are
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
communication with their customers.
+ National online databases can be used to convert BBAN's to IBAN's.

View File

@@ -86,11 +86,11 @@ class account_banking_account_settings(orm.Model):
string='Partner'),
'default_credit_account_id': fields.many2one(
'account.account', 'Default credit account', select=True,
help=('The account to use when an unexpected payment was signaled. '
'This can happen when a direct debit payment is cancelled '
help=('The account to use when an unexpected payment was signaled.'
' This can happen when a direct debit payment is cancelled '
'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
),
'default_debit_account_id': fields.many2one(
@@ -98,27 +98,27 @@ class account_banking_account_settings(orm.Model):
select=True, required=True,
help=('The account to use when an unexpected payment is received. '
'This can be needed when a customer pays in advance or when '
'no matching invoice can be found. Mind that you can correct '
'movements before confirming them.'
),
'no matching invoice can be found. Mind that you can '
'correct movements before confirming them.'
),
),
'costs_account_id': fields.many2one(
'account.account', 'Bank Costs Account', select=True,
help=('The account to use when the bank invoices its own costs. '
'Leave it blank to disable automatic invoice generation '
'on bank costs.'
),
),
),
'invoice_journal_id': fields.many2one(
'account.journal', 'Costs Journal',
help=('This is the journal used to create invoices for bank costs.'
),
),
),
'bank_partner_id': fields.many2one(
'res.partner', 'Bank Partner',
help=('The partner to use for bank costs. Banks are not partners '
'by default. You will most likely have to create one.'
),
),
),
}
@@ -196,7 +196,7 @@ class account_banking_account_settings(orm.Model):
values['journal_id'] = bank['journal_id'][0]
return {'value': values}
def onchange_company_id (
def onchange_company_id(
self, cr, uid, ids, company_id=False, context=None):
if not company_id:
return {}
@@ -229,37 +229,59 @@ class account_banking_imported_file(orm.Model):
_description = __doc__
_rec_name = 'date'
_columns = {
'company_id': fields.many2one('res.company', 'Company',
select=True, readonly=True
),
'date': fields.datetime('Import Date', readonly=True, select=True,
states={'draft': [('readonly', False)]}
),
'format': fields.char('File Format', size=20, readonly=True,
states={'draft': [('readonly', False)]}
),
'file': fields.binary('Raw Data', readonly=True,
states={'draft': [('readonly', False)]}
),
'file_name': fields.char('File name', size=256),
'log': fields.text('Import Log', readonly=True,
states={'draft': [('readonly', False)]}
),
'user_id': fields.many2one('res.users', 'Responsible User',
readonly=True, select=True,
states={'draft': [('readonly', False)]}
),
'state': fields.selection(
[('unfinished', 'Unfinished'),
('error', 'Error'),
('review', 'Review'),
('ready', 'Finished'),
], 'State', select=True, readonly=True
'company_id': fields.many2one(
'res.company',
'Company',
select=True,
readonly=True,
),
'date': fields.datetime(
'Import Date',
readonly=True,
select=True,
states={'draft': [('readonly', False)]},
),
'format': fields.char(
'File Format',
size=20,
readonly=True,
states={'draft': [('readonly', False)]},
),
'file': fields.binary(
'Raw Data',
readonly=True,
states={'draft': [('readonly', False)]},
),
'file_name': fields.char('File name', size=256),
'log': fields.text(
'Import Log',
readonly=True,
states={'draft': [('readonly', False)]},
),
'user_id': fields.many2one(
'res.users',
'Responsible User',
readonly=True,
select=True,
states={'draft': [('readonly', False)]},
),
'state': fields.selection(
[
('unfinished', 'Unfinished'),
('error', 'Error'),
('review', 'Review'),
('ready', 'Finished'),
],
'State',
select=True,
readonly=True,
),
'statement_ids': fields.one2many(
'account.bank.statement',
'banking_id',
'Statements',
readonly=False,
),
'statement_ids': fields.one2many('account.bank.statement',
'banking_id', 'Statements',
readonly=False,
),
}
_defaults = {
'date': fields.date.context_today,
@@ -284,11 +306,17 @@ class account_bank_statement(orm.Model):
_inherit = 'account.bank.statement'
_columns = {
'period_id': fields.many2one('account.period', 'Period',
required=False, readonly=True),
'banking_id': fields.many2one('account.banking.imported.file',
'Imported File', readonly=True,
),
'period_id': fields.many2one(
'account.period',
'Period',
required=False,
readonly=True,
),
'banking_id': fields.many2one(
'account.banking.imported.file',
'Imported File',
readonly=True,
),
}
_defaults = {
@@ -321,7 +349,7 @@ class account_bank_statement(orm.Model):
_constraints = [
(_check_company_id,
'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):
@@ -419,11 +447,12 @@ class account_bank_statement(orm.Model):
('account_id', '=', st_line.account_id.id)],
context=context)
account_move_line_obj.write(cr, uid, torec, {
(st_line.reconcile_id.line_partial_ids and
'reconcile_partial_id' or 'reconcile_id'):
st_line.reconcile_id.id }, context=context)
(st_line.reconcile_id.line_partial_ids
and 'reconcile_partial_id'
or 'reconcile_id'): st_line.reconcile_id.id
}, context=context)
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(
uid, 'account.move.line', move_line.id, cr)
return res
@@ -438,7 +467,7 @@ class account_bank_statement(orm.Model):
if ids and isinstance(ids, (int, long)):
ids = [ids]
noname_ids = self.search(
cr, uid, [('id', 'in', ids),('name', '=', '/')],
cr, uid, [('id', 'in', ids), ('name', '=', '/')],
context=context)
for st in self.browse(cr, uid, noname_ids, context=context):
if st.journal_id.sequence_id:
@@ -464,7 +493,7 @@ class account_voucher(orm.Model):
context = {}
if not context.get('period_id') and context.get('move_line_ids'):
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 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.
'''
res_users_obj = self.pool.get('res.users')
return res_users_obj.browse(cr, uid, uid,
context=context).company_id.currency_id.id
return res_users_obj.browse(
cr, uid, uid, context=context).company_id.currency_id.id
def _get_invoice_id(self, cr, uid, ids, name, args, context=None):
res = {}
@@ -519,36 +548,70 @@ class account_bank_statement_line(orm.Model):
_columns = {
# Redefines. Todo: refactor away to view attrs
'amount': fields.float('Amount', readonly=True,
digits_compute=dp.get_precision('Account'),
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)]}),
'amount': fields.float(
'Amount',
readonly=True,
digits_compute=dp.get_precision('Account'),
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,
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)]}),
'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)]},
),
'reconcile_id': fields.many2one(
'account.move.reconcile', 'Reconciliation', readonly=True
),
'account.move.reconcile',
'Reconciliation',
readonly=True,
),
'invoice_id': fields.function(
_get_invoice_id, method=True, string='Linked Invoice',
type='many2one', relation='account.invoice'
),
_get_invoice_id,
method=True,
string='Linked Invoice',
type='many2one',
relation='account.invoice',
),
}
_defaults = {
@@ -592,16 +655,14 @@ class invoice(orm.Model):
'''
return [('none', _('Free Reference')),
('structured', _('Structured Reference')),
]
]
_columns = {
'reference_type': fields.selection(_get_reference_type,
'Reference Type', required=True
)
)
}
invoice()
class account_move_line(orm.Model):
_inherit = "account.move.line"
@@ -617,9 +678,6 @@ class account_move_line(orm.Model):
if not ids:
return total
for line in self.read(
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)
return total
account_move_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,8 +5,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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:

View File

@@ -5,8 +5,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -29,14 +29,17 @@ try:
except AttributeError:
from mx import DateTime as datetime
def str2date(datestr, format='%d/%m/%y'):
'''Convert a string to a datatime object'''
return datetime.strptime(datestr, format)
def date2str(date, format='%Y-%m-%d'):
'''Convert a datetime object to a string'''
return date.strftime(format)
def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'):
'''
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)
_SWIFT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-?:().,'+ "
_SWIFT = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"/-?:().,'+ ")
def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']):
'''
@@ -62,7 +67,7 @@ def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']):
s = [x in _SWIFT and x or ' '
for x in unicodedata.normalize('NFKD', astr).encode('ascii', 'ignore')
]
]
return ''.join(s)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -22,6 +22,7 @@
import re
from openerp.tools.translate import _
class mem_bank_statement(object):
'''
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
__slots__ = [
'start_balance','end_balance', 'date', 'local_account',
'local_currency', 'id', 'transactions'
'start_balance',
'end_balance',
'date',
'local_account',
'local_currency',
'id',
'transactions'
]
def __init__(self, *args, **kwargs):
super(mem_bank_statement, self).__init__(*args, **kwargs)
self.id = ''
@@ -59,6 +66,7 @@ class mem_bank_statement(object):
check += float(transaction.transferred_amount)
return abs(check - float(self.end_balance)) < 0.0001
class mem_bank_transaction(object):
'''
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
'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',
# The other parties customer number
@@ -270,7 +279,7 @@ class mem_bank_transaction(object):
if value in self.types:
self.transfer_type = value
else:
raise ValueError, _('Invalid value for transfer_type')
raise ValueError(_('Invalid value for transfer_type'))
type = property(_get_type, _set_type)
@@ -282,6 +291,7 @@ class mem_bank_transaction(object):
return (self.execution_date and self.remote_account
and self.transferred_amount and True) or False
class parser_type(type):
'''
Meta annex factory class for house keeping and collecting parsers.
@@ -314,11 +324,13 @@ class parser_type(type):
keys.sort()
return [(parsers[x].code, parsers[x].name) for x in keys]
def create_parser(code):
if code in parser_type.parser_by_code:
return parser_type.parser_by_code[code]()
return None
class parser(object):
'''
A parser delivers the interface for any parser object. Inherit from
@@ -408,5 +420,3 @@ class parser(object):
raise NotImplementedError(
_('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
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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
try:
datetime.strptime
def strpdate(str, format):
return datetime.strptime(str, format).date()
except AttributeError:
import time
def strpdate(str, format):
tm = time.strptime(str, format)
return date(tm.tm_year, tm.tm_mon, tm.tm_mday)
import unicodedata
class Field(object):
'''Base Field class - fixed length left aligned string field in a record'''
def __init__(self, name, length=1, fillchar=' ', cast=str):
@@ -57,11 +60,14 @@ class Field(object):
def take(self, buffer):
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):
return '%s "%s"' % (self.__class__.__name__, self.name)
class Filler(Field):
'''Constant value field'''
def __init__(self, name, length=1, value=' '):
@@ -73,9 +79,10 @@ class Filler(Field):
def format(self, value):
return super(Filler, self).format(
self.value * (self.length / len(self.value) +1)
self.value * (self.length / len(self.value) + 1)
)
class DateField(Field):
'''Variable date field'''
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 self.auto and date.today() or None
class RightAlignedField(Field):
'''Deviation of Field: right aligned'''
def format(self, value):
@@ -107,7 +115,10 @@ class RightAlignedField(Field):
def take(self, buffer):
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):
'''Deviation of Field: left zero filled'''
@@ -118,6 +129,7 @@ class NumberField(RightAlignedField):
def format(self, value):
return super(NumberField, self).format(self.cast(value or ''))
class RecordType(object):
fields = []
@@ -130,7 +142,7 @@ class RecordType(object):
offset += field.length
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):
return any(lambda x, y=key: x.name == y, self.fields)
@@ -139,7 +151,7 @@ class RecordType(object):
for field in self.fields:
if field.name == key:
return field
raise KeyError, 'No such field: %s' % key
raise KeyError('No such field: %s' % key)
def format(self, buffer):
result = []
@@ -150,7 +162,8 @@ class RecordType(object):
def take(self, buffer):
return dict(zip([x.name for x in self.fields],
[x.take(buffer) for x in self.fields]
))
))
class Record(object):
_recordtype = None
@@ -159,7 +172,7 @@ class Record(object):
if hasattr(self, '_fields') and self._fields:
self._recordtype = RecordType(self._fields)
if not self._recordtype and not recordtype:
raise ValueError, 'No recordtype specified'
raise ValueError('No recordtype specified')
if not self._recordtype:
self._recordtype = recordtype()
self._length = len(self._recordtype)
@@ -173,9 +186,11 @@ class Record(object):
super(Record, self).__setattr__(attr, value)
else:
field = self._recordtype[attr]
self._value = self._value[:field.offset] + \
field.format(value) + \
self._value[field.offset + field.length:]
self._value = (
self._value[:field.offset] +
field.format(value) +
self._value[field.offset + field.length:]
)
def __getattr__(self, attr):
if attr.startswith('_'):
@@ -189,7 +204,6 @@ class Record(object):
def __unicode__(self):
return unicode(self.cast(self))
def asciify(str):
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']
def modulo_97_base10(abuffer):
'''
Calculate the modulo 97 value of a string in base10
@@ -55,6 +56,7 @@ def modulo_97_base10(abuffer):
checksum %= 97
return checksum
def base36_to_base10str(abuffer):
'''
Convert a base36 string value to a string of base10 digits.
@@ -67,6 +69,7 @@ def base36_to_base10str(abuffer):
result += digit
return result
class BBANFormat(object):
'''
A BBANFormat is an auxilliary class for IBAN. It represents the composition
@@ -178,6 +181,7 @@ class BBANFormat(object):
i += 1
return res
class IBAN(str):
'''
A IBAN string represents a SEPA bank account number. This class provides
@@ -272,7 +276,7 @@ class IBAN(str):
if item.isalnum():
init += item
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)
def __init__(self, *args, **kwargs):
@@ -287,8 +291,7 @@ class IBAN(str):
@classmethod
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
a BBAN from BBAN components before generation.
@@ -304,20 +307,17 @@ class IBAN(str):
if countrycode:
countrycode = countrycode.upper()
else:
raise ValueError, \
'Either BIC or countrycode is required'
raise ValueError('Either BIC or countrycode is required')
if countrycode not in cls.countries:
raise ValueError, \
'%s is not a SEPA country' % countrycode
raise ValueError('%s is not a SEPA country' % countrycode)
format = cls.BBAN_formats[countrycode]
if BBAN:
if len(BBAN) == len(format._iban):
ibanno = cls(countrycode + '00' + BBAN)
return cls(countrycode + ibanno.checksum + BBAN)
raise ValueError, \
'Insufficient data to generate IBAN'
raise ValueError('Insufficient data to generate IBAN')
@property
def valid(self):
@@ -325,8 +325,10 @@ class IBAN(str):
Check if the string + check digits deliver a valid checksum
'''
_buffer = self[4:] + self[:4]
return self.countrycode in self.countries and \
int(base36_to_base10str(_buffer)) % 97 == 1
return (
self.countrycode in self.countries
and int(base36_to_base10str(_buffer)) % 97 == 1
)
def __repr__(self):
'''
@@ -421,6 +423,7 @@ class IBAN(str):
'''
return self[4:]
class BBAN(object):
'''
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
formatted string
'''
i = 0; max_i = len(fmt._iban)
i = 0
max_i = len(fmt._iban)
while i < max_i:
if fmt._iban[i] == element:
next = i +1
next = i + 1
while next < max_i and fmt._iban[next] == element:
next += 1
return next - i
@@ -453,7 +457,10 @@ class BBAN(object):
if countrycode.upper() in IBAN.countries:
self._fmt = IBAN.BBAN_formats[countrycode.upper()]
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 bban[j] in ' \t' and j < max_j:
j += 1
@@ -512,15 +519,16 @@ class BBAN(object):
'''Simple check if BBAN is in the right format'''
return self._bban and True or False
if __name__ == '__main__':
import sys
for arg in sys.argv[1:]:
iban = IBAN(arg)
print 'IBAN:', iban
print 'country code:', iban.countrycode
print 'bank code:', iban.bankcode
print 'branch code:', iban.branchcode
print 'BBAN:', iban.BBAN
print 'localized BBAN:', iban.localized_BBAN
print 'check digits:', iban.checkdigits
print 'checksum:', iban.checksum
print('IBAN:', iban)
print('country code:', iban.countrycode)
print('bank code:', iban.bankcode)
print('branch code:', iban.branchcode)
print('BBAN:', iban.BBAN)
print('localized BBAN:', iban.localized_BBAN)
print('check digits:', iban.checkdigits)
print('checksum:', iban.checksum)

View File

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

View File

@@ -5,8 +5,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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/>.
#
##############################################################################
'''
Define a struct class which behaves like a dict, but allows using
object.attr alongside object['attr'].
@@ -25,6 +26,7 @@ object.attr alongside object['attr'].
__all__ = ['struct']
class struct(dict):
'''
Ease working with dicts. Allow dict.key alongside dict['key']
@@ -52,4 +54,4 @@ class struct(dict):
else:
fmt = '%*.*s%%s: %%s' % (indent, indent, '')
for item in self.iteritems():
print fmt % item
print(fmt % item)

View File

@@ -5,8 +5,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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/>.
#
##############################################################################
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
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -23,11 +23,13 @@
# Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes
# Stefan Rijnhart (Therp): bugreport and bugfix
#
'''
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
use parser.models as a mean of communication with the business logic.
'''
import base64
import datetime
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).
payment_window = datetime.timedelta(days=10)
def parser_types(*args, **kwargs):
'''Delay evaluation of parser types until start of wizard, to allow
depending modules to initialize and add their parsers to the list
@@ -57,18 +60,26 @@ class banking_import_line(orm.TransientModel):
_columns = {
'name': fields.char('Name', size=64),
'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(
'account.bank.statement.line',
'Resulting statement line', readonly=True),
'type': fields.selection([
('supplier','Supplier'),
('customer','Customer'),
('general','General')
('supplier', 'Supplier'),
('customer', 'Customer'),
('general', 'General')
], 'Type', required=True),
'partner_id': fields.many2one('res.partner', 'Partner'),
'statement_id': fields.many2one('account.bank.statement', 'Statement',
select=True, required=True, ondelete='cascade'),
'statement_id': fields.many2one(
'account.bank.statement',
'Statement',
select=True,
required=True,
ondelete='cascade',
),
'ref': fields.char('Reference', size=32),
'note': fields.text('Notes'),
'period_id': fields.many2one('account.period', 'Period'),
@@ -83,13 +94,16 @@ class banking_import_line(orm.TransientModel):
'account.invoice', 'banking_import_line_invoice_rel',
'line_id', 'invoice_id'),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
'transaction_type': fields.selection([
'transaction_type': fields.selection(
[
# TODO: payment terminal etc...
('invoice', 'Invoice payment'),
('storno', 'Canceled debit order'),
('bank_costs', 'Bank costs'),
('unknown', 'Unknown'),
], 'Transaction type'),
],
'Transaction type',
),
'duplicate': fields.boolean('Duplicate'),
}
@@ -119,7 +133,8 @@ class banking_import(orm.TransientModel):
if not parser:
raise orm.except_orm(
_('ERROR!'),
_('Unable to import parser %(parser)s. Parser class not found.') %
_('Unable to import parser %(parser)s. Parser class not '
'found.') %
{'parser': parser_code}
)
@@ -133,16 +148,17 @@ class banking_import(orm.TransientModel):
if any([x for x in statements if not x.is_valid()]):
raise orm.except_orm(
_('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
import_id = statement_file_obj.create(cr, uid, dict(
company_id = company.id,
file = statements_file,
file_name = banking_import.file_name,
state = 'unfinished',
format = parser.name,
company_id=company.id,
file=statements_file,
file_name=banking_import.file_name,
state='unfinished',
format=parser.name,
))
bank_country_code = False
@@ -151,14 +167,14 @@ class banking_import(orm.TransientModel):
# Results
results = struct(
stat_loaded_cnt = 0,
trans_loaded_cnt = 0,
stat_skipped_cnt = 0,
trans_skipped_cnt = 0,
trans_matched_cnt = 0,
bank_costs_invoice_cnt = 0,
error_cnt = 0,
log = [],
stat_loaded_cnt=0,
trans_loaded_cnt=0,
stat_skipped_cnt=0,
trans_skipped_cnt=0,
trans_matched_cnt=0,
bank_costs_invoice_cnt=0,
error_cnt=0,
log=[],
)
# Caching
@@ -175,7 +191,9 @@ class banking_import(orm.TransientModel):
continue
# 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
if statement.local_account in info and \
@@ -190,8 +208,10 @@ class banking_import(orm.TransientModel):
)
if not account_info:
results.log.append(
_('Statements found for unknown account %(bank_account)s') %
{'bank_account': statement.local_account}
_('Statements found for unknown account '
'%(bank_account)s') % {
'bank_account': statement.local_account
}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
@@ -200,7 +220,7 @@ class banking_import(orm.TransientModel):
results.log.append(
_('Statements found for account %(bank_account)s, '
'but no default journal was defined.'
) % {'bank_account': statement.local_account}
) % {'bank_account': statement.local_account}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
@@ -210,7 +230,7 @@ class banking_import(orm.TransientModel):
currency_code = account_info.currency_id.name
# Cache results
if not statement.local_account in info:
if statement.local_account not in info:
info[statement.local_account] = {
currency_code: account_info
}
@@ -224,10 +244,10 @@ class banking_import(orm.TransientModel):
results.log.append(
_('Statement %(statement_id)s for account %(bank_account)s'
' uses different currency than the defined bank journal.'
) % {
'bank_account': statement.local_account,
'statement_id': statement.id
}
) % {
'bank_account': statement.local_account,
'statement_id': statement.id
}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
@@ -251,7 +271,8 @@ class banking_import(orm.TransientModel):
)
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(
cr, uid, [
('company_id', '=', company.id),
@@ -272,17 +293,17 @@ class banking_import(orm.TransientModel):
# Create the bank statement record
statement_id = statement_obj.create(cr, uid, dict(
name = statement.id,
journal_id = account_info.journal_id.id,
date = convert.date2str(statement.date),
balance_start = statement.start_balance,
balance_end_real = statement.end_balance,
balance_end = statement.end_balance,
state = 'draft',
user_id = uid,
banking_id = import_id,
company_id = company.id,
period_id = period_ids[0],
name=statement.id,
journal_id=account_info.journal_id.id,
date=convert.date2str(statement.date),
balance_start=statement.start_balance,
balance_end_real=statement.end_balance,
balance_end=statement.end_balance,
state='draft',
user_id=uid,
banking_id=import_id,
company_id=company.id,
period_id=period_ids[0],
))
imported_statement_ids.append(statement_id)
@@ -294,7 +315,8 @@ class banking_import(orm.TransientModel):
values = {}
for attr in transaction.__slots__ + ['type']:
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:
values[attr] = eval('transaction.%s' % attr)
values['statement_id'] = statement_id
@@ -308,32 +330,14 @@ class banking_import(orm.TransientModel):
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(
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 = [
'%s: %s' % (_('Total number of statements'),
results.stat_skipped_cnt + results.stat_loaded_cnt),
@@ -360,15 +364,18 @@ class banking_import(orm.TransientModel):
text_log = '\n'.join(report + results.log)
state = results.error_cnt and 'error' or 'ready'
statement_file_obj.write(cr, uid, import_id, dict(
state = state, log = text_log,
), context)
state=state,
log=text_log,
), context)
if not imported_statement_ids or not results.trans_loaded_cnt:
# file state can be 'ready' while import state is 'error'
state = 'error'
self.write(cr, uid, [ids[0]], dict(
import_id = import_id, log = text_log, state = state,
statement_ids = [(6, 0, imported_statement_ids)],
), context)
import_id=import_id,
log=text_log,
state=state,
statement_ids=[(6, 0, imported_statement_ids)],
), context)
return {
'name': (state == 'ready' and _('Review Bank Statements') or
_('Error')),
@@ -393,13 +400,15 @@ class banking_import(orm.TransientModel):
),
'file_name': fields.char('File name', size=256),
'file': fields.binary(
'Statements File', required=True,
help = ('The Transactions File to import. Please note that while it is '
'perfectly safe to reload the same file multiple times or to load in '
'timeframe overlapping statements files, there are formats that may '
'introduce different sequencing, which may create double entries.\n\n'
'To stay on the safe side, always load bank statements files using the '
'same format.'),
'Statements File',
required=True,
help=('The Transactions File to import. Please note that while it '
'is perfectly safe to reload the same file multiple times '
'or to load in timeframe overlapping statements files, '
'there are formats that may introduce different '
'sequencing, which may create double entries.\n\n'
'To stay on the safe side, always load bank statements '
'files using the same format.'),
states={
'ready': [('readonly', True)],
'error': [('readonly', True)],
@@ -435,8 +444,8 @@ class banking_import(orm.TransientModel):
_defaults = {
'state': 'init',
'company': lambda s,cr,uid,c:
'company': lambda s, cr, uid, c:
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,
}

View File

@@ -7,8 +7,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -78,7 +78,7 @@ class banking_transaction_wizard(orm.TransientModel):
import_transaction_obj = self.pool.get('banking.import.transaction')
trans_id = self.read(
cr, uid, ids[0], ['import_transaction_id'],
context=context)['import_transaction_id'][0] # many2one tuple
context=context)['import_transaction_id'][0] # many2one tuple
import_transaction_obj.match(cr, uid, [trans_id], context=context)
return self.create_act_window(cr, uid, ids, context=None)
@@ -128,12 +128,17 @@ class banking_transaction_wizard(orm.TransientModel):
wiz.import_transaction_id.invoice_id):
transaction_obj.write(
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(
cr, uid, wiz.import_transaction_id.statement_line_id.id,
{ 'partner_id': move_line.partner_id.id or False,
'account_id': move_line.account_id.id,
}, context=context)
cr, uid,
wiz.import_transaction_id.statement_line_id.id,
{
'partner_id': (
move_line.partner_id.id or False),
'account_id': move_line.account_id.id,
}, context=context)
found = True
break
# Cannot match the invoice
@@ -150,15 +155,16 @@ class banking_transaction_wizard(orm.TransientModel):
# Rewrite *2many directive notation
if manual_invoice_ids:
manual_invoice_ids = (
[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]])
[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]])
if manual_move_line_ids:
manual_move_line_ids = (
[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]])
[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]])
for wiz in self.browse(cr, uid, ids, context=context):
#write can be called multiple times for the same values
#that doesn't hurt above, but it does here
# write can be called multiple times for the same values
# that doesn't hurt above, but it does here
if wiz.match_type and (
len(manual_move_line_ids) > 1 or
len(manual_invoice_ids) > 1):
@@ -171,7 +177,8 @@ class banking_transaction_wizard(orm.TransientModel):
found_move_line = False
if invoice.move_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))
found_move_line = True
break
@@ -181,12 +188,13 @@ class banking_transaction_wizard(orm.TransientModel):
_("No entry found for the selected invoice. "))
for move_line_id in manual_move_line_ids:
todo_entry = [False, move_line_id]
move_line=move_line_obj.read(
cr,
uid,
move_line_id,
['invoice'],
context=context)
move_line = move_line_obj.read(
cr,
uid,
move_line_id,
['invoice'],
context=context
)
if move_line['invoice']:
todo_entry[0] = move_line['invoice'][0]
todo.append(todo_entry)
@@ -194,25 +202,27 @@ class banking_transaction_wizard(orm.TransientModel):
while todo:
todo_entry = todo.pop()
move_line = move_line_obj.browse(
cr, uid, todo_entry[1], context)
cr, uid, todo_entry[1], context)
transaction_id = wiz.import_transaction_id.id
statement_line_id = wiz.statement_line_id.id
if len(todo) > 0:
statement_line_id = wiz.statement_line_id.split_off(
move_line.debit or -move_line.credit)[0]
move_line.debit or -move_line.credit)[0]
transaction_id = statement_line_obj.browse(
cr,
uid,
statement_line_id,
context=context).import_transaction_id.id
cr,
uid,
statement_line_id,
context=context
).import_transaction_id.id
vals = {
'move_line_id': todo_entry[1],
'move_line_ids': [(6, 0, [todo_entry[1]])],
'invoice_id': todo_entry[0],
'invoice_ids': [(6, 0,
[todo_entry[0]] if todo_entry[0] else [])],
'invoice_ids': [
(6, 0, [todo_entry[0]] if todo_entry[0] else [])
],
'match_type': 'manual',
}
@@ -255,22 +265,19 @@ class banking_transaction_wizard(orm.TransientModel):
# Get the bank account setting record, to reset the account
account_id = False
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
partner_id = False
if (wiz.statement_line_id.partner_bank_id and
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})
# 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
if 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})
if wiz.statement_line_id:
#delete splits causing an unsplit if this is a split
#transaction
statement_pool.unlink(cr, uid,
statement_pool.search(cr, uid,
[('parent_id', '=', wiz.statement_line_id.id)],
context=context),
context=context)
# delete splits causing an unsplit if this is a split
# transaction
statement_pool.unlink(
cr,
uid,
statement_pool.search(
cr, uid,
[('parent_id', '=', wiz.statement_line_id.id)],
context=context
),
context=context
)
if wiz.import_transaction_id:
wiz.import_transaction_id.clear_and_write()
@@ -313,8 +325,8 @@ class banking_transaction_wizard(orm.TransientModel):
ids = [ids]
transaction_obj = self.pool.get('banking.import.transaction')
for wiz in self.read(
cr, uid, ids, ['duplicate', 'import_transaction_id'],
context=context):
cr, uid, ids, ['duplicate', 'import_transaction_id'],
context=context):
transaction_obj.write(
cr, uid, wiz['import_transaction_id'][0],
{'duplicate': not wiz['duplicate']}, context=context)
@@ -363,8 +375,12 @@ class banking_transaction_wizard(orm.TransientModel):
'import_transaction_id', 'invoice_ids', string="Matching invoices",
type='many2many', relation='account.invoice'),
'invoice_id': fields.related(
'import_transaction_id', 'invoice_id', string="Invoice to reconcile",
type='many2one', relation='account.invoice'),
'import_transaction_id',
'invoice_id',
string="Invoice to reconcile",
type='many2one',
relation='account.invoice',
),
'move_line_ids': fields.related(
'import_transaction_id', 'move_line_ids', string="Entry lines",
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",
type='many2one', relation='account.move.line'),
'duplicate': fields.related(
'import_transaction_id', 'duplicate', string='Flagged as duplicate',
type='boolean'),
'import_transaction_id',
'duplicate',
string='Flagged as duplicate',
type='boolean',
),
'match_multi': fields.related(
'import_transaction_id', 'match_multi',
type="boolean", string='Multiple matches'),
'match_type': fields.related(
'import_transaction_id', 'match_type', type='selection',
'import_transaction_id',
'match_type',
type='selection',
selection=[
('move','Move'),
('move', 'Move'),
('invoice', 'Invoice'),
('payment', 'Payment line'),
('payment_order', 'Payment order'),
@@ -388,8 +409,10 @@ class banking_transaction_wizard(orm.TransientModel):
('manual', 'Manual'),
('payment_manual', 'Payment line (manual)'),
('payment_order_manual', 'Payment order (manual)'),
],
string='Match type', readonly=True),
],
string='Match type',
readonly=True,
),
'manual_invoice_ids': fields.many2many(
'account.invoice',
'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',
domain=[('account_id.reconcile', '=', True),
('reconcile_id', '=', False)]),
'payment_option': fields.related('import_transaction_id','payment_option', string='Payment Difference', type='selection', required=True,
selection=[('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')]),
'payment_option': fields.related(
'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(
'import_transaction_id', 'writeoff_analytic_id',
type='many2one', relation='account.analytic.account',
@@ -411,9 +443,11 @@ class banking_transaction_wizard(orm.TransientModel):
'statement_line_id', 'analytic_account_id',
type='many2one', relation='account.analytic.account',
string="Analytic Account"),
'move_currency_amount': fields.related('import_transaction_id','move_currency_amount',
type='float', string='Match Currency Amount', readonly=True),
}
banking_transaction_wizard()
'move_currency_amount': fields.related(
'import_transaction_id',
'move_currency_amount',
type='float',
string='Match Currency Amount',
readonly=True,
),
}

View File

@@ -5,8 +5,8 @@
# All Rights Reserved
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -32,6 +32,7 @@ __all__ = [
'create_bank_account',
]
def get_period(pool, cr, uid, date, company, log=None):
'''
Wrapper over account_period.find() to log exceptions of
@@ -43,7 +44,7 @@ def get_period(pool, cr, uid, date, company, log=None):
try:
period_ids = pool.get('account.period').find(
cr, uid, dt=date, context=context)
except Exception, e:
except Exception as e:
if log is None:
raise
else:
@@ -51,6 +52,7 @@ def get_period(pool, cr, uid, date, company, log=None):
return False
return period_ids[0]
def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
'''
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 partner_bank_obj.browse(cr, uid, bank_account_ids)
def _has_attr(obj, attr):
# Needed for dangling addresses and a weird exception scheme in
# OpenERP's orm.
@@ -80,6 +83,7 @@ def _has_attr(obj, attr):
except KeyError:
return False
def get_partner(pool, cr, uid, name, address, postal_code, city,
country_id, log, context=None):
'''
@@ -115,7 +119,8 @@ def get_partner(pool, cr, uid, name, address, postal_code, city,
key = name.lower()
partners = []
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):
partners.append(partner)
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})
return partner_ids and partner_ids[0] or False
def get_company_bank_account(pool, cr, uid, account_number, currency,
company, log):
'''
@@ -139,16 +145,16 @@ def get_company_bank_account(pool, cr, uid, account_number, currency,
return False
elif len(bank_accounts) != 1:
log.append(
_('More than one bank account was found with the same number %(account_no)s')
% dict(account_no = account_number)
_('More than one bank account was found with the same number '
'%(account_no)s') % dict(account_no=account_number)
)
return False
if bank_accounts[0].partner_id.id != company.partner_id.id:
log.append(
_('Account %(account_no)s is not owned by %(partner)s')
% dict(account_no = account_number,
partner = company.partner_id.name,
))
% dict(account_no=account_number,
partner=company.partner_id.name,
))
return False
results.account = bank_accounts[0]
bank_settings_obj = pool.get('account.banking.account.settings')
@@ -189,8 +195,9 @@ def get_company_bank_account(pool, cr, uid, account_number, currency,
return results
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.
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
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:
bank_id = bank_obj.create(cr, uid, dict(
code = info.code,
name = info.name,
street = address.street,
street2 = address.street2,
zip = address.zip,
city = address.city,
country = country_id,
bic = info.bic[:8],
code=info.code,
name=info.name,
street=address.street,
street2=address.street2,
zip=address.zip,
city=address.city,
country=country_id,
bic=info.bic[:8],
))
else:
info = struct(name=name, code=code)
if not online or not bank_id:
bank_id = bank_obj.create(cr, uid, dict(
code = info.code or 'UNKNOW',
name = info.name or _('Unknown Bank'),
country = country_id,
bic = bic,
code=info.code or 'UNKNOW', # FIXME: Typo?
name=info.name or _('Unknown Bank'),
country=country_id,
bic=bic,
))
return bank_id, country_id
def get_country_id(pool, cr, uid, transaction, context=None):
"""
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
return country_id
def create_bank_account(pool, cr, uid, partner_id,
account_number, holder_name, address, city,
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.
'''
values = struct(
partner_id = partner_id,
owner_name = holder_name,
country_id = country_id,
partner_id=partner_id,
owner_name=holder_name,
country_id=country_id,
)
# Are we dealing with IBAN?
@@ -325,5 +336,3 @@ def create_bank_account(pool, cr, uid, partner_id,
# Create bank account and return
return pool.get('res.partner.bank').create(
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
import ast
class link_partner(orm.TransientModel):
_name = 'banking.link_partner'
_description = 'Link partner'
@@ -160,8 +161,8 @@ class link_partner(orm.TransientModel):
wiz_read = self.read(
cr, uid, ids[0], context=context, load='_classic_write')
partner_vals = {
'type': 'default',
}
'type': 'default',
}
self.update_partner_values(
cr, uid, wiz_read, partner_vals, context=context)
partner_id = self.pool.get('res.partner').create(
@@ -205,5 +206,3 @@ class link_partner(orm.TransientModel):
'res_id': ids[0],
'nodestroy': nodestroy,
}