[MOV] move addons out of __unported__ (they remain not installable)

This commit is contained in:
Stéphane Bidoul
2015-10-13 16:29:29 +02:00
parent 17726e11a4
commit fe4f640ca8
187 changed files with 21 additions and 21 deletions

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import parser
from . import wizard
from . import statement

View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{'name': "Bank statement base import",
'version': '1.2',
'author': "Camptocamp,Odoo Community Association (OCA)",
'maintainer': 'Camptocamp',
'category': 'Finance',
'complexity': 'normal',
'depends': [
'account_statement_ext',
'account_statement_base_completion'
],
'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.
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:
* __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': [
"wizard/import_statement_view.xml",
"statement_view.xml",
],
'test': [],
'installable': False,
'images': [],
'auto_install': False,
'license': 'AGPL-3',
}

View File

@@ -0,0 +1,4 @@
"ref";"date";"amount";"commission_amount";"label"
50969286;2011-03-07 13:45:14;118.4;-11.84;"label a"
51065326;2011-03-02 13:45:14;189;-15.12;"label b"
51179306;2011-03-02 17:45:14;189;-15.12;"label c"
1 ref date amount commission_amount label
2 50969286 2011-03-07 13:45:14 118.4 -11.84 label a
3 51065326 2011-03-02 13:45:14 189 -15.12 label b
4 51179306 2011-03-02 17:45:14 189 -15.12 label c

Binary file not shown.

View File

@@ -0,0 +1,289 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_statement_base_import
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-21 11:58+0000\n"
"PO-Revision-Date: 2014-01-21 11:58+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_statement_base_import
#: view:credit.statement.import:0
#: model:ir.actions.act_window,name:account_statement_base_import.statement_importer_action
msgid "Import statement"
msgstr ""
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Historical Import Logs"
msgstr ""
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_credit_statement_import
msgid "credit.statement.import"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,input_statement:0
msgid "Statement file"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:168
#, python-format
msgid "Column %s you try to import is not present in the bank statement line!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:162
#, python-format
msgid "Nothing to import"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,journal_id:0
msgid "Financial journal to use transaction"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:108
#, python-format
msgid "Column %s not present in file"
msgstr ""
#. module: account_statement_base_import
#: view:account.statement.profile:0
#: model:ir.ui.menu,name:account_statement_base_import.statement_importer_menu
msgid "Import Bank Statement"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:54
#, python-format
msgid "User Error"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:223
#, python-format
msgid "The statement cannot be created: %s"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:167
#, python-format
msgid "Missing column!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/parser.py:150
#, python-format
msgid "No buffer file given."
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:107
#: code:addons/account_statement_base_import/parser/file_parser.py:171
#: code:addons/account_statement_base_import/parser/file_parser.py:205
#, python-format
msgid "Invalid data"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,launch_import_completion:0
msgid "Launch completion after import"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,partner_id:0
msgid "Credit insitute partner"
msgstr ""
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Import related infos"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:163
#, python-format
msgid "The file is empty"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/wizard/import_statement.py:90
#, python-format
msgid "Please use a file with an extention"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:172
#: code:addons/account_statement_base_import/parser/file_parser.py:206
#, python-format
msgid "Value %s of column %s is not valid.\n"
" Please check the line with ref %s:\n"
" \n"
" Detail: %s"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:29
#: code:addons/account_statement_base_import/parser/generic_file_parser.py:30
#, python-format
msgid "Please install python lib xlrd"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:160
#, python-format
msgid " 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"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,last_import_date:0
msgid "Last Import Date"
msgstr ""
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_account_statement_profile
msgid "Statement Profile"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:222
#, python-format
msgid "Statement import error"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:193
#, python-format
msgid "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"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:192
#, python-format
msgid "Date format is not valid"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,import_type:0
msgid "Type of import"
msgstr ""
#. module: account_statement_base_import
#: help:account.statement.profile,launch_import_completion:0
msgid "Tic that box to automatically launch the completion on each imported file using this profile."
msgstr ""
#. module: account_statement_base_import
#: help:credit.statement.import,balance_check:0
msgid "Tic that box if you want OpenERP to control the start/end balance before confirming a bank statement. If don't ticked, no balance control will be done."
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:154
#, python-format
msgid "No Profile!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:159
#, python-format
msgid "Date format is not valid."
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,profile_id:0
msgid "Import configuration parameter"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,rec_log:0
msgid "log"
msgstr ""
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Import Parameters Summary"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,balance_check:0
msgid "Balance check"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,force_partner_on_bank:0
msgid "Force partner on bank move"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,file_name:0
msgid "File Name"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:55
#, python-format
msgid "Invalid file type %s. Please use csv or xls"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:155
#, python-format
msgid "You must provide a valid profile to import a bank statement!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:83
#, python-format
msgid "Statement ID %s have been imported with %s lines."
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,receivable_account_id:0
msgid "Force Receivable/Payable Account"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:164
#: code:addons/account_statement_base_import/parser/file_parser.py:174
#: code:addons/account_statement_base_import/parser/file_parser.py:198
#: code:addons/account_statement_base_import/parser/file_parser.py:208
#, python-format
msgid "Missing"
msgstr ""
#. module: account_statement_base_import
#: help:account.statement.profile,import_type:0
msgid "Choose here the method by which you want to import bank statement for this profile."
msgstr ""
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Cancel"
msgstr ""
#. module: account_statement_base_import
#: help:credit.statement.import,force_partner_on_bank:0
msgid "Tic that box if you want to use the credit insitute partner in the counterpart of the treasury/banking move."
msgstr ""

View File

@@ -0,0 +1,329 @@
# Spanish translation for banking-addons
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the banking-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: banking-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2014-01-21 11:58+0000\n"
"PO-Revision-Date: 2014-06-05 22:11+0000\n"
"Last-Translator: Pedro Manuel Baeza <pedro.baeza@gmail.com>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-06-06 06:36+0000\n"
"X-Generator: Launchpad (build 17031)\n"
#. module: account_statement_base_import
#: view:credit.statement.import:0
#: model:ir.actions.act_window,name:account_statement_base_import.statement_importer_action
msgid "Import statement"
msgstr "Importar extracto"
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Historical Import Logs"
msgstr "Registro histórico de importaciones"
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_credit_statement_import
msgid "credit.statement.import"
msgstr "credit.statement.import"
#. module: account_statement_base_import
#: field:credit.statement.import,input_statement:0
msgid "Statement file"
msgstr "Archivo de extracto"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:168
#, python-format
msgid ""
"Column %s you try to import is not present in the bank statement line!"
msgstr ""
"La columna %s que intenta importar no está presente en la línea del extracto "
"bancario."
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:162
#, python-format
msgid "Nothing to import"
msgstr "Nada que importar"
#. module: account_statement_base_import
#: field:credit.statement.import,journal_id:0
msgid "Financial journal to use transaction"
msgstr "Diario contable a usar"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:102
#, python-format
msgid "Column %s not present in file"
msgstr "La columna %s no está presente en el archivo"
#. module: account_statement_base_import
#: view:account.statement.profile:0
#: model:ir.ui.menu,name:account_statement_base_import.statement_importer_menu
msgid "Import Bank Statement"
msgstr "Importar extracto bancario"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:54
#, python-format
msgid "User Error"
msgstr "Error de usuario"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:223
#, python-format
msgid "The statement cannot be created: %s"
msgstr "El extracto no puede ser creado: %s"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:167
#, python-format
msgid "Missing column!"
msgstr "Columna ausente"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/parser.py:166
#, python-format
msgid "No buffer file given."
msgstr "No se ha proporcionado ningún búfer de archivo."
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:107
#: code:addons/account_statement_base_import/parser/file_parser.py:171
#: code:addons/account_statement_base_import/parser/file_parser.py:205
#, python-format
msgid "Invalid data"
msgstr "Datos inválidos"
#. module: account_statement_base_import
#: field:account.statement.profile,launch_import_completion:0
msgid "Launch completion after import"
msgstr "Lanzar el completado después de la importación"
#. module: account_statement_base_import
#: field:credit.statement.import,partner_id:0
msgid "Credit insitute partner"
msgstr "Empresa para el agente financiero"
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Import related infos"
msgstr "Importar información relacionada"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:163
#, python-format
msgid "The file is empty"
msgstr "El archivo está vacío"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/wizard/import_statement.py:93
#, python-format
msgid "Please use a file with an extention"
msgstr "Use por favor un archivo con extensión"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:172
#: code:addons/account_statement_base_import/parser/file_parser.py:206
#, python-format
msgid ""
"Value %s of column %s is not valid.\n"
" Please check the line with ref %s:\n"
" \n"
" Detail: %s"
msgstr ""
"El valor %s de la columna %s no es válido.\n"
"\n"
"Compruebe por favor la línea con referencia %s\n"
" \n"
"Detalles: %s"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:29
#: code:addons/account_statement_base_import/parser/generic_file_parser.py:31
#, python-format
msgid "Please install python lib xlrd"
msgstr "Por favor instale la librería de Python xlrd"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:160
#, python-format
msgid ""
" 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"
msgstr ""
" La columna %s debería tener el formato YYYY-MM-DD y es: %s \n"
" \n"
"Compruebe por favor la línea con referencia %s \n"
" \n"
"Detalles: %s"
#. module: account_statement_base_import
#: field:account.statement.profile,last_import_date:0
msgid "Last Import Date"
msgstr "Última fecha de importación"
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_account_statement_profile
msgid "Statement Profile"
msgstr "Perfil de extracto"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:234
#, python-format
msgid "Statement import error"
msgstr "Error de importación del extracto"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:193
#, python-format
msgid ""
"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"
msgstr ""
"Modifique el formato de fecha para la columna %s. Valor: %s\n"
"\n"
"Compruebe por favor la línea con referencia: %s\n"
" \n"
"Detalles: %s"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:192
#, python-format
msgid "Date format is not valid"
msgstr "El formato de fecha no es válido"
#. module: account_statement_base_import
#: field:account.statement.profile,import_type:0
msgid "Type of import"
msgstr "Tipo de importación"
#. module: account_statement_base_import
#: help:account.statement.profile,launch_import_completion:0
msgid ""
"Tic that box to automatically launch the completion on each imported file "
"using this profile."
msgstr ""
"Marque esta casilla para lanzar automáticamente el completado en cada "
"archivo importado usando este perfil."
#. module: account_statement_base_import
#: help:credit.statement.import,balance_check:0
msgid ""
"Tic that box if you want OpenERP to control the start/end balance before "
"confirming a bank statement. If don't ticked, no balance control will be "
"done."
msgstr ""
"Marque esta casilla si quiere que el sistema controle el saldo inicial/final "
"antes de confirmar un extracto bancaria. Si no está marcada, no se realizará "
"ningún control de saldo."
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:154
#, python-format
msgid "No Profile!"
msgstr "Sin perfil"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:159
#, python-format
msgid "Date format is not valid."
msgstr "El formato de fecha no es válido."
#. module: account_statement_base_import
#: field:credit.statement.import,profile_id:0
msgid "Import configuration parameter"
msgstr "Parámetros de configuración de la importación"
#. module: account_statement_base_import
#: field:account.statement.profile,rec_log:0
msgid "log"
msgstr "registro"
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Import Parameters Summary"
msgstr "Resumen de parámetros de importación"
#. module: account_statement_base_import
#: field:credit.statement.import,balance_check:0
msgid "Balance check"
msgstr "Comprobar saldo"
#. module: account_statement_base_import
#: field:credit.statement.import,force_partner_on_bank:0
msgid "Force partner on bank move"
msgstr "Forzar empresa en el apunte bancario"
#. module: account_statement_base_import
#: field:credit.statement.import,file_name:0
msgid "File Name"
msgstr "Nombre del archivo"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:55
#, python-format
msgid "Invalid file type %s. Please use csv or xls"
msgstr "Tipo de archivo %s no válido. Utilice por favor CSV o XLS."
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:155
#, python-format
msgid "You must provide a valid profile to import a bank statement!"
msgstr "Debe introducir un perfil válido para importar un extracto bancario"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:83
#, python-format
msgid "Statement ID %s have been imported with %s lines."
msgstr "El extracto con ID %s ha sido importado con %s líneas."
#. module: account_statement_base_import
#: field:credit.statement.import,receivable_account_id:0
msgid "Force Receivable/Payable Account"
msgstr "Forzar cuenta a cobrar/a pagar"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:164
#: code:addons/account_statement_base_import/parser/file_parser.py:174
#: code:addons/account_statement_base_import/parser/file_parser.py:198
#: code:addons/account_statement_base_import/parser/file_parser.py:208
#, python-format
msgid "Missing"
msgstr "Ausente"
#. module: account_statement_base_import
#: help:account.statement.profile,import_type:0
msgid ""
"Choose here the method by which you want to import bank statement for this "
"profile."
msgstr ""
"Escoja aquí el método con el que quiere importar el extracto bancario para "
"este perfil."
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Cancel"
msgstr "Cancelar"
#. module: account_statement_base_import
#: help:credit.statement.import,force_partner_on_bank:0
msgid ""
"Tic that box if you want to use the credit insitute partner in the "
"counterpart of the treasury/banking move."
msgstr ""
"Marque esta casilla si quiere usar la empresa de su institución financiera "
"en la contrapartida del movimiento de caja/banco."

View File

@@ -0,0 +1,303 @@
# French translation for banking-addons
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the banking-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: banking-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2014-01-21 11:58+0000\n"
"PO-Revision-Date: 2014-03-21 15:17+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-05-22 06:49+0000\n"
"X-Generator: Launchpad (build 17017)\n"
#. module: account_statement_base_import
#: view:credit.statement.import:0
#: model:ir.actions.act_window,name:account_statement_base_import.statement_importer_action
msgid "Import statement"
msgstr "Import de relevé"
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Historical Import Logs"
msgstr ""
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_credit_statement_import
msgid "credit.statement.import"
msgstr "credit.statement.import"
#. module: account_statement_base_import
#: field:credit.statement.import,input_statement:0
msgid "Statement file"
msgstr "Fichier à importer"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:168
#, python-format
msgid ""
"Column %s you try to import is not present in the bank statement line!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:162
#, python-format
msgid "Nothing to import"
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,journal_id:0
msgid "Financial journal to use transaction"
msgstr "Journal"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:102
#, python-format
msgid "Column %s not present in file"
msgstr "Colonne %s non présente dans le fichier"
#. module: account_statement_base_import
#: view:account.statement.profile:0
#: model:ir.ui.menu,name:account_statement_base_import.statement_importer_menu
msgid "Import Bank Statement"
msgstr "Importation de relevé"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:54
#, python-format
msgid "User Error"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:223
#, python-format
msgid "The statement cannot be created: %s"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:167
#, python-format
msgid "Missing column!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/parser.py:166
#, python-format
msgid "No buffer file given."
msgstr "Pas de fichier tampon donné."
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:107
#: code:addons/account_statement_base_import/parser/file_parser.py:171
#: code:addons/account_statement_base_import/parser/file_parser.py:205
#, python-format
msgid "Invalid data"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,launch_import_completion:0
msgid "Launch completion after import"
msgstr "Lancer l'auto-complétion après import"
#. module: account_statement_base_import
#: field:credit.statement.import,partner_id:0
msgid "Credit insitute partner"
msgstr "Organisme bancaire"
#. module: account_statement_base_import
#: view:account.statement.profile:0
msgid "Import related infos"
msgstr "Importation des informations liées"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:163
#, python-format
msgid "The file is empty"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/wizard/import_statement.py:93
#, python-format
msgid "Please use a file with an extention"
msgstr "Veuillez sélectionner un fichier avec une extension"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:172
#: code:addons/account_statement_base_import/parser/file_parser.py:206
#, python-format
msgid ""
"Value %s of column %s is not valid.\n"
" Please check the line with ref %s:\n"
" \n"
" Detail: %s"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:29
#: code:addons/account_statement_base_import/parser/generic_file_parser.py:31
#, python-format
msgid "Please install python lib xlrd"
msgstr "Veuillez installer la bibliothèque python xlrd"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:160
#, python-format
msgid ""
" 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"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,last_import_date:0
msgid "Last Import Date"
msgstr "Date de dernier import"
#. module: account_statement_base_import
#: model:ir.model,name:account_statement_base_import.model_account_statement_profile
msgid "Statement Profile"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:234
#, python-format
msgid "Statement import error"
msgstr "Erreur d'import de relevé"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:193
#, python-format
msgid ""
"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"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:192
#, python-format
msgid "Date format is not valid"
msgstr ""
#. module: account_statement_base_import
#: field:account.statement.profile,import_type:0
msgid "Type of import"
msgstr "Type d'import"
#. module: account_statement_base_import
#: help:account.statement.profile,launch_import_completion:0
msgid ""
"Tic that box to automatically launch the completion on each imported file "
"using this profile."
msgstr ""
#. module: account_statement_base_import
#: help:credit.statement.import,balance_check:0
msgid ""
"Tic that box if you want OpenERP to control the start/end balance before "
"confirming a bank statement. If don't ticked, no balance control will be "
"done."
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:154
#, python-format
msgid "No Profile!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:159
#, python-format
msgid "Date format is not valid."
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,profile_id:0
msgid "Import configuration parameter"
msgstr "Paramètres de configuration d'import"
#. module: account_statement_base_import
#: field:account.statement.profile,rec_log:0
msgid "log"
msgstr "journal"
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Import Parameters Summary"
msgstr "Résumé des paramètres d'import"
#. module: account_statement_base_import
#: field:credit.statement.import,balance_check:0
msgid "Balance check"
msgstr "Vérification des soldes"
#. module: account_statement_base_import
#: field:credit.statement.import,force_partner_on_bank:0
msgid "Force partner on bank move"
msgstr "Forcer un partenaire sur la ligne du compte de banque"
#. module: account_statement_base_import
#: field:credit.statement.import,file_name:0
msgid "File Name"
msgstr "Nom du fichier"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:55
#, python-format
msgid "Invalid file type %s. Please use csv or xls"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:155
#, python-format
msgid "You must provide a valid profile to import a bank statement!"
msgstr ""
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/statement.py:83
#, python-format
msgid "Statement ID %s have been imported with %s lines."
msgstr ""
#. module: account_statement_base_import
#: field:credit.statement.import,receivable_account_id:0
msgid "Force Receivable/Payable Account"
msgstr "Forcer le compte Client/Fournisseur"
#. module: account_statement_base_import
#: code:addons/account_statement_base_import/parser/file_parser.py:164
#: code:addons/account_statement_base_import/parser/file_parser.py:174
#: code:addons/account_statement_base_import/parser/file_parser.py:198
#: code:addons/account_statement_base_import/parser/file_parser.py:208
#, python-format
msgid "Missing"
msgstr ""
#. module: account_statement_base_import
#: help:account.statement.profile,import_type:0
msgid ""
"Choose here the method by which you want to import bank statement for this "
"profile."
msgstr "Choisissez la méthode d'import de relevé pour ce profil."
#. module: account_statement_base_import
#: view:credit.statement.import:0
msgid "Cancel"
msgstr "Annulation"
#. module: account_statement_base_import
#: help:credit.statement.import,force_partner_on_bank:0
msgid ""
"Tic that box if you want to use the credit insitute partner in the "
"counterpart of the treasury/banking move."
msgstr ""

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from .parser import new_bank_statement_parser
from .parser import BankStatementImportParser
from . import file_parser
from . import generic_file_parser

View File

@@ -0,0 +1,203 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright Camptocamp SA
# Author Nicolas Bessi, Joel Grand-Guillaume
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.tools.translate import _
from openerp.osv.orm import except_orm
import tempfile
import datetime
from .parser import BankStatementImportParser
from .parser import UnicodeDictReader
try:
import xlrd
except:
raise Exception(_('Please install python lib xlrd'))
def float_or_zero(val):
""" Conversion function used to manage
empty string into float usecase"""
return float(val) if val else 0.0
class FileParser(BankStatementImportParser):
"""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,
dialect=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 put into 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_orm(
_('User Error'),
_('Invalid file type %s. Please use csv, xls or xlsx') % ftype)
self.conversion_dict = extra_fields
self.keys_to_validate = self.conversion_dict.keys()
self.fieldnames = header
self._datemode = 0 # used only for xls documents,
# 0 means Windows mode (1900 based dates).
# Set in _parse_xls, from the contents of the file
self.dialect = dialect
def _custom_format(self, *args, **kwargs):
"""No other work on data are needed in this parser."""
return True
def _pre(self, *args, **kwargs):
"""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
given ftype
"""
res = None
if self.ftype == 'csv':
res = self._parse_csv()
else:
res = self._parse_xls()
self.result_row_list = res
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).
"""
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_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."""
self.result_row_list = self._cast_rows(*args, **kwargs)
return True
def _parse_csv(self):
""":return: list of dict from csv file (line/rows)"""
csv_file = tempfile.NamedTemporaryFile()
csv_file.write(self.filebuffer)
csv_file.flush()
with open(csv_file.name, 'rU') as fobj:
reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames,
dialect=self.dialect)
return list(reader)
def _parse_xls(self):
""":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
wb_file.seek(0)
with xlrd.open_workbook(wb_file.name) as wb:
self._datemode = wb.datemode
sheet = wb.sheet_by_index(0)
header = sheet.row_values(0)
res = []
for rownum in range(1, sheet.nrows):
res.append(dict(zip(header, sheet.row_values(rownum))))
return res
def _from_csv(self, result_set, conversion_rules):
"""Handle the converstion from the dict and handle date format from
an .csv file.
"""
for line in result_set:
for rule in conversion_rules:
if conversion_rules[rule] == datetime.datetime:
try:
date_string = line[rule].split(' ')[0]
line[rule] = datetime.datetime.strptime(date_string,
'%Y-%m-%d')
except ValueError as err:
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)))
else:
try:
line[rule] = conversion_rules[rule](line[rule])
except Exception as 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
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)
line[rule] = datetime.datetime(*t_tuple)
except Exception as err:
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)))
else:
try:
line[rule] = conversion_rules[rule](line[rule])
except Exception as 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.
"""
func = getattr(self, '_from_%s' % self.ftype)
res = func(self.result_row_list, self.conversion_dict)
return res

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright Camptocamp SA
# Author Joel Grand-Guillaume
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import datetime
from .file_parser import FileParser
from openerp.addons.account_statement_base_import.parser.file_parser import (
float_or_zero
)
from openerp.tools import ustr
class GenericFileParser(FileParser):
"""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.
"""
def __init__(self, parse_name, ftype='csv', **kwargs):
conversion_dict = {
'ref': ustr,
'label': ustr,
'date': datetime.datetime,
'amount': float_or_zero,
}
super(GenericFileParser, self).__init__(
parse_name, ftype=ftype,
extra_fields=conversion_dict,
**kwargs)
@classmethod
def parser_for(cls, parser_name):
"""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'
def get_st_line_vals(self, line, *args, **kwargs):
"""
This method 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, it MUST contain at least:
{
'name':value,
'date':value,
'amount':value,
'ref':value,
'label':value,
}
"""
return {
'name': line.get('label', line.get('ref', '/')),
'date': line.get('date', datetime.datetime.now().date()),
'amount': line.get('amount', 0.0),
'ref': line.get('ref', '/'),
'label': line.get('label', ''),
}

View File

@@ -0,0 +1,230 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base64
import csv
from datetime import datetime
from openerp.tools.translate import _
def UnicodeDictReader(utf8_data, **kwargs):
sniffer = csv.Sniffer()
pos = utf8_data.tell()
sample_data = utf8_data.read(2048)
utf8_data.seek(pos)
if not kwargs.get('dialect'):
dialect = sniffer.sniff(sample_data, delimiters=',;\t')
del kwargs['dialect']
else:
dialect = kwargs.pop('dialect')
csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs)
for row in csv_reader:
yield dict([(unicode(key or '', 'utf-8'),
unicode(value or '', 'utf-8'))
for key, value in row.iteritems()])
class BankStatementImportParser(object):
"""
Generic abstract class for defining parser for different files and
format to import in a bank statement. Inherit from it to create your
own. If your file is a .csv or .xls format, you should consider inheirt
from the FileParser instead.
"""
def __init__(self, profile, *args, **kwargs):
# The name of the parser as it will be called
self.parser_name = profile.import_type
# The result as a list of row. One row per line of data in the file,
# but not the commission one!
self.result_row_list = None
# The file buffer on which to work on
self.filebuffer = None
# The profile record to access its parameters in any parser method
self.profile = profile
self.balance_start = None
self.balance_end = None
self.statement_name = None
self.statement_date = None
self.support_multi_statements = False
@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.
"""
return False
def _decode_64b_stream(self):
"""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.
"""
if decode_base_64:
self._decode_64b_stream()
self._custom_format(kwargs)
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
"""
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
"""
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.
"""
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.
"""
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, ...
"""
return NotImplementedError
def get_st_vals(self):
"""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 {
'name': self.statement_name or '/',
'balance_start': self.balance_start,
'balance_end_real': self.balance_end,
'date': self.statement_date or datetime.now()
}
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.
: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,
'amount':value,
'ref':value,
}
"""
return NotImplementedError
def parse(self, filebuffer, *args, **kwargs):
"""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 !!!
"""
if filebuffer:
self.filebuffer = filebuffer
else:
raise Exception(_('No buffer file given.'))
self._format(*args, **kwargs)
self._pre(*args, **kwargs)
if self.support_multi_statements:
while self._parse(*args, **kwargs):
self._validate(*args, **kwargs)
self._post(*args, **kwargs)
yield self.result_row_list
else:
self._parse(*args, **kwargs)
self._validate(*args, **kwargs)
self._post(*args, **kwargs)
yield self.result_row_list
def itersubclasses(cls, _seen=None):
"""
itersubclasses(cls)
Generator over all subclasses of a given class, in depth first order.
>>> list(itersubclasses(int)) == [bool]
True
>>> class A(object): pass
>>> class B(A): pass
>>> class C(A): pass
>>> class D(B,C): pass
>>> class E(D): pass
>>>
>>> for cls in itersubclasses(A):
... print(cls.__name__)
B
D
E
C
>>> # get ALL (new-style) classes currently defined
>>> [cls.__name__ for cls in itersubclasses(object)] #doctest: +ELLIPSIS
['type', ...'tuple', ...]
"""
if not isinstance(cls, type):
raise TypeError('itersubclasses must be called with '
'new-style classes, not %.100r' % cls)
if _seen is None:
_seen = set()
try:
subs = cls.__subclasses__()
except TypeError: # fails only when cls is type
subs = cls.__subclasses__(cls)
for sub in subs:
if sub not in _seen:
_seen.add(sub)
yield sub
for sub in itersubclasses(sub, _seen):
yield sub
def new_bank_statement_parser(profile, *args, **kwargs):
"""Return an instance of the good parser class based on the given profile.
:param profile: browse_record of import profile.
:return: class instance for given profile import type.
"""
for cls in itersubclasses(BankStatementImportParser):
if cls.parser_for(profile.import_type):
return cls(profile, *args, **kwargs)
raise ValueError

View File

@@ -0,0 +1,255 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import sys
import traceback
from openerp.tools.translate import _
import datetime
from openerp.osv import fields, orm
from .parser import new_bank_statement_parser
from openerp.tools.config import config
class AccountStatementProfil(orm.Model):
_inherit = "account.statement.profile"
def _get_import_type_selection(self, cr, uid, context=None):
"""This is the method to be inherited for adding the parser"""
return [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')]
def __get_import_type_selection(self, cr, uid, context=None):
""" Call method which can be inherited """
return self._get_import_type_selection(cr, uid, context=context)
_columns = {
'launch_import_completion': fields.boolean(
"Launch completion after import",
help="Tic that box to automatically launch the completion "
"on each imported file using this profile."),
'last_import_date': fields.datetime("Last Import Date"),
# we remove deprecated as it floods logs in standard/warning level
# sob...
'rec_log': fields.text('log', readonly=True), # Deprecated
'import_type': fields.selection(
__get_import_type_selection,
'Type of import',
required=True,
help="Choose here the method by which you want to import bank"
"statement for this profile."),
}
_defaults = {
'import_type': 'generic_csvxls_so'
}
def _write_extra_statement_lines(
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.
: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: context: global context
"""
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)
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,
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.
: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.
"""
statement_line_obj = self.pool['account.bank.statement.line']
values = parser_vals
values['statement_id'] = statement_id
date = values.get('date')
period_memoizer = context.get('period_memoizer')
if not period_memoizer:
period_memoizer = {}
context['period_memoizer'] = period_memoizer
if period_memoizer.get(date):
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)
values['period_id'] = periods[0]
period_memoizer[date] = periods[0]
values = statement_line_obj._add_missing_default_values(
cr, uid, values, context)
return values
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
the profile.
"""
vals = {'profile_id': profile_id}
vals.update(parser.get_st_vals())
if vals.get('balance_start') is None:
# Get starting balance from journal balance if parser doesn't
# fill this data, simulating the manual flow
statement_obj = self.pool['account.bank.statement']
profile = self.browse(cr, uid, profile_id, context=context)
temp = statement_obj.onchange_journal_id(
cr, uid, None, profile.journal_id.id, context=context)
vals['balance_start'] = temp['value'].get('balance_start', False)
return vals
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 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
:param char: ftype represent the file exstension (csv by default)
:return: list: list of ids of the created account.bank.statemênt
"""
prof_obj = self.pool['account.statement.profile']
if not profile_id:
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)
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.
:param prof : The profile used to import the file
:param parser: the parser
:param filebuffer file_stream: binary of the providen file
:param char: ftype represent the file exstension (csv by default)
:return: ID of the created account.bank.statemênt
"""
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 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 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)
try:
# Record every line in the bank statement
statement_store = []
for line in result_row_list:
parser_vals = parser.get_st_line_vals(line)
values = self.prepare_statement_lines_vals(
cr, uid, parser_vals, statement_id,
context)
statement_store.append(values)
# 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
start_bal = statement_obj.read(
cr, uid, statement_id, ['balance_start'], context=context)
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),
'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:" % (
error_type.__name__, error_value)
st += ''.join(traceback.format_tb(trbk, 30))
# TODO we should catch correctly the exception with a python
# Exception and only re-catch some special exception.
# For now we avoid re-catching error in debug mode
if config['debug_mode']:
raise
raise orm.except_orm(_("Statement import error"),
_("The statement cannot be created: %s") % st)
return statement_id

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="statement_importer_view_form" model="ir.ui.view">
<field name="name">account.statement.profile.view</field>
<field name="model">account.statement.profile</field>
<field name="inherit_id" ref="account_statement_ext.statement_importer_view_form"/>
<field name="arch" type="xml">
<field name="bank_statement_prefix" position="after">
<separator colspan="4" string="Import related infos"/>
<field name="launch_import_completion"/>
<field name="last_import_date"/>
<field name="import_type"/>
<button name="%(account_statement_base_import.statement_importer_action)d"
string="Import Bank Statement"
type="action" icon="gtk-ok"
colspan = "2"/>
<group attrs="{'invisible': [('rec_log', '=', False)]}">
<separator colspan="4" string="Historical Import Logs"/>
<field name="rec_log" colspan="4" nolabel="1" />
</group>
</field>
</field>
</record>
<record id="bank_statement_view_form" model="ir.ui.view">
<field name="name">account_bank_statement.bank_statement.view_form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account_statement_base_completion.bank_statement_view_form" />
<field eval="20" name="priority"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='line_ids']/form//field[@name='account_id']" position="attributes">
<attribute name="attrs">{'required': [('already_completed','=', True)]}</attribute>
</xpath>
<xpath expr="//field[@name='line_ids']/tree//field[@name='account_id']" position="attributes">
<attribute name="attrs">{'required': [('already_completed','=', True)]}</attribute>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
#
#
# Authors: Laurent Mignon
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
from . import test_base_import
checks = [
test_base_import
]

View File

@@ -0,0 +1,110 @@
# -*- coding: utf-8 -*-
#
#
# Authors: Laurent Mignon
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
import base64
import inspect
import os
from openerp.tests import common
class TestCodaImport(common.TransactionCase):
def prepare(self):
self.company_a = self.browse_ref('base.main_company')
self.profile_obj = self.registry("account.statement.profile")
self.account_bank_statement_obj = self.registry(
"account.bank.statement")
# 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')
self.profile_id = self.profile_obj.create(self.cr, self.uid, {
"name": "BASE_PROFILE",
"commission_account_id": self.account_id,
"journal_id": self.journal_id,
"import_type": "generic_csvxls_so"})
def _create_fiscalyear(self, year, company_id):
fiscalyear_obj = self.registry("account.fiscalyear")
fiscalyear_id = fiscalyear_obj.create(self.cr, self.uid, {
"name": year,
"code": year,
"date_start": year + "-01-01",
"date_stop": year + "-12-31",
"company_id": company_id
})
fiscalyear_obj.create_period3(self.cr, self.uid, [fiscalyear_id])
return fiscalyear_id
def _filename_to_abs_filename(self, file_name):
dir_name = os.path.dirname(inspect.getfile(self.__class__))
return os.path.join(dir_name, file_name)
def _import_file(self, file_name):
""" import a file using the wizard
return the create account.bank.statement object
"""
with open(file_name) as f:
content = f.read()
wizard_id = self.import_wizard_obj.create(self.cr, self.uid, {
"profile_id": self.profile_id,
'input_statement': base64.b64encode(content),
'file_name': os.path.basename(file_name),
})
res = self.import_wizard_obj.import_statement(
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]
def test_simple_xls(self):
"""Test import from xls
"""
self.prepare()
file_name = self._filename_to_abs_filename(
os.path.join("..", "data", "statement.xls"))
statement = self._import_file(file_name)
self._validate_imported_satement(statement)
def test_simple_csv(self):
"""Test import from csv
"""
self.prepare()
file_name = self._filename_to_abs_filename(
os.path.join("..", "data", "statement.csv"))
statement = self._import_file(file_name)
self._validate_imported_satement(statement)
def _validate_imported_satement(self, statement):
self.assertEqual("/", statement.name)
self.assertEqual(0.0, statement.balance_start)
self.assertEqual(0.0, statement.balance_end_real)
self.assertEqual(3, len(statement.line_ids))
self.assertTrue(statement.account_id)
st_line_obj = statement.line_ids[1]
# common infos
self.assertEqual(st_line_obj.ref, "51065326")
self.assertEqual(st_line_obj.date, "2011-03-02")
self.assertEqual(st_line_obj.amount, 189.0)
self.assertEqual(st_line_obj.name, "label b")

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author Nicolas Bessi, Joel Grand-Guillaume. Copyright Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import import_statement

View File

@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# 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 (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
Wizard to import financial institute date in bank statement
"""
from openerp.osv import orm, fields
from openerp.tools.translate import _
import os
class CreditPartnerStatementImporter(orm.TransientModel):
_name = "credit.statement.import"
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
res = {}
if (context.get('active_model', False) ==
'account.statement.profile' and
context.get('active_ids', False)):
ids = context['active_ids']
assert len(
ids) == 1, 'You cannot use this on more than one profile !'
res['profile_id'] = ids[0]
other_vals = self.onchange_profile_id(
cr, uid, [], res['profile_id'], context=context)
res.update(other_vals.get('value', {}))
return res
_columns = {
'profile_id': fields.many2one('account.statement.profile',
'Import configuration parameter',
required=True),
'input_statement': fields.binary('Statement file', required=True),
'partner_id': fields.many2one('res.partner',
'Credit insitute partner'),
'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'),
'force_partner_on_bank': fields.boolean(
'Force partner on bank move',
help="Tic that box if you want to use the credit insitute partner "
"in the counterpart of the treasury/banking move."),
'balance_check': fields.boolean(
'Balance check',
help="Tic that box if you want OpenERP to control the "
"start/end balance before confirming a bank statement. "
"If don't ticked, no balance control will be done."),
}
def onchange_profile_id(self, cr, uid, ids, profile_id, context=None):
res = {}
if profile_id:
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.id,
'force_partner_on_bank': c.force_partner_on_bank,
'balance_check': c.balance_check,
}
}
return res
def _check_extension(self, filename):
(__, ftype) = os.path.splitext(filename)
if not ftype:
# We do not use osv exception we do not want to have it logged
raise Exception(_('Please use a file with an extention'))
return ftype
def import_statement(self, cr, uid, req_id, context=None):
"""This Function import credit card agency statement"""
context = context or {}
if isinstance(req_id, list):
req_id = req_id[0]
importer = self.browse(cr, uid, req_id, context)
ftype = self._check_extension(importer.file_name)
context['file_name'] = importer.file_name
sid = self.pool.get(
'account.statement.profile').multi_statement_import(
cr,
uid,
False,
importer.profile_id.id,
importer.input_statement,
ftype.replace('.', ''),
context=context
)
model_obj = self.pool.get('ir.model.data')
action_obj = self.pool.get('ir.actions.act_window')
action_id = model_obj.get_object_reference(
cr, uid, 'account', 'action_bank_statement_tree')[1]
res = action_obj.read(cr, uid, action_id)
res['domain'] = res['domain'][:-1] + ",('id', 'in', %s)]" % sid
return res

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="statement_importer_view" model="ir.ui.view">
<field name="name">credit.statement.import.config.view</field>
<field name="model">credit.statement.import</field>
<field name="arch" type="xml">
<form string="Import statement">
<group colspan="4" >
<field name="profile_id" on_change="onchange_profile_id(profile_id)"/>
<field name="input_statement" filename="file_name" colspan="2"/>
<field name="file_name" colspan="2" invisible="1"/>
<separator string="Import Parameters Summary" colspan="4"/>
<field name="partner_id" readonly="1"/>
<field name="journal_id" readonly="1"/>
<field name="receivable_account_id" readonly="1"/>
<field name="force_partner_on_bank" readonly="1"/>
<field name="balance_check" readonly="1"/>
</group>
<separator string="" colspan="4"/>
<group colspan="4" col="6">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-ok" name="import_statement" string="Import statement" type="object"/>
</group>
</form>
</field>
</record>
<record id="statement_importer_action" model="ir.actions.act_window">
<field name="name">Import statement</field>
<field name="res_model">credit.statement.import</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="statement_importer_view"/>
<field name="target">new</field>
</record>
<menuitem id="statement_importer_menu" name="Import Bank Statement" action="statement_importer_action" parent="account.menu_finance_bank_and_cash"/>
</data>
</openerp>