mirror of
https://github.com/OCA/account-reconcile.git
synced 2025-01-20 12:27:39 +02:00
[IMP] account_statement_base_import: Fix PEP8
This commit is contained in:
@@ -31,30 +31,34 @@
|
||||
],
|
||||
'description': """
|
||||
This module brings basic methods and fields on bank statement to deal with
|
||||
the importation of different bank and offices. A generic abstract method is defined and an
|
||||
example that gives you a basic way of importing bank statement through a standard file is provided.
|
||||
the importation of different bank and offices. A generic abstract method is
|
||||
defined and an example that gives you a basic way of importing bank statement
|
||||
through a standard file is provided.
|
||||
|
||||
This module improves the bank statement and allows you to import your bank transactions with
|
||||
a standard .csv or .xls file (you'll find it in the 'data' folder). It respects the profile
|
||||
(provided by the accouhnt_statement_ext module) to pass the entries. That means,
|
||||
you'll have to choose a file format for each profile.
|
||||
In order to achieve this it uses the `xlrd` Python module which you will need to install
|
||||
separately in your environment.
|
||||
This module improves the bank statement and allows you to import your bank
|
||||
transactions with a standard .csv or .xls file (you'll find it in the 'data'
|
||||
folder). It respects the profile (provided by the accouhnt_statement_ext
|
||||
module) to pass the entries. That means, you'll have to choose a file format
|
||||
for each profile.
|
||||
In order to achieve this it uses the `xlrd` Python module which you will need
|
||||
to install separately in your environment.
|
||||
|
||||
This module can handle a commission taken by the payment office and has the following format:
|
||||
This module can handle a commission taken by the payment office and has the
|
||||
following format:
|
||||
|
||||
* ref : the SO number, INV number or any matching ref found. It'll be used as reference
|
||||
in the generated entries and will be useful for reconciliation process
|
||||
* date : date of the payment
|
||||
* amount : amount paid in the currency of the journal used in the importation profile
|
||||
* label : the comunication given by the payment office, used as communication in the
|
||||
generated entries.
|
||||
|
||||
The goal is here to populate the statement lines of a bank statement with the infos that the
|
||||
bank or office give you. Fell free to inherit from this module to add your own format.Then,
|
||||
if you need to complete data from there, add your own account_statement_*_completion module and implement
|
||||
the needed rules.
|
||||
* __ref__: the SO number, INV number or any matching ref found. It'll be used
|
||||
as reference in the generated entries and will be useful for reconciliation
|
||||
process
|
||||
* __date__: date of the payment
|
||||
* __amount__: amount paid in the currency of the journal used in the
|
||||
importation profile
|
||||
* __label__: the comunication given by the payment office, used as
|
||||
communication in the generated entries.
|
||||
|
||||
The goal is here to populate the statement lines of a bank statement with the
|
||||
infos that the bank or office give you. Fell free to inherit from this module
|
||||
to add your own format. Then, if you need to complete data from there, add your
|
||||
own account_statement_*_completion module and implement the needed rules.
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': [
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv.osv import except_osv
|
||||
from openerp.osv.orm import except_orm
|
||||
import tempfile
|
||||
import datetime
|
||||
from parser import BankStatementImportParser
|
||||
@@ -36,25 +36,27 @@ def float_or_zero(val):
|
||||
|
||||
|
||||
class FileParser(BankStatementImportParser):
|
||||
|
||||
"""
|
||||
Generic abstract class for defining parser for .csv, .xls or .xlsx file format.
|
||||
"""Generic abstract class for defining parser for .csv, .xls or .xlsx file
|
||||
format.
|
||||
"""
|
||||
|
||||
def __init__(self, parse_name, ftype='csv', extra_fields=None, header=None, **kwargs):
|
||||
def __init__(self, parse_name, ftype='csv', extra_fields=None, header=None,
|
||||
**kwargs):
|
||||
"""
|
||||
:param char: parse_name: The name of the parser
|
||||
:param char: ftype: extension of the file (could be csv, xls or xlsx)
|
||||
:param dict: extra_fields: extra fields to add to the conversion dict. In the format
|
||||
{fieldname: fieldtype}
|
||||
:param list: header : specify header fields if the csv file has no header
|
||||
:param char: ftype: extension of the file (could be csv, xls or \
|
||||
xlsx)
|
||||
:param dict: extra_fields: extra fields to add to the conversion \
|
||||
dict. In the format {fieldname: fieldtype}
|
||||
:param list: header : specify header fields if the csv file has no \
|
||||
header
|
||||
"""
|
||||
|
||||
super(FileParser, self).__init__(parse_name, **kwargs)
|
||||
if ftype in ('csv', 'xls', 'xlsx'):
|
||||
self.ftype = ftype[0:3]
|
||||
else:
|
||||
raise except_osv(_('User Error'),
|
||||
raise except_orm(
|
||||
_('User Error'),
|
||||
_('Invalid file type %s. Please use csv, xls or xlsx') % ftype)
|
||||
self.conversion_dict = {
|
||||
'ref': unicode,
|
||||
@@ -71,23 +73,17 @@ class FileParser(BankStatementImportParser):
|
||||
# Set in _parse_xls, from the contents of the file
|
||||
|
||||
def _custom_format(self, *args, **kwargs):
|
||||
"""
|
||||
No other work on data are needed in this parser.
|
||||
"""
|
||||
"""No other work on data are needed in this parser."""
|
||||
return True
|
||||
|
||||
def _pre(self, *args, **kwargs):
|
||||
"""
|
||||
No pre-treatment needed for this parser.
|
||||
"""
|
||||
"""No pre-treatment needed for this parser."""
|
||||
return True
|
||||
|
||||
def _parse(self, *args, **kwargs):
|
||||
"""
|
||||
Launch the parsing through .csv, .xls or .xlsx depending on the
|
||||
"""Launch the parsing through .csv, .xls or .xlsx depending on the
|
||||
given ftype
|
||||
"""
|
||||
|
||||
res = None
|
||||
if self.ftype == 'csv':
|
||||
res = self._parse_csv()
|
||||
@@ -97,31 +93,27 @@ class FileParser(BankStatementImportParser):
|
||||
return True
|
||||
|
||||
def _validate(self, *args, **kwargs):
|
||||
"""
|
||||
We check that all the key of the given file (means header) are present
|
||||
in the validation key provided. Otherwise, we raise an Exception.
|
||||
We skip the validation step if the file header is provided separately
|
||||
(in the field: fieldnames).
|
||||
"""We check that all the key of the given file (means header) are
|
||||
present in the validation key provided. Otherwise, we raise an
|
||||
Exception. We skip the validation step if the file header is provided
|
||||
separately (in the field: fieldnames).
|
||||
"""
|
||||
if self.fieldnames is None:
|
||||
parsed_cols = self.result_row_list[0].keys()
|
||||
for col in self.keys_to_validate:
|
||||
if col not in parsed_cols:
|
||||
raise except_osv(_('Invalid data'),
|
||||
raise except_orm(_('Invalid data'),
|
||||
_('Column %s not present in file') % col)
|
||||
return True
|
||||
|
||||
def _post(self, *args, **kwargs):
|
||||
"""
|
||||
Cast row type depending on the file format .csv or .xls after parsing the file.
|
||||
"""
|
||||
"""Cast row type depending on the file format .csv or .xls after
|
||||
parsing the file."""
|
||||
self.result_row_list = self._cast_rows(*args, **kwargs)
|
||||
return True
|
||||
|
||||
def _parse_csv(self):
|
||||
"""
|
||||
:return: list of dict from csv file (line/rows)
|
||||
"""
|
||||
""":return: list of dict from csv file (line/rows)"""
|
||||
csv_file = tempfile.NamedTemporaryFile()
|
||||
csv_file.write(self.filebuffer)
|
||||
csv_file.flush()
|
||||
@@ -130,9 +122,7 @@ class FileParser(BankStatementImportParser):
|
||||
return list(reader)
|
||||
|
||||
def _parse_xls(self):
|
||||
"""
|
||||
:return: dict of dict from xls/xlsx file (line/rows)
|
||||
"""
|
||||
""":return: dict of dict from xls/xlsx file (line/rows)"""
|
||||
wb_file = tempfile.NamedTemporaryFile()
|
||||
wb_file.write(self.filebuffer)
|
||||
# We ensure that cursor is at beginig of file
|
||||
@@ -147,8 +137,7 @@ class FileParser(BankStatementImportParser):
|
||||
return res
|
||||
|
||||
def _from_csv(self, result_set, conversion_rules):
|
||||
"""
|
||||
Handle the converstion from the dict and handle date format from
|
||||
"""Handle the converstion from the dict and handle date format from
|
||||
an .csv file.
|
||||
"""
|
||||
for line in result_set:
|
||||
@@ -159,72 +148,60 @@ class FileParser(BankStatementImportParser):
|
||||
line[rule] = datetime.datetime.strptime(date_string,
|
||||
'%Y-%m-%d')
|
||||
except ValueError as err:
|
||||
raise except_osv(_("Date format is not valid."),
|
||||
raise except_orm(
|
||||
_("Date format is not valid."),
|
||||
_(" It should be YYYY-MM-DD for column: %s"
|
||||
" value: %s \n \n"
|
||||
" \n Please check the line with ref: %s"
|
||||
" \n \n Detail: %s") % (rule,
|
||||
line.get(
|
||||
rule, _('Missing')),
|
||||
line.get(
|
||||
'ref', line),
|
||||
repr(err)))
|
||||
" value: %s \n \n \n Please check the line with "
|
||||
"ref: %s \n \n Detail: %s") %
|
||||
(rule, line.get(rule, _('Missing')),
|
||||
line.get('ref', line), repr(err)))
|
||||
else:
|
||||
try:
|
||||
line[rule] = conversion_rules[rule](line[rule])
|
||||
except Exception as err:
|
||||
raise except_osv(_('Invalid data'),
|
||||
_("Value %s of column %s is not valid."
|
||||
"\n Please check the line with ref %s:"
|
||||
"\n \n Detail: %s") % (line.get(rule, _('Missing')),
|
||||
rule,
|
||||
line.get(
|
||||
'ref', line),
|
||||
repr(err)))
|
||||
raise except_orm(
|
||||
_('Invalid data'),
|
||||
_("Value %s of column %s is not valid.\n Please "
|
||||
"check the line with ref %s:\n \n Detail: %s") %
|
||||
(line.get(rule, _('Missing')), rule,
|
||||
line.get('ref', line), repr(err)))
|
||||
return result_set
|
||||
|
||||
def _from_xls(self, result_set, conversion_rules):
|
||||
"""
|
||||
Handle the converstion from the dict and handle date format from
|
||||
"""Handle the converstion from the dict and handle date format from
|
||||
an .csv, .xls or .xlsx file.
|
||||
"""
|
||||
for line in result_set:
|
||||
for rule in conversion_rules:
|
||||
if conversion_rules[rule] == datetime.datetime:
|
||||
try:
|
||||
t_tuple = xlrd.xldate_as_tuple(
|
||||
line[rule], self._datemode)
|
||||
t_tuple = xlrd.xldate_as_tuple(line[rule],
|
||||
self._datemode)
|
||||
line[rule] = datetime.datetime(*t_tuple)
|
||||
except Exception as err:
|
||||
raise except_osv(_("Date format is not valid"),
|
||||
raise except_orm(
|
||||
_("Date format is not valid"),
|
||||
_("Please modify the cell formatting to date format"
|
||||
" for column: %s"
|
||||
" value: %s"
|
||||
"\n Please check the line with ref: %s"
|
||||
"\n \n Detail: %s") % (rule,
|
||||
line.get(
|
||||
rule, _('Missing')),
|
||||
line.get(
|
||||
'ref', line),
|
||||
repr(err)))
|
||||
" for column: %s value: %s\n Please check the "
|
||||
"line with ref: %s\n \n Detail: %s") %
|
||||
(rule, line.get(rule, _('Missing')),
|
||||
line.get('ref', line), repr(err)))
|
||||
else:
|
||||
try:
|
||||
line[rule] = conversion_rules[rule](line[rule])
|
||||
except Exception as err:
|
||||
raise except_osv(_('Invalid data'),
|
||||
_("Value %s of column %s is not valid."
|
||||
"\n Please check the line with ref %s:"
|
||||
"\n \n Detail: %s") % (line.get(rule, _('Missing')),
|
||||
rule,
|
||||
line.get(
|
||||
'ref', line),
|
||||
repr(err)))
|
||||
raise except_orm(
|
||||
_('Invalid data'),
|
||||
_("Value %s of column %s is not valid.\n Please "
|
||||
"check the line with ref %s:\n \n Detail: %s") %
|
||||
(line.get(rule, _('Missing')), rule,
|
||||
line.get('ref', line), repr(err)))
|
||||
return result_set
|
||||
|
||||
def _cast_rows(self, *args, **kwargs):
|
||||
"""
|
||||
Convert the self.result_row_list using the self.conversion_dict providen.
|
||||
We call here _from_xls or _from_csv depending on the self.ftype variable.
|
||||
"""Convert the self.result_row_list using the self.conversion_dict
|
||||
providen. We call here _from_xls or _from_csv depending on the
|
||||
self.ftype variable.
|
||||
"""
|
||||
func = getattr(self, '_from_%s' % self.ftype)
|
||||
res = func(self.result_row_list, self.conversion_dict)
|
||||
|
||||
@@ -31,9 +31,7 @@ except:
|
||||
|
||||
|
||||
class GenericFileParser(FileParser):
|
||||
|
||||
"""
|
||||
Standard parser that use a define format in csv or xls to import into a
|
||||
"""Standard parser that use a define format in csv or xls to import into a
|
||||
bank statement. This is mostely an example of how to proceed to create a new
|
||||
parser, but will also be useful as it allow to import a basic flat file.
|
||||
"""
|
||||
@@ -44,8 +42,7 @@ class GenericFileParser(FileParser):
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
"""
|
||||
Used by the new_bank_statement_parser class factory. Return true if
|
||||
"""Used by the new_bank_statement_parser class factory. Return true if
|
||||
the providen name is generic_csvxls_so
|
||||
"""
|
||||
return parser_name == 'generic_csvxls_so'
|
||||
@@ -56,9 +53,10 @@ class GenericFileParser(FileParser):
|
||||
method of statement line in order to record it. It is the responsibility
|
||||
of every parser to give this dict of vals, so each one can implement his
|
||||
own way of recording the lines.
|
||||
:param: line: a dict of vals that represent a line of result_row_list
|
||||
:return: dict of values to give to the create method of statement line,
|
||||
it MUST contain at least:
|
||||
:param: line: a dict of vals that represent a line of \
|
||||
result_row_list
|
||||
:return: dict of values to give to the create method of statement \
|
||||
line, it MUST contain at least:
|
||||
{
|
||||
'name':value,
|
||||
'date':value,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
import base64
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
def UnicodeDictReader(utf8_data, **kwargs):
|
||||
@@ -31,7 +32,8 @@ def UnicodeDictReader(utf8_data, **kwargs):
|
||||
dialect = sniffer.sniff(sample_data, delimiters=',;\t')
|
||||
csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs)
|
||||
for row in csv_reader:
|
||||
yield dict([(key, unicode(value, 'utf-8')) for key, value in row.iteritems()])
|
||||
yield dict([(key, unicode(value, 'utf-8')) for key, value in
|
||||
row.iteritems()])
|
||||
|
||||
|
||||
class BankStatementImportParser(object):
|
||||
@@ -61,23 +63,19 @@ class BankStatementImportParser(object):
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
"""
|
||||
Override this method for every new parser, so that new_bank_statement_parser can
|
||||
return the good class from his name.
|
||||
"""Override this method for every new parser, so that
|
||||
new_bank_statement_parser can return the good class from his name.
|
||||
"""
|
||||
return False
|
||||
|
||||
def _decode_64b_stream(self):
|
||||
"""
|
||||
Decode self.filebuffer in base 64 and override it
|
||||
"""
|
||||
"""Decode self.filebuffer in base 64 and override it"""
|
||||
self.filebuffer = base64.b64decode(self.filebuffer)
|
||||
return True
|
||||
|
||||
def _format(self, decode_base_64=True, **kwargs):
|
||||
"""
|
||||
Decode into base 64 if asked and Format the given filebuffer by calling
|
||||
_custom_format method.
|
||||
"""Decode into base 64 if asked and Format the given filebuffer by
|
||||
calling _custom_format method.
|
||||
"""
|
||||
if decode_base_64:
|
||||
self._decode_64b_stream()
|
||||
@@ -85,44 +83,40 @@ class BankStatementImportParser(object):
|
||||
return True
|
||||
|
||||
def _custom_format(self, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser to convert format, encoding and so on before
|
||||
starting to work on datas. Work on self.filebuffer
|
||||
"""Implement a method in your parser to convert format, encoding and so
|
||||
on before starting to work on datas. Work on self.filebuffer
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def _pre(self, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser to make a pre-treatment on datas before parsing
|
||||
them, like concatenate stuff, and so... Work on self.filebuffer
|
||||
"""Implement a method in your parser to make a pre-treatment on datas
|
||||
before parsing them, like concatenate stuff, and so... Work on
|
||||
self.filebuffer
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def _parse(self, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser to save the result of parsing self.filebuffer
|
||||
in self.result_row_list instance property.
|
||||
"""Implement a method in your parser to save the result of parsing
|
||||
self.filebuffer in self.result_row_list instance property.
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def _validate(self, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser to validate the self.result_row_list instance
|
||||
property and raise an error if not valid.
|
||||
"""Implement a method in your parser to validate the
|
||||
self.result_row_list instance property and raise an error if not valid.
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def _post(self, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser to make some last changes on the result of parsing
|
||||
the datas, like converting dates, computing commission, ...
|
||||
"""Implement a method in your parser to make some last changes on the
|
||||
result of parsing the datas, like converting dates, computing
|
||||
commission, ...
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def get_st_vals(self):
|
||||
"""
|
||||
This method return a dict of vals that ca be passed to
|
||||
create method of statement.
|
||||
"""This method return a dict of vals that ca be passed to create method
|
||||
of statement.
|
||||
:return: dict of vals that represent additional infos for the statement
|
||||
"""
|
||||
return {
|
||||
@@ -133,13 +127,13 @@ class BankStatementImportParser(object):
|
||||
}
|
||||
|
||||
def get_st_line_vals(self, line, *args, **kwargs):
|
||||
"""
|
||||
Implement a method in your parser that must return a dict of vals that can be
|
||||
passed to create method of statement line in order to record it. It is the responsibility
|
||||
of every parser to give this dict of vals, so each one can implement his
|
||||
own way of recording the lines.
|
||||
"""Implement a method in your parser that must return a dict of vals
|
||||
that can be passed to create method of statement line in order to record
|
||||
it. It is the responsibility of every parser to give this dict of vals,
|
||||
so each one can implement his own way of recording the lines.
|
||||
|
||||
:param: line: a dict of vals that represent a line of result_row_list
|
||||
:return: dict of values to give to the create method of statement line,
|
||||
:return: dict of values to give to the create method of statement line,\
|
||||
it MUST contain at least:
|
||||
{
|
||||
'name':value,
|
||||
@@ -151,15 +145,14 @@ class BankStatementImportParser(object):
|
||||
return NotImplementedError
|
||||
|
||||
def parse(self, filebuffer, *args, **kwargs):
|
||||
"""
|
||||
This will be the method that will be called by wizard, button and so
|
||||
"""This will be the method that will be called by wizard, button and so
|
||||
to parse a filebuffer by calling successively all the private method
|
||||
that need to be define for each parser.
|
||||
Return:
|
||||
[] of rows as {'key':value}
|
||||
|
||||
Note: The row_list must contain only value that are present in the account.
|
||||
bank.statement.line object !!!
|
||||
Note: The row_list must contain only value that are present in the
|
||||
account.bank.statement.line object !!!
|
||||
"""
|
||||
if filebuffer:
|
||||
self.filebuffer = filebuffer
|
||||
|
||||
@@ -20,16 +20,14 @@
|
||||
##############################################################################
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from openerp.tools.translate import _
|
||||
import datetime
|
||||
from openerp.osv.orm import Model
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.osv import fields, orm
|
||||
from parser import new_bank_statement_parser
|
||||
from openerp.tools.config import config
|
||||
|
||||
|
||||
class AccountStatementProfil(Model):
|
||||
class AccountStatementProfil(orm.Model):
|
||||
_inherit = "account.statement.profile"
|
||||
|
||||
def _get_import_type_selection(self, cr, uid, context=None):
|
||||
@@ -62,52 +60,51 @@ class AccountStatementProfil(Model):
|
||||
}
|
||||
|
||||
def _write_extra_statement_lines(
|
||||
self, cr, uid, parser, result_row_list, profile, statement_id, context):
|
||||
self, cr, uid, parser, result_row_list, profile, statement_id,
|
||||
context):
|
||||
"""Insert extra lines after the main statement lines.
|
||||
|
||||
After the main statement lines have been created, you can override this method to create
|
||||
extra statement lines.
|
||||
After the main statement lines have been created, you can override this
|
||||
method to create extra statement lines.
|
||||
|
||||
:param: browse_record of the current parser
|
||||
:param: result_row_list: [{'key':value}]
|
||||
:param: profile: browserecord of account.statement.profile
|
||||
:param: statement_id: int/long of the current importing statement ID
|
||||
:param: statement_id: int/long of the current importing \
|
||||
statement ID
|
||||
:param: context: global context
|
||||
"""
|
||||
pass
|
||||
|
||||
def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines, context):
|
||||
"""
|
||||
Write the log in the logger
|
||||
def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines,
|
||||
context):
|
||||
"""Write the log in the logger
|
||||
|
||||
:param int/long statement_id: ID of the concerned account.bank.statement
|
||||
:param int/long num_lines: Number of line that have been parsed
|
||||
:return: True
|
||||
"""
|
||||
self.message_post(cr,
|
||||
uid,
|
||||
ids,
|
||||
body=_('Statement ID %s have been imported with %s lines.') %
|
||||
(statement_id, num_lines),
|
||||
context=context)
|
||||
self.message_post(
|
||||
cr, uid, ids,
|
||||
body=_('Statement ID %s have been imported with %s '
|
||||
'lines.') % (statement_id, num_lines), context=context)
|
||||
return True
|
||||
|
||||
# Deprecated remove on V8
|
||||
def prepare_statetement_lines_vals(self, *args, **kwargs):
|
||||
return self.prepare_statement_lines_vals(*args, **kwargs)
|
||||
|
||||
def prepare_statement_lines_vals(
|
||||
self, cr, uid, parser_vals,
|
||||
def prepare_statement_lines_vals(self, cr, uid, parser_vals,
|
||||
statement_id, context):
|
||||
"""
|
||||
Hook to build the values of a line from the parser returned values. At
|
||||
least it fullfill the statement_id. Overide it to add your
|
||||
own completion if needed.
|
||||
"""Hook to build the values of a line from the parser returned values.
|
||||
At least it fullfill the statement_id. Overide it to add your own
|
||||
completion if needed.
|
||||
|
||||
:param dict of vals from parser for account.bank.statement.line (called by
|
||||
parser.get_st_line_vals)
|
||||
:param dict of vals from parser for account.bank.statement.line \
|
||||
(called by parser.get_st_line_vals)
|
||||
:param int/long statement_id: ID of the concerned account.bank.statement
|
||||
:return: dict of vals that will be passed to create method of statement line.
|
||||
:return: dict of vals that will be passed to create method of \
|
||||
statement line.
|
||||
"""
|
||||
statement_line_obj = self.pool['account.bank.statement.line']
|
||||
values = parser_vals
|
||||
@@ -121,10 +118,8 @@ class AccountStatementProfil(Model):
|
||||
values['period_id'] = period_memoizer[date]
|
||||
else:
|
||||
# This is awfully slow...
|
||||
periods = self.pool.get('account.period').find(cr, uid,
|
||||
dt=values.get(
|
||||
'date'),
|
||||
context=context)
|
||||
periods = self.pool.get('account.period').find(
|
||||
cr, uid, dt=values.get('date'), context=context)
|
||||
values['period_id'] = periods[0]
|
||||
period_memoizer[date] = periods[0]
|
||||
values = statement_line_obj._add_missing_default_values(
|
||||
@@ -133,8 +128,7 @@ class AccountStatementProfil(Model):
|
||||
|
||||
def prepare_statement_vals(self, cr, uid, profile_id, result_row_list,
|
||||
parser, context=None):
|
||||
"""
|
||||
Hook to build the values of the statement from the parser and
|
||||
"""Hook to build the values of the statement from the parser and
|
||||
the profile.
|
||||
"""
|
||||
vals = {'profile_id': profile_id}
|
||||
@@ -151,9 +145,8 @@ class AccountStatementProfil(Model):
|
||||
|
||||
def multi_statement_import(self, cr, uid, ids, profile_id, file_stream,
|
||||
ftype="csv", context=None):
|
||||
"""
|
||||
Create multiple bank statements from values given by the parser for the
|
||||
givenprofile.
|
||||
"""Create multiple bank statements from values given by the parser for
|
||||
the given profile.
|
||||
|
||||
:param int/long profile_id: ID of the profile used to import the file
|
||||
:param filebuffer file_stream: binary of the providen file
|
||||
@@ -162,23 +155,26 @@ class AccountStatementProfil(Model):
|
||||
"""
|
||||
prof_obj = self.pool['account.statement.profile']
|
||||
if not profile_id:
|
||||
raise osv.except_osv(_("No Profile!"),
|
||||
_("You must provide a valid profile to import a bank statement!"))
|
||||
raise orm.except_orm(
|
||||
_("No Profile!"),
|
||||
_("You must provide a valid profile to import a bank "
|
||||
"statement!"))
|
||||
prof = prof_obj.browse(cr, uid, profile_id, context=context)
|
||||
|
||||
parser = new_bank_statement_parser(prof, ftype=ftype)
|
||||
res = []
|
||||
for result_row_list in parser.parse(file_stream):
|
||||
statement_id = self._statement_import(cr, uid, ids, prof, parser,
|
||||
file_stream, ftype=ftype, context=context)
|
||||
statement_id = self._statement_import(
|
||||
cr, uid, ids, prof, parser, file_stream, ftype=ftype,
|
||||
context=context)
|
||||
res.append(statement_id)
|
||||
return res
|
||||
|
||||
def _statement_import(self, cr, uid, ids, prof, parser, file_stream, ftype="csv", context=None):
|
||||
"""
|
||||
Create a bank statement with the given profile and parser. It will fullfill the bank statement
|
||||
with the values of the file providen, but will not complete data (like finding the partner, or
|
||||
the right account). This will be done in a second step with the completion rules.
|
||||
def _statement_import(self, cr, uid, ids, prof, parser, file_stream,
|
||||
ftype="csv", context=None):
|
||||
"""Create a bank statement with the given profile and parser. It will
|
||||
fullfill the bank statement with the values of the file providen, but
|
||||
will not complete data (like finding the partner, or the right account).
|
||||
This will be done in a second step with the completion rules.
|
||||
|
||||
:param prof : The profile used to import the file
|
||||
:param parser: the parser
|
||||
@@ -186,28 +182,25 @@ class AccountStatementProfil(Model):
|
||||
:param char: ftype represent the file exstension (csv by default)
|
||||
:return: ID of the created account.bank.statemênt
|
||||
"""
|
||||
statement_obj = self.pool.get('account.bank.statement')
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
attachment_obj = self.pool.get('ir.attachment')
|
||||
|
||||
statement_obj = self.pool['account.bank.statement']
|
||||
statement_line_obj = self.pool['account.bank.statement.line']
|
||||
attachment_obj = self.pool['ir.attachment']
|
||||
result_row_list = parser.result_row_list
|
||||
# Check all key are present in account.bank.statement.line!!
|
||||
if not result_row_list:
|
||||
raise osv.except_osv(_("Nothing to import"),
|
||||
raise orm.except_orm(_("Nothing to import"),
|
||||
_("The file is empty"))
|
||||
parsed_cols = parser.get_st_line_vals(result_row_list[0]).keys()
|
||||
for col in parsed_cols:
|
||||
if col not in statement_line_obj._columns:
|
||||
raise osv.except_osv(_("Missing column!"),
|
||||
_("Column %s you try to import is not "
|
||||
"present in the bank statement line!") % col)
|
||||
|
||||
raise orm.except_orm(
|
||||
_("Missing column!"),
|
||||
_("Column %s you try to import is not present in the bank "
|
||||
"statement line!") % col)
|
||||
statement_vals = self.prepare_statement_vals(
|
||||
cr, uid, prof.id, result_row_list, parser, context)
|
||||
statement_id = statement_obj.create(cr, uid,
|
||||
statement_vals,
|
||||
context=context)
|
||||
|
||||
statement_id = statement_obj.create(
|
||||
cr, uid, statement_vals, context=context)
|
||||
try:
|
||||
# Record every line in the bank statement
|
||||
statement_store = []
|
||||
@@ -220,7 +213,6 @@ class AccountStatementProfil(Model):
|
||||
# Hack to bypass ORM poor perfomance. Sob...
|
||||
statement_line_obj._insert_lines(
|
||||
cr, uid, statement_store, context=context)
|
||||
|
||||
self._write_extra_statement_lines(
|
||||
cr, uid, parser, result_row_list, prof, statement_id, context)
|
||||
# Trigger store field computation if someone has better idea
|
||||
@@ -229,27 +221,24 @@ class AccountStatementProfil(Model):
|
||||
start_bal = start_bal['balance_start']
|
||||
statement_obj.write(
|
||||
cr, uid, [statement_id], {'balance_start': start_bal})
|
||||
|
||||
attachment_data = {
|
||||
'name': 'statement file',
|
||||
'datas': file_stream,
|
||||
'datas_fname': "%s.%s" % (datetime.datetime.now().date(), ftype),
|
||||
'datas_fname': "%s.%s" % (datetime.datetime.now().date(),
|
||||
ftype),
|
||||
'res_model': 'account.bank.statement',
|
||||
'res_id': statement_id,
|
||||
}
|
||||
attachment_obj.create(cr, uid, attachment_data, context=context)
|
||||
|
||||
# If user ask to launch completion at end of import, do it!
|
||||
if prof.launch_import_completion:
|
||||
statement_obj.button_auto_completion(
|
||||
cr, uid, [statement_id], context)
|
||||
|
||||
# Write the needed log infos on profile
|
||||
self.write_logs_after_import(cr, uid, prof.id,
|
||||
statement_id,
|
||||
len(result_row_list),
|
||||
context)
|
||||
|
||||
except Exception:
|
||||
error_type, error_value, trbk = sys.exc_info()
|
||||
st = "Error: %s\nDescription: %s\nTraceback:" % (
|
||||
@@ -260,6 +249,6 @@ class AccountStatementProfil(Model):
|
||||
# For now we avoid re-catching error in debug mode
|
||||
if config['debug_mode']:
|
||||
raise
|
||||
raise osv.except_osv(_("Statement import error"),
|
||||
raise orm.except_orm(_("Statement import error"),
|
||||
_("The statement cannot be created: %s") % st)
|
||||
return statement_id
|
||||
|
||||
@@ -22,11 +22,10 @@
|
||||
import base64
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
class test_coda_import(common.TransactionCase):
|
||||
class TestCodaImport(common.TransactionCase):
|
||||
|
||||
def prepare(self):
|
||||
self.company_a = self.browse_ref('base.main_company')
|
||||
@@ -36,7 +35,6 @@ class test_coda_import(common.TransactionCase):
|
||||
# create the 2009 fiscal year since imported coda file reference
|
||||
# statement lines in 2009
|
||||
self.fiscalyear_id = self._create_fiscalyear("2011", self.company_a.id)
|
||||
|
||||
self.account_id = self.ref("account.a_recv")
|
||||
self.journal_id = self.ref("account.bank_journal")
|
||||
self.import_wizard_obj = self.registry('credit.statement.import')
|
||||
@@ -77,7 +75,8 @@ class test_coda_import(common.TransactionCase):
|
||||
self.cr, self.uid, wizard_id)
|
||||
statement_id = self.account_bank_statement_obj.search(
|
||||
self.cr, self.uid, eval(res['domain']))
|
||||
return self.account_bank_statement_obj.browse(self.cr, self.uid, statement_id)[0]
|
||||
return self.account_bank_statement_obj.browse(
|
||||
self.cr, self.uid, statement_id)[0]
|
||||
|
||||
def test_simple_xls(self):
|
||||
"""Test import from xls
|
||||
|
||||
@@ -36,7 +36,8 @@ class CreditPartnerStatementImporter(orm.TransientModel):
|
||||
if context is None:
|
||||
context = {}
|
||||
res = {}
|
||||
if (context.get('active_model', False) == 'account.statement.profile' and
|
||||
if (context.get('active_model', False) ==
|
||||
'account.statement.profile' and
|
||||
context.get('active_ids', False)):
|
||||
ids = context['active_ids']
|
||||
assert len(
|
||||
@@ -57,8 +58,8 @@ class CreditPartnerStatementImporter(orm.TransientModel):
|
||||
'journal_id': fields.many2one('account.journal',
|
||||
'Financial journal to use transaction'),
|
||||
'file_name': fields.char('File Name', size=128),
|
||||
'receivable_account_id': fields.many2one('account.account',
|
||||
'Force Receivable/Payable Account'),
|
||||
'receivable_account_id': fields.many2one(
|
||||
'account.account', 'Force Receivable/Payable Account'),
|
||||
'force_partner_on_bank': fields.boolean(
|
||||
'Force partner on bank move',
|
||||
help="Tic that box if you want to use the credit insitute partner "
|
||||
@@ -73,12 +74,12 @@ class CreditPartnerStatementImporter(orm.TransientModel):
|
||||
def onchange_profile_id(self, cr, uid, ids, profile_id, context=None):
|
||||
res = {}
|
||||
if profile_id:
|
||||
c = self.pool.get("account.statement.profile").browse(
|
||||
c = self.pool["account.statement.profile"].browse(
|
||||
cr, uid, profile_id, context=context)
|
||||
res = {'value':
|
||||
{'partner_id': c.partner_id and c.partner_id.id or False,
|
||||
'journal_id': c.journal_id and c.journal_id.id or False,
|
||||
'receivable_account_id': c.receivable_account_id and c.receivable_account_id.id or False,
|
||||
'receivable_account_id': c.receivable_account_id.id,
|
||||
'force_partner_on_bank': c.force_partner_on_bank,
|
||||
'balance_check': c.balance_check,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user