mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Initial adjustments for 8.0 repository
This commit is contained in:
1
__unported__/account_bank_statement_tax/__init__.py
Normal file
1
__unported__/account_bank_statement_tax/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
import model
|
||||
43
__unported__/account_bank_statement_tax/__openerp__.py
Normal file
43
__unported__/account_bank_statement_tax/__openerp__.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2012 - 2013 Therp BV (<http://therp.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Apply a tax on bank statement lines',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Therp BV',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account',
|
||||
],
|
||||
'data': [
|
||||
'view/account_bank_statement.xml',
|
||||
],
|
||||
'description': '''
|
||||
Allow an (inclusive) tax to be set on a bank statement line. When the
|
||||
statement is confirmed, the tax will be processed like a tax set on a
|
||||
move line.
|
||||
|
||||
This module is co-funded by BAS Solutions.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_bank_statement_tax
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 16:00+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 16:00+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_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement_line
|
||||
msgid "Bank Statement Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: field:account.bank.statement.line,tax_id:0
|
||||
msgid "Tax"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: help:account.bank.statement.line,tax_id:0
|
||||
msgid "Apply an (inclusive) tax from the bank statement line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement
|
||||
msgid "Bank Statement"
|
||||
msgstr ""
|
||||
|
||||
38
__unported__/account_bank_statement_tax/i18n/hu.po
Normal file
38
__unported__/account_bank_statement_tax/i18n/hu.po
Normal file
@@ -0,0 +1,38 @@
|
||||
# Hungarian 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: 2013-10-25 16:00+0000\n"
|
||||
"PO-Revision-Date: 2014-01-13 18:20+0000\n"
|
||||
"Last-Translator: krnkris <Unknown>\n"
|
||||
"Language-Team: Hungarian <hu@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-31 06:01+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement_line
|
||||
msgid "Bank Statement Line"
|
||||
msgstr "Bankkivonat tételsor"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: field:account.bank.statement.line,tax_id:0
|
||||
msgid "Tax"
|
||||
msgstr "Adó"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: help:account.bank.statement.line,tax_id:0
|
||||
msgid "Apply an (inclusive) tax from the bank statement line"
|
||||
msgstr "Egy bankivonat adó (beleértve) sorára alkalmazza"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement
|
||||
msgid "Bank Statement"
|
||||
msgstr "Bankszámlakivonat"
|
||||
37
__unported__/account_bank_statement_tax/i18n/nl.po
Normal file
37
__unported__/account_bank_statement_tax/i18n/nl.po
Normal file
@@ -0,0 +1,37 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_bank_statement_tax
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 16:00+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 17:46+0000\n"
|
||||
"Last-Translator: Erwin van der Ploeg | Endian Solutions <Unknown>\n"
|
||||
"Language-Team: \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-31 06:01+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement_line
|
||||
msgid "Bank Statement Line"
|
||||
msgstr "Bankafschriftregel"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: field:account.bank.statement.line,tax_id:0
|
||||
msgid "Tax"
|
||||
msgstr "Belasting"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: help:account.bank.statement.line,tax_id:0
|
||||
msgid "Apply an (inclusive) tax from the bank statement line"
|
||||
msgstr "Voeg een inclusief belasting tarief toe aan de afschriftregel."
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement
|
||||
msgid "Bank Statement"
|
||||
msgstr "Bankafschrift"
|
||||
38
__unported__/account_bank_statement_tax/i18n/pt_BR.po
Normal file
38
__unported__/account_bank_statement_tax/i18n/pt_BR.po
Normal file
@@ -0,0 +1,38 @@
|
||||
# Brazilian Portuguese translation for banking-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the banking-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: banking-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2013-10-25 16:00+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:18+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@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-31 06:01+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement_line
|
||||
msgid "Bank Statement Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: field:account.bank.statement.line,tax_id:0
|
||||
msgid "Tax"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: help:account.bank.statement.line,tax_id:0
|
||||
msgid "Apply an (inclusive) tax from the bank statement line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_statement_tax
|
||||
#: model:ir.model,name:account_bank_statement_tax.model_account_bank_statement
|
||||
msgid "Bank Statement"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,2 @@
|
||||
import account_bank_statement_line
|
||||
import account_bank_statement
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2012 - 2013 Therp BV (<http://therp.nl>).
|
||||
# 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 openerp.osv import orm
|
||||
from openerp.tools import ustr
|
||||
|
||||
|
||||
class AccountBankStatement(orm.Model):
|
||||
_inherit = 'account.bank.statement'
|
||||
|
||||
def get_tax_move_lines(
|
||||
self, cr, uid, st_line, defaults,
|
||||
company_currency_id, context=None):
|
||||
"""
|
||||
Process inclusive taxes on bank statement lines.
|
||||
|
||||
@param st_line: browse record of the statement line
|
||||
@param defaults: dictionary of default move line values. Usually
|
||||
the same as the originating move line.
|
||||
|
||||
return one or more serialized tax move lines and a set of values to
|
||||
update the originating move line with, containing the new amount.
|
||||
"""
|
||||
|
||||
if not st_line.tax_id:
|
||||
return False, False
|
||||
tax_obj = self.pool.get('account.tax')
|
||||
move_lines = []
|
||||
update_move_line = {}
|
||||
base_amount = -defaults['credit'] or defaults['debit']
|
||||
tax_obj = self.pool.get('account.tax')
|
||||
|
||||
fiscal_position = (
|
||||
st_line.partner_id.property_account_position
|
||||
if st_line.partner_id
|
||||
and st_line.partner_id.property_account_position
|
||||
else False)
|
||||
tax_ids = self.pool.get('account.fiscal.position').map_tax(
|
||||
cr, uid, fiscal_position, [st_line.tax_id])
|
||||
taxes = tax_obj.browse(cr, uid, tax_ids, context=context)
|
||||
|
||||
computed_taxes = tax_obj.compute_all(
|
||||
cr, uid, taxes, base_amount, 1.00)
|
||||
|
||||
for tax in computed_taxes['taxes']:
|
||||
if tax['tax_code_id']:
|
||||
if not update_move_line.get('tax_code_id'):
|
||||
update_move_line['tax_code_id'] = tax['base_code_id']
|
||||
update_move_line['tax_amount'] = tax['base_sign'] * (
|
||||
computed_taxes.get('total', 0.0))
|
||||
# As the tax is inclusive, we need to correct the amount
|
||||
# on the original move line
|
||||
amount = computed_taxes.get('total', 0.0)
|
||||
update_move_line['credit'] = (
|
||||
(amount < 0) and -amount) or 0.0
|
||||
update_move_line['debit'] = (
|
||||
(amount > 0) and amount) or 0.0
|
||||
|
||||
move_lines.append({
|
||||
'move_id': defaults['move_id'],
|
||||
'name': (
|
||||
defaults.get('name', '')
|
||||
+ ' ' + ustr(tax['name'] or '')),
|
||||
'date': defaults.get('date', False),
|
||||
'partner_id': defaults.get('partner_id', False),
|
||||
'ref': defaults.get('ref', False),
|
||||
'statement_id': defaults.get('statement_id'),
|
||||
'tax_code_id': tax['tax_code_id'],
|
||||
'tax_amount': tax['tax_sign'] * tax.get('amount', 0.0),
|
||||
'account_id': (
|
||||
tax.get('account_collected_id',
|
||||
defaults['account_id'])),
|
||||
'credit': tax['amount'] < 0 and - tax['amount'] or 0.0,
|
||||
'debit': tax['amount'] > 0 and tax['amount'] or 0.0,
|
||||
'account_id': (
|
||||
tax.get('account_collected_id',
|
||||
defaults['account_id'])),
|
||||
})
|
||||
|
||||
return move_lines, update_move_line
|
||||
|
||||
def _prepare_bank_move_line(
|
||||
self, cr, uid, st_line, move_id, amount, company_currency_id,
|
||||
context=None):
|
||||
"""
|
||||
Overload of the original method from the account module. Create
|
||||
the tax move lines.
|
||||
"""
|
||||
res = super(AccountBankStatement, self)._prepare_bank_move_line(
|
||||
cr, uid, st_line, move_id, amount, company_currency_id,
|
||||
context=context)
|
||||
if st_line.tax_id:
|
||||
tax_move_lines, counterpart_update_vals = self.get_tax_move_lines(
|
||||
cr, uid, st_line, res, company_currency_id, context=context)
|
||||
res.update(counterpart_update_vals)
|
||||
for tax_move_line in tax_move_lines:
|
||||
self.pool.get('account.move.line').create(
|
||||
cr, uid, tax_move_line, context=context)
|
||||
return res
|
||||
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2012 - 2013 Therp BV (<http://therp.nl>).
|
||||
# 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 openerp.osv import orm, fields
|
||||
|
||||
|
||||
class AccountBankStatementLine(orm.Model):
|
||||
_inherit = 'account.bank.statement.line'
|
||||
|
||||
_columns = {
|
||||
'tax_id': fields.many2one(
|
||||
'account.tax', 'Tax',
|
||||
domain=[('price_include', '=', True)],
|
||||
help="Apply an (inclusive) tax from the bank statement line",
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_bank_statement_form" model="ir.ui.view">
|
||||
<field name="name">Add tax to the embedded bank statement line form</field>
|
||||
<field name="inherit_id" ref="account.view_bank_statement_form" />
|
||||
<field name="model">account.bank.statement</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='amount']"
|
||||
position="after">
|
||||
<field name="tax_id"
|
||||
domain="[('parent_id', '=', False), ('price_include', '=', True), ('type_tax_use', 'in', (amount and amount > 0 and ('sale', 'all') or ('purchase', 'all')))]"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
36
__unported__/account_banking/__init__.py
Normal file
36
__unported__/account_banking/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract EduSense BV
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (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 sepa
|
||||
import record
|
||||
import banking_import_transaction
|
||||
import account_banking
|
||||
import parsers
|
||||
import wizard
|
||||
import res_partner
|
||||
import res_bank
|
||||
import res_partner_bank
|
||||
105
__unported__/account_banking/__openerp__.py
Normal file
105
__unported__/account_banking/__openerp__.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 Therp BV (<http://therp.nl>).
|
||||
# (C) 2011 Smile (<http://smile.fr>).
|
||||
#
|
||||
# All other contributions are (C) by their respective contributors
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Account Banking',
|
||||
'version': '0.4',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Banking addons community',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_voucher',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/account_banking_data.xml',
|
||||
'wizard/bank_import_view.xml',
|
||||
'account_banking_view.xml',
|
||||
'wizard/banking_transaction_wizard.xml',
|
||||
'wizard/link_partner.xml',
|
||||
'workflow/account_invoice.xml',
|
||||
],
|
||||
'js': [
|
||||
'static/src/js/account_banking.js',
|
||||
],
|
||||
'description': '''
|
||||
Module to do banking.
|
||||
|
||||
This modules tries to combine all current banking import and export
|
||||
schemes. Rationale for this is that it is quite common to have foreign
|
||||
bank account numbers next to national bank account numbers. The current
|
||||
approach, which hides the national banking interface schemes in the
|
||||
l10n_xxx modules, makes it very difficult to use these simultanious.
|
||||
A more banking oriented approach seems more logical and cleaner.
|
||||
|
||||
Changes to default OpenERP:
|
||||
|
||||
* Puts focus on the real life messaging with banks:
|
||||
+ Bank statement lines upgraded to independent bank transactions.
|
||||
+ Banking statements have no special accountancy meaning, they're just
|
||||
message envelopes for a number of bank transactions.
|
||||
+ Bank statements can be either encoded by hand to reflect the document
|
||||
version of Bank Statements, or created as an optional side effect of
|
||||
importing Bank Transactions.
|
||||
|
||||
* Preparations for SEPA:
|
||||
+ IBAN accounts are the standard in the SEPA countries
|
||||
+ local accounts are derived from SEPA (excluding Turkey) but are
|
||||
considered to be identical to the corresponding SEPA account.
|
||||
+ Banks are identified with either Country + Bank code + Branch code or
|
||||
BIC
|
||||
+ Each bank can have its own pace in introducing SEPA into their
|
||||
communication with their customers.
|
||||
+ National online databases can be used to convert BBAN's to IBAN's.
|
||||
+ The SWIFT database is consulted for bank information.
|
||||
|
||||
* Adds dropin extensible import facility for bank communication in:
|
||||
- Drop-in input parser development.
|
||||
- MultiBank (NL) format transaction files available as
|
||||
account_banking_nl_multibank,
|
||||
|
||||
* Extends payments for digital banking:
|
||||
+ Adapted workflow in payments to reflect banking operations
|
||||
+ Relies on account_payment mechanics to extend with export generators.
|
||||
- ClieOp3 (NL) payment and direct debit orders files available as
|
||||
account_banking_nl_clieop
|
||||
|
||||
* Additional features for the import/export mechanism:
|
||||
+ Automatic matching and creation of bank accounts, banks and partners,
|
||||
during import of statements.
|
||||
+ Automatic matching with invoices and payments.
|
||||
+ Sound import mechanism, allowing multiple imports of the same
|
||||
transactions repeated over multiple files.
|
||||
+ Journal configuration per bank account.
|
||||
+ Business logic and format parsing strictly separated to ease the
|
||||
development of new parsers.
|
||||
+ No special configuration needed for the parsers, new parsers are
|
||||
recognized and made available at server (re)start.
|
||||
''',
|
||||
'installable': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
683
__unported__/account_banking/account_banking.py
Normal file
683
__unported__/account_banking/account_banking.py
Normal file
@@ -0,0 +1,683 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# All other contributions are (C) by their respective contributors
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
'''
|
||||
This module shows resemblance to both account_bankimport/bankimport.py,
|
||||
account/account_bank_statement.py and account_payment(_export). All hail to
|
||||
the makers. account_bankimport is only referenced for their ideas and the
|
||||
framework of the filters, which they in their turn seem to have derived
|
||||
from account_coda.
|
||||
|
||||
Modifications are extensive:
|
||||
|
||||
1. In relation to account/account_bank_statement.py:
|
||||
account.bank.statement is effectively stripped from its account.period
|
||||
association, while account.bank.statement.line is extended with the same
|
||||
association, thereby reflecting real world usage of bank.statement as a
|
||||
list of bank transactions and bank.statement.line as a bank transaction.
|
||||
|
||||
2. In relation to account/account_bankimport:
|
||||
All filter objects and extensions to res.company are removed. Instead a
|
||||
flexible auto-loading and auto-browsing plugin structure is created,
|
||||
whereby business logic and encoding logic are strictly separated.
|
||||
Both parsers and business logic are rewritten from scratch.
|
||||
|
||||
The association of account.journal with res.company is replaced by an
|
||||
association of account.journal with res.partner.bank, thereby allowing
|
||||
multiple bank accounts per company and one journal per bank account.
|
||||
|
||||
The imported bank statement file does not result in a single 'bank
|
||||
statement', but in a list of bank statements by definition of whatever the
|
||||
bank sees as a statement. Every imported bank statement contains at least
|
||||
one bank transaction, which is a modded account.bank.statement.line.
|
||||
|
||||
3. In relation to account_payment:
|
||||
An additional state was inserted between 'open' and 'done', to reflect a
|
||||
exported bank orders file which was not reported back through statements.
|
||||
The import of statements matches the payments and reconciles them when
|
||||
needed, flagging them 'done'. When no export wizards are found, the
|
||||
default behavior is to flag the orders as 'sent', not as 'done'.
|
||||
Rejected payments from the bank receive on import the status 'rejected'.
|
||||
'''
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.osv.osv import except_osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import netsvc
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
|
||||
|
||||
class account_banking_account_settings(orm.Model):
|
||||
'''Default Journal for Bank Account'''
|
||||
_name = 'account.banking.account.settings'
|
||||
_description = __doc__
|
||||
_columns = {
|
||||
'company_id': fields.many2one('res.company', 'Company', select=True,
|
||||
required=True),
|
||||
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',
|
||||
select=True, required=True),
|
||||
'journal_id': fields.many2one('account.journal', 'Journal',
|
||||
required=True),
|
||||
'partner_id': fields.related(
|
||||
'company_id', 'partner_id',
|
||||
type='many2one', relation='res.partner',
|
||||
string='Partner'),
|
||||
'default_credit_account_id': fields.many2one(
|
||||
'account.account', 'Default credit account', select=True,
|
||||
help=('The account to use when an unexpected payment was signaled.'
|
||||
' This can happen when a direct debit payment is cancelled '
|
||||
'by a customer, or when no matching payment can be found. '
|
||||
'Mind that you can correct movements before confirming them.'
|
||||
),
|
||||
required=True
|
||||
),
|
||||
'default_debit_account_id': fields.many2one(
|
||||
'account.account', 'Default debit account',
|
||||
select=True, required=True,
|
||||
help=('The account to use when an unexpected payment is received. '
|
||||
'This can be needed when a customer pays in advance or when '
|
||||
'no matching invoice can be found. Mind that you can '
|
||||
'correct movements before confirming them.'
|
||||
),
|
||||
),
|
||||
'costs_account_id': fields.many2one(
|
||||
'account.account', 'Bank Costs Account', select=True,
|
||||
help=('The account to use when the bank invoices its own costs. '
|
||||
'Leave it blank to disable automatic invoice generation '
|
||||
'on bank costs.'
|
||||
),
|
||||
),
|
||||
'invoice_journal_id': fields.many2one(
|
||||
'account.journal', 'Costs Journal',
|
||||
help=('This is the journal used to create invoices for bank costs.'
|
||||
),
|
||||
),
|
||||
'bank_partner_id': fields.many2one(
|
||||
'res.partner', 'Bank Partner',
|
||||
help=('The partner to use for bank costs. Banks are not partners '
|
||||
'by default. You will most likely have to create one.'
|
||||
),
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
def _default_company(self, cr, uid, context=None):
|
||||
"""
|
||||
Return the user's company or the first company found
|
||||
in the database
|
||||
"""
|
||||
user = self.pool.get('res.users').read(
|
||||
cr, uid, uid, ['company_id'], context=context)
|
||||
if user['company_id']:
|
||||
return user['company_id'][0]
|
||||
return self.pool.get('res.company').search(
|
||||
cr, uid, [('parent_id', '=', False)])[0]
|
||||
|
||||
def _default_partner_id(self, cr, uid, context=None, company_id=False):
|
||||
if not company_id:
|
||||
company_id = self._default_company(cr, uid, context=context)
|
||||
return self.pool.get('res.company').read(
|
||||
cr, uid, company_id, ['partner_id'],
|
||||
context=context)['partner_id'][0]
|
||||
|
||||
def _default_journal(self, cr, uid, context=None, company_id=False):
|
||||
if not company_id:
|
||||
company_id = self._default_company(cr, uid, context=context)
|
||||
journal_ids = self.pool.get('account.journal').search(
|
||||
cr, uid, [('type', '=', 'bank'), ('company_id', '=', company_id)])
|
||||
return journal_ids and journal_ids[0] or False
|
||||
|
||||
def _default_partner_bank_id(
|
||||
self, cr, uid, context=None, company_id=False):
|
||||
if not company_id:
|
||||
company_id = self._default_company(cr, uid, context=context)
|
||||
partner_id = self.pool.get('res.company').read(
|
||||
cr, uid, company_id, ['partner_id'],
|
||||
context=context)['partner_id'][0]
|
||||
bank_ids = self.pool.get('res.partner.bank').search(
|
||||
cr, uid, [('partner_id', '=', partner_id)], context=context)
|
||||
return bank_ids and bank_ids[0] or False
|
||||
|
||||
def _default_debit_account_id(
|
||||
self, cr, uid, context=None, company_id=False):
|
||||
localcontext = context and context.copy() or {}
|
||||
localcontext['force_company'] = (
|
||||
company_id or self._default_company(cr, uid, context=context))
|
||||
account_def = self.pool.get('ir.property').get(
|
||||
cr, uid, 'property_account_receivable',
|
||||
'res.partner', context=localcontext)
|
||||
return account_def and account_def.id or False
|
||||
|
||||
def _default_credit_account_id(
|
||||
self, cr, uid, context=None, company_id=False):
|
||||
localcontext = context and context.copy() or {}
|
||||
localcontext['force_company'] = (
|
||||
company_id or self._default_company(cr, uid, context=context))
|
||||
account_def = self.pool.get('ir.property').get(
|
||||
cr, uid, 'property_account_payable',
|
||||
'res.partner', context=localcontext)
|
||||
return account_def and account_def.id or False
|
||||
|
||||
def find(self, cr, uid, journal_id, partner_bank_id=False, context=None):
|
||||
domain = [('journal_id', '=', journal_id)]
|
||||
if partner_bank_id:
|
||||
domain.append(('partner_bank_id', '=', partner_bank_id))
|
||||
return self.search(cr, uid, domain, context=context)
|
||||
|
||||
def onchange_partner_bank_id(
|
||||
self, cr, uid, ids, partner_bank_id, context=None):
|
||||
values = {}
|
||||
if partner_bank_id:
|
||||
bank = self.pool.get('res.partner.bank').read(
|
||||
cr, uid, partner_bank_id, ['journal_id'], context=context)
|
||||
if bank['journal_id']:
|
||||
values['journal_id'] = bank['journal_id'][0]
|
||||
return {'value': values}
|
||||
|
||||
def onchange_company_id(
|
||||
self, cr, uid, ids, company_id=False, context=None):
|
||||
if not company_id:
|
||||
return {}
|
||||
result = {
|
||||
'partner_id': self._default_partner_id(
|
||||
cr, uid, company_id=company_id, context=context),
|
||||
'journal_id': self._default_journal(
|
||||
cr, uid, company_id=company_id, context=context),
|
||||
'default_debit_account_id': self._default_debit_account_id(
|
||||
cr, uid, company_id=company_id, context=context),
|
||||
'default_credit_account_id': self._default_credit_account_id(
|
||||
cr, uid, company_id=company_id, context=context),
|
||||
}
|
||||
return {'value': result}
|
||||
|
||||
_defaults = {
|
||||
'company_id': _default_company,
|
||||
'partner_id': _default_partner_id,
|
||||
'journal_id': _default_journal,
|
||||
'default_debit_account_id': _default_debit_account_id,
|
||||
'default_credit_account_id': _default_credit_account_id,
|
||||
'partner_bank_id': _default_partner_bank_id,
|
||||
}
|
||||
account_banking_account_settings()
|
||||
|
||||
|
||||
class account_banking_imported_file(orm.Model):
|
||||
'''Imported Bank Statements File'''
|
||||
_name = 'account.banking.imported.file'
|
||||
_description = __doc__
|
||||
_rec_name = 'date'
|
||||
_columns = {
|
||||
'company_id': fields.many2one(
|
||||
'res.company',
|
||||
'Company',
|
||||
select=True,
|
||||
readonly=True,
|
||||
),
|
||||
'date': fields.datetime(
|
||||
'Import Date',
|
||||
readonly=True,
|
||||
select=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'format': fields.char(
|
||||
'File Format',
|
||||
size=20,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'file': fields.binary(
|
||||
'Raw Data',
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'file_name': fields.char('File name', size=256),
|
||||
'log': fields.text(
|
||||
'Import Log',
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'user_id': fields.many2one(
|
||||
'res.users',
|
||||
'Responsible User',
|
||||
readonly=True,
|
||||
select=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'state': fields.selection(
|
||||
[
|
||||
('unfinished', 'Unfinished'),
|
||||
('error', 'Error'),
|
||||
('review', 'Review'),
|
||||
('ready', 'Finished'),
|
||||
],
|
||||
'State',
|
||||
select=True,
|
||||
readonly=True,
|
||||
),
|
||||
'statement_ids': fields.one2many(
|
||||
'account.bank.statement',
|
||||
'banking_id',
|
||||
'Statements',
|
||||
readonly=False,
|
||||
),
|
||||
}
|
||||
_defaults = {
|
||||
'date': fields.date.context_today,
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
}
|
||||
account_banking_imported_file()
|
||||
|
||||
|
||||
class account_bank_statement(orm.Model):
|
||||
'''
|
||||
Implement changes to this model for the following features:
|
||||
|
||||
* bank statement lines have their own period_id, derived from
|
||||
their effective date. The period and date are propagated to
|
||||
the move lines created from each statement line
|
||||
* bank statement lines have their own state. When a statement
|
||||
is confirmed, all lines are confirmed too. When a statement
|
||||
is reopened, lines remain confirmed until reopened individually.
|
||||
* upon confirmation of a statement line, the move line is
|
||||
created and reconciled according to the matched entry(/ies)
|
||||
'''
|
||||
_inherit = 'account.bank.statement'
|
||||
|
||||
_columns = {
|
||||
'period_id': fields.many2one(
|
||||
'account.period',
|
||||
'Period',
|
||||
required=False,
|
||||
readonly=True,
|
||||
),
|
||||
'banking_id': fields.many2one(
|
||||
'account.banking.imported.file',
|
||||
'Imported File',
|
||||
readonly=True,
|
||||
),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'period_id': False,
|
||||
}
|
||||
|
||||
def _check_company_id(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Adapt this constraint method from the account module to reflect the
|
||||
move of period_id to the statement line: also check the periods of the
|
||||
lines. Update the statement period if it does not have one yet.
|
||||
Don't call super, because its check is integrated below and
|
||||
it will break if a statement does not have any lines yet and
|
||||
therefore may not have a period.
|
||||
"""
|
||||
for statement in self.browse(cr, uid, ids, context=context):
|
||||
if (statement.period_id and
|
||||
statement.company_id != statement.period_id.company_id):
|
||||
return False
|
||||
for line in statement.line_ids:
|
||||
if (line.period_id and
|
||||
statement.company_id != line.period_id.company_id):
|
||||
return False
|
||||
if not statement.period_id:
|
||||
statement.write({'period_id': line.period_id.id})
|
||||
statement.refresh()
|
||||
return True
|
||||
|
||||
# Redefine the constraint, or it still refer to the original method
|
||||
_constraints = [
|
||||
(_check_company_id,
|
||||
'The journal and period chosen have to belong to the same company.',
|
||||
['journal_id', 'period_id']),
|
||||
]
|
||||
|
||||
def _get_period(self, cr, uid, date=False, context=None):
|
||||
"""
|
||||
Used in statement line's _defaults, so it is always triggered
|
||||
on installation or module upgrade even if there are no records
|
||||
without a value. For that reason, we need
|
||||
to be tolerant and allow for the situation in which no period
|
||||
exists for the current date (i.e. when no date is specified).
|
||||
|
||||
Cannot be used directly as a defaults method due to lp:1296229
|
||||
"""
|
||||
local_ctx = dict(context or {}, account_period_prefer_normal=True)
|
||||
try:
|
||||
return self.pool.get('account.period').find(
|
||||
cr, uid, dt=date, context=local_ctx)[0]
|
||||
except except_osv:
|
||||
if date:
|
||||
raise
|
||||
return False
|
||||
|
||||
def _prepare_move(
|
||||
self, cr, uid, st_line, st_line_number, context=None):
|
||||
"""
|
||||
Add the statement line's period to the move, overwriting
|
||||
the period on the statement
|
||||
"""
|
||||
res = super(account_bank_statement, self)._prepare_move(
|
||||
cr, uid, st_line, st_line_number, context=context)
|
||||
if context and context.get('period_id'):
|
||||
res['period_id'] = context['period_id']
|
||||
return res
|
||||
|
||||
def _prepare_move_line_vals(
|
||||
self, cr, uid, st_line, move_id, debit, credit, currency_id=False,
|
||||
amount_currency=False, account_id=False, analytic_id=False,
|
||||
partner_id=False, context=None):
|
||||
"""
|
||||
Add the statement line's period to the move lines, overwriting
|
||||
the period on the statement
|
||||
"""
|
||||
res = super(account_bank_statement, self)._prepare_move_line_vals(
|
||||
cr, uid, st_line, move_id, debit, credit, currency_id=currency_id,
|
||||
amount_currency=amount_currency, account_id=account_id,
|
||||
analytic_id=analytic_id, partner_id=partner_id, context=context)
|
||||
if context and context.get('period_id'):
|
||||
res['period_id'] = context['period_id']
|
||||
return res
|
||||
|
||||
def create_move_from_st_line(self, cr, uid, st_line_id,
|
||||
company_currency_id, st_line_number,
|
||||
context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
account_move_obj = self.pool.get('account.move')
|
||||
account_move_line_obj = self.pool.get('account.move.line')
|
||||
account_bank_statement_line_obj = self.pool.get(
|
||||
'account.bank.statement.line')
|
||||
st_line = account_bank_statement_line_obj.browse(
|
||||
cr, uid, st_line_id, context=context)
|
||||
|
||||
# Take period from statement line and write to context
|
||||
# this will be picked up by the _prepare_move* methods
|
||||
period_id = self._get_period(
|
||||
cr, uid, date=st_line.date, context=context)
|
||||
localctx = context.copy()
|
||||
localctx['period_id'] = period_id
|
||||
|
||||
# Write date & period on the voucher, delegate to account_voucher's
|
||||
# override of this method. Then post the related move and return.
|
||||
if st_line.voucher_id:
|
||||
voucher_pool = self.pool.get('account.voucher')
|
||||
voucher_pool.write(
|
||||
cr, uid, [st_line.voucher_id.id], {
|
||||
'date': st_line.date,
|
||||
'period_id': period_id,
|
||||
}, context=context)
|
||||
|
||||
res = super(account_bank_statement, self).create_move_from_st_line(
|
||||
cr, uid, st_line_id, company_currency_id, st_line_number,
|
||||
context=localctx)
|
||||
|
||||
st_line.refresh()
|
||||
if st_line.voucher_id:
|
||||
if not st_line.voucher_id.journal_id.entry_posted:
|
||||
account_move_obj.post(
|
||||
cr, uid, [st_line.voucher_id.move_id.id], context={})
|
||||
else:
|
||||
# Write stored reconcile_id and pay invoices through workflow
|
||||
if st_line.reconcile_id:
|
||||
move_ids = [move.id for move in st_line.move_ids]
|
||||
torec = account_move_line_obj.search(
|
||||
cr, uid, [
|
||||
('move_id', 'in', move_ids),
|
||||
('account_id', '=', st_line.account_id.id)],
|
||||
context=context)
|
||||
account_move_line_obj.write(cr, uid, torec, {
|
||||
(st_line.reconcile_id.line_partial_ids
|
||||
and 'reconcile_partial_id'
|
||||
or 'reconcile_id'): st_line.reconcile_id.id
|
||||
}, context=context)
|
||||
for move_line in (st_line.reconcile_id.line_id or []) + (
|
||||
st_line.reconcile_id.line_partial_ids or []):
|
||||
netsvc.LocalService("workflow").trg_trigger(
|
||||
uid, 'account.move.line', move_line.id, cr)
|
||||
return res
|
||||
|
||||
def button_confirm_bank(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Assign journal sequence to statements without a name
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
obj_seq = self.pool.get('ir.sequence')
|
||||
if ids and isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
noname_ids = self.search(
|
||||
cr, uid, [('id', 'in', ids), ('name', '=', '/')],
|
||||
context=context)
|
||||
for st in self.browse(cr, uid, noname_ids, context=context):
|
||||
if st.journal_id.sequence_id:
|
||||
period_id = self._get_period(
|
||||
cr, uid, date=st.date, context=context)
|
||||
year = self.pool.get('account.period').browse(
|
||||
cr, uid, period_id, context=context).fiscalyear_id.id
|
||||
c = {'fiscalyear_id': year}
|
||||
st_number = obj_seq.get_id(
|
||||
cr, uid, st.journal_id.sequence_id.id, context=c)
|
||||
self.write(
|
||||
cr, uid, ids, {'name': st_number}, context=context)
|
||||
|
||||
return super(account_bank_statement, self).button_confirm_bank(
|
||||
cr, uid, ids, context)
|
||||
|
||||
|
||||
class account_voucher(orm.Model):
|
||||
_inherit = 'account.voucher'
|
||||
|
||||
def _get_period(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context.get('period_id') and context.get('move_line_ids'):
|
||||
move_line = self.pool.get('account.move.line').browse(
|
||||
cr, uid, context.get('move_line_ids')[0], context=context)
|
||||
return move_line.period_id.id
|
||||
return super(account_voucher, self)._get_period(cr, uid, context)
|
||||
|
||||
|
||||
class account_bank_statement_line(orm.Model):
|
||||
'''
|
||||
Extension on basic class:
|
||||
1. Extra links to account.period and res.partner.bank for tracing and
|
||||
matching.
|
||||
2. Extra 'trans' field to carry the transaction id of the bank.
|
||||
3. Readonly states for most fields except when in draft.
|
||||
'''
|
||||
_inherit = 'account.bank.statement.line'
|
||||
_description = 'Bank Transaction'
|
||||
|
||||
def _get_period(self, cr, uid, date=False, context=None):
|
||||
return self.pool['account.bank.statement']._get_period(
|
||||
cr, uid, date=date, context=context)
|
||||
|
||||
def _get_period_context(self, cr, uid, context=None):
|
||||
"""
|
||||
Workaround for lp:1296229, context is passed positionally
|
||||
"""
|
||||
return self._get_period(cr, uid, context=context)
|
||||
|
||||
def _get_currency(self, cr, uid, context=None):
|
||||
'''
|
||||
Get the default currency (required to allow other modules to function,
|
||||
which assume currency to be a calculated field and thus optional)
|
||||
Remark: this is only a fallback as the real default is in the journal,
|
||||
which is inaccessible from within this method.
|
||||
'''
|
||||
res_users_obj = self.pool.get('res.users')
|
||||
return res_users_obj.browse(
|
||||
cr, uid, uid, context=context).company_id.currency_id.id
|
||||
|
||||
def _get_invoice_id(self, cr, uid, ids, name, args, context=None):
|
||||
res = {}
|
||||
for st_line in self.browse(cr, uid, ids, context):
|
||||
res[st_line.id] = False
|
||||
for move_line in (
|
||||
st_line.reconcile_id and
|
||||
(st_line.reconcile_id.line_id or
|
||||
st_line.reconcile_id.line_partial_ids) or
|
||||
st_line.import_transaction_id and
|
||||
st_line.import_transaction_id.move_line_id and
|
||||
[st_line.import_transaction_id.move_line_id] or []):
|
||||
if move_line.invoice:
|
||||
res[st_line.id] = move_line.invoice.id
|
||||
continue
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
# Redefines. Todo: refactor away to view attrs
|
||||
'amount': fields.float(
|
||||
'Amount',
|
||||
readonly=True,
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'ref': fields.char(
|
||||
'Ref.',
|
||||
size=32,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'name': fields.char(
|
||||
'Name',
|
||||
size=64,
|
||||
required=False,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'date': fields.date(
|
||||
'Date',
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
# New columns
|
||||
'trans': fields.char(
|
||||
'Bank Transaction ID',
|
||||
size=15,
|
||||
required=False,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'partner_bank_id': fields.many2one(
|
||||
'res.partner.bank',
|
||||
'Bank Account',
|
||||
required=False,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
),
|
||||
'period_id': fields.many2one(
|
||||
'account.period',
|
||||
'Period',
|
||||
required=True,
|
||||
states={'confirmed': [('readonly', True)]},
|
||||
),
|
||||
'currency': fields.many2one(
|
||||
'res.currency',
|
||||
'Currency',
|
||||
required=True,
|
||||
states={'confirmed': [('readonly', True)]},
|
||||
),
|
||||
'reconcile_id': fields.many2one(
|
||||
'account.move.reconcile',
|
||||
'Reconciliation',
|
||||
readonly=True,
|
||||
),
|
||||
'invoice_id': fields.function(
|
||||
_get_invoice_id,
|
||||
method=True,
|
||||
string='Linked Invoice',
|
||||
type='many2one',
|
||||
relation='account.invoice',
|
||||
),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'period_id': _get_period_context,
|
||||
'currency': _get_currency,
|
||||
}
|
||||
|
||||
|
||||
class invoice(orm.Model):
|
||||
'''
|
||||
Create other reference types as well.
|
||||
|
||||
Descendant classes can extend this function to add more reference
|
||||
types, ie.
|
||||
|
||||
def _get_reference_type(self, cr, uid, context=None):
|
||||
return super(my_class, self)._get_reference_type(cr, uid,
|
||||
context=context) + [('my_ref', _('My reference')]
|
||||
|
||||
Don't forget to redefine the column "reference_type" as below or
|
||||
your method will never be triggered.
|
||||
|
||||
TODO: move 'structured' part to account_banking_payment module
|
||||
where it belongs
|
||||
'''
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
def test_undo_paid(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Called from the workflow. Used to unset paid state on
|
||||
invoices that were paid with bank transfers which are being cancelled
|
||||
"""
|
||||
for invoice in self.read(cr, uid, ids, ['reconciled'], context):
|
||||
if invoice['reconciled']:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _get_reference_type(self, cr, uid, context=None):
|
||||
'''
|
||||
Return the list of reference types
|
||||
'''
|
||||
return [('none', _('Free Reference')),
|
||||
('structured', _('Structured Reference')),
|
||||
]
|
||||
|
||||
_columns = {
|
||||
'reference_type': fields.selection(_get_reference_type,
|
||||
'Reference Type', required=True
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class account_move_line(orm.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def get_balance(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Return the balance of any set of move lines.
|
||||
|
||||
Not to be confused with the 'balance' field on this model, which
|
||||
returns the account balance that the move line applies to.
|
||||
"""
|
||||
total = 0.0
|
||||
if not ids:
|
||||
return total
|
||||
for line in self.read(
|
||||
cr, uid, ids, ['debit', 'credit'], context=context):
|
||||
total += (line['debit'] or 0.0) - (line['credit'] or 0.0)
|
||||
return total
|
||||
32
__unported__/account_banking/account_banking_demo.xml
Normal file
32
__unported__/account_banking/account_banking_demo.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record model="res.partner" id="partner_demo1">
|
||||
<field name="name">Tiny S.p.r.l</field>
|
||||
</record>
|
||||
<record model="res.partner.bank" id="partner_bank1">
|
||||
<field name="acc_number">301915554082</field>
|
||||
<field name="state">bank</field>
|
||||
<field name="partner_id" ref="partner_demo1"></field>
|
||||
</record>
|
||||
|
||||
<record model="res.partner" id="partner_demo2">
|
||||
<field name="name">The-design Company</field>
|
||||
</record>
|
||||
<record model="res.partner.bank" id="partner_bank2">
|
||||
<field name="acc_number">050000000017</field>
|
||||
<field name="state">iban</field>
|
||||
<field name="partner_id" ref="partner_demo2"></field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="res.partner.bank" id="partner_agrolait">
|
||||
<field name="acc_number">301915554082</field>
|
||||
<field name="partner_id" ref="base.res_partner_agrolait"/>
|
||||
</record>
|
||||
|
||||
<record model="res.partner.bank" id="res_partner_10">
|
||||
<field name="acc_number">050000000017</field>
|
||||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
</record>-->
|
||||
</data>
|
||||
</openerp>
|
||||
389
__unported__/account_banking/account_banking_view.xml
Normal file
389
__unported__/account_banking/account_banking_view.xml
Normal file
@@ -0,0 +1,389 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) EduSense BV <http://www.edusense.nl>
|
||||
All rights reserved.
|
||||
The licence is in the file __terp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Create new submenu in finance/periodical processing -->
|
||||
<menuitem name="Banking"
|
||||
id="account_banking.menu_finance_banking_actions"
|
||||
parent="account.menu_finance_periodical_processing"
|
||||
/>
|
||||
<!-- Create new submenu in finance/configuration -->
|
||||
<menuitem name="Banking"
|
||||
id="account_banking.menu_finance_banking_settings"
|
||||
parent="account.menu_finance_configuration"
|
||||
/>
|
||||
<menuitem action="account.action_view_bank_statement_tree"
|
||||
id="account.journal_cash_move_lines"
|
||||
sequence="18"
|
||||
parent="account.menu_finance_bank_and_cash"/>
|
||||
<!-- Add a shortcut menu for bank accounts -->
|
||||
<record model="ir.actions.act_window" id="action_account_banking_res_partner_banks">
|
||||
<field name="name">Bank Accounts</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner.bank</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<menuitem name="Bank Accounts"
|
||||
id="menu_action_account_banking_bank_accounts"
|
||||
parent="account_banking.menu_finance_banking_settings"
|
||||
action="action_account_banking_res_partner_banks"
|
||||
sequence="10"
|
||||
/>
|
||||
|
||||
<!-- Create new view on default journals for bank accounts -->
|
||||
<record model="ir.ui.view" id="view_banking_account_settings_form">
|
||||
<field name="name">account.banking.account.settings.form</field>
|
||||
<field name="model">account.banking.account.settings</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Default Import Settings for Bank Account">
|
||||
<field name="company_id"
|
||||
widget='selection'
|
||||
groups="base.group_multi_company"
|
||||
on_change="onchange_company_id(company_id)" />
|
||||
<separator string="Bank Account Details" colspan="4" />
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="partner_bank_id"
|
||||
domain="[('partner_id', '=', partner_id)]"
|
||||
on_change="onchange_partner_bank_id(partner_bank_id)" />
|
||||
<field name="journal_id"
|
||||
domain="[('type','=','bank'),
|
||||
('company_id', '=', company_id)]" />
|
||||
<separator string="Default Accounts for Unknown Movements" colspan="4" />
|
||||
<field name="default_credit_account_id"
|
||||
domain="[('company_id', '=', company_id)]" />
|
||||
<field name="default_debit_account_id"
|
||||
domain="[('company_id', '=', company_id)]" />
|
||||
<separator string="Generation of Bank Costs Invoices" colspan="4" />
|
||||
<field name="bank_partner_id" />
|
||||
<field name="costs_account_id"
|
||||
attrs="{'required': [('bank_partner_id', '!=', False)]}"
|
||||
domain="[('company_id', '=', company_id)]" />
|
||||
<field name="invoice_journal_id"
|
||||
attrs="{'required': [('bank_partner_id', '!=', False)]}"
|
||||
domain="[('company_id', '=', company_id)]" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_banking_account_settings_tree">
|
||||
<field name="name">account.banking.account.settings.tree</field>
|
||||
<field name="model">account.banking.account.settings</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Default Import Settings for Bank Account">
|
||||
<field name="company_id" />
|
||||
<field name="partner_bank_id" />
|
||||
<field name="journal_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_account_banking_journals">
|
||||
<field name="name">Default Import Settings for Bank Accounts</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.banking.account.settings</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- Create new submenu for finance configuration -->
|
||||
<menuitem name="Default Import Settings for Bank Accounts"
|
||||
id="menu_action_account_banking_bank_journals"
|
||||
parent="account_banking.menu_finance_banking_settings"
|
||||
action="action_account_banking_journals"
|
||||
sequence="20"
|
||||
/>
|
||||
|
||||
<!-- Create new view on imported statement files -->
|
||||
<record model="ir.ui.view" id="view_account_banking_imported_file_form">
|
||||
<field name="name">account.banking.imported.file.form</field>
|
||||
<field name="model">account.banking.imported.file</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Imported Bank Statements">
|
||||
<notebook colspan="4">
|
||||
<page string="Import Details">
|
||||
<field name="company_id" />
|
||||
<field name="date" />
|
||||
<field name="user_id" />
|
||||
<field name="state" />
|
||||
<field name="file" filename="file_name"/>
|
||||
<field name="file_name" invisible="1"/>
|
||||
<field name="format" />
|
||||
</page>
|
||||
<page string="Statements">
|
||||
<field name="statement_ids" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Import Log">
|
||||
<field name="log" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_account_banking_imported_file_tree">
|
||||
<field name="name">account.banking.imported.file.tree</field>
|
||||
<field name="model">account.banking.imported.file</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Imported Bank Statements Files" colors="red:state=='error';blue:state=='unfinished'">
|
||||
<field name="company_id" />
|
||||
<field name="date" />
|
||||
<field name="user_id" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_banking_imported_files">
|
||||
<field name="name">Imported Bank Statements Files</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.banking.imported.file</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- Add a menu item for it -->
|
||||
<menuitem name="Imported Bank Statements Files"
|
||||
id="menu_action_account_banking_imported_files"
|
||||
parent="account.menu_finance_bank_and_cash"
|
||||
action="action_account_banking_imported_files"
|
||||
sequence="15"
|
||||
/>
|
||||
|
||||
<!-- Add the import wizard to the menu -->
|
||||
<menuitem name="Import Bank Statements File"
|
||||
id="menu_account_banking_import_wizard"
|
||||
parent="account.menu_finance_bank_and_cash"
|
||||
action="wizard_account_banking_import_file"
|
||||
sequence="12"/>
|
||||
|
||||
<!-- Add the import wizard to the statement's right menu -->
|
||||
<act_window name="Import Bank Statements File"
|
||||
res_model="account.banking.bank.import"
|
||||
src_model="account.bank.statement"
|
||||
view_mode="form"
|
||||
target="new"
|
||||
key2="client_action_multi"
|
||||
id="act_account_banking_import_wizard"/>
|
||||
|
||||
<!-- Create right menu entry to see statements -->
|
||||
<act_window name="Bank Statements File"
|
||||
domain="[('id','=',banking_id)]"
|
||||
res_model="account.banking.imported.file"
|
||||
src_model="account.bank.statement"
|
||||
view_type="form"
|
||||
view_mode="tree,form"
|
||||
id="act_account_payment_account_bank_statement"/>
|
||||
|
||||
<!-- Move period_id from bank_statement form to bank_statement_line form
|
||||
-->
|
||||
<record id="view_banking_bank_statement_tree_1" model="ir.ui.view">
|
||||
<field name="name">account.bank.statement.tree.banking</field>
|
||||
<field name="inherit_id" ref="account.view_bank_statement_tree" />
|
||||
<field name="model">account.bank.statement</field>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Remove period from bank statement -->
|
||||
<field name="period_id" position="replace">
|
||||
<!-- Add invisible column for identification of import file
|
||||
-->
|
||||
<field name="banking_id" invisible="True" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_banking_bank_statement_form_1" model="ir.ui.view">
|
||||
<field name="name">account.bank.statement.form.banking-1</field>
|
||||
<field name="inherit_id" ref="account.view_bank_statement_form" />
|
||||
<field name="model">account.bank.statement</field>
|
||||
<field name="sequence" eval="60"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<page string="Transactions" position="after">
|
||||
<page string="Journal Entries" name="move_live_ids">
|
||||
<field colspan="4" name="move_line_ids" nolabel="1"/>
|
||||
</page>
|
||||
</page>
|
||||
<field name="period_id" position="replace"/>
|
||||
|
||||
<xpath expr="//page[@string='Transactions']/field/tree"
|
||||
position="attributes">
|
||||
<attribute name="colors">black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state == 'draft';</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='name']"
|
||||
position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='name']"
|
||||
position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- Add invisible field for identification of import file
|
||||
on bank statements
|
||||
-->
|
||||
<field name="balance_end_real" position="after">
|
||||
<field name="banking_id" invisible="True"/>
|
||||
</field>
|
||||
|
||||
<!-- Show bank accounts in account_bank_statement_line to
|
||||
enable manualcoupling of bank account numbers to
|
||||
statement lines and harvest info for future matching
|
||||
in the process.
|
||||
-->
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='partner_id']"
|
||||
position="after">
|
||||
<field name="link_partner_ok" invisible="1" />
|
||||
<button name="link_partner"
|
||||
string="Link partner"
|
||||
icon="terp-partner"
|
||||
type="object"
|
||||
attrs="{'invisible': [('link_partner_ok', '=', False)]}"
|
||||
/>
|
||||
<!-- TODO set partner_id when partner_bank_id changes -->
|
||||
<field name="partner_bank_id"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='partner_id']"
|
||||
position="after">
|
||||
<field name="partner_bank_id"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/tree//field[@name='account_id']"
|
||||
position="attributes">
|
||||
<attribute name="attrs">{'readonly': ['|', ('state', '!=', 'draft'), ('match_type', '!=', False)]}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='amount']"
|
||||
position="after">
|
||||
<field name="match_type"/>
|
||||
<field name="residual"/>
|
||||
<field name="parent_id" invisible="1" />
|
||||
<button name="match_wizard"
|
||||
string="Match"
|
||||
icon="terp-gtk-jump-to-ltr"
|
||||
attrs="{'invisible': ['|', ('parent_id', '!=', False),
|
||||
('state', '!=', 'draft')]}"
|
||||
type="object"
|
||||
/>
|
||||
<field name="match_multi" invisible="1"/>
|
||||
<field name="duplicate" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<button name="confirm" states="draft"
|
||||
string="Confirm transaction"
|
||||
icon="gtk-ok"
|
||||
type="object"/>
|
||||
<button name="cancel" states="confirmed"
|
||||
string="Cancel transaction"
|
||||
icon="gtk-cancel"
|
||||
type="object"/>
|
||||
<field name="invoice_id"/>
|
||||
<field name="reconcile_id"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='amount']"
|
||||
position="after">
|
||||
<field name="state"/>
|
||||
<field name="invoice_id"/>
|
||||
<field name="reconcile_id"/>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_bank_statement_line_tree">
|
||||
<field name="name">Bank statement line tree view</field>
|
||||
<field name="model">account.bank.statement.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Statement lines" colors="black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state=='draft';">
|
||||
<field name="sequence" readonly="1" invisible="1"/>
|
||||
<field name="date"/>
|
||||
<field name="name"/>
|
||||
<field name="ref"/>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="link_partner_ok" invisible="1" />
|
||||
<button name="link_partner"
|
||||
string="Link partner"
|
||||
icon="terp-partner"
|
||||
type="object"
|
||||
attrs="{'invisible': [('link_partner_ok', '=', False)]}"
|
||||
/>
|
||||
<!-- TODO set partner_id when partner_bank_id changes -->
|
||||
<field name="partner_bank_id"/>
|
||||
<field name="type" on_change="onchange_type(partner_id, type)"/>
|
||||
<!-- TODO note the references to parent from the statement form view -->
|
||||
<field domain="[('journal_id','=',parent.journal_id)]"
|
||||
attrs="{'readonly': ['|', ('state', '!=', 'draft'), ('match_type', '!=', '')]}" name="account_id"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '<>', 'view')]"/>
|
||||
<field name="amount"/>
|
||||
<field name="match_type"/>
|
||||
<field name="residual"/>
|
||||
<field name="parent_id" invisible="1" />
|
||||
<button name="match_wizard" states="draft"
|
||||
string="Match"
|
||||
icon="terp-gtk-jump-to-ltr"
|
||||
attrs="{'invisible': ['|', ('parent_id', '!=', False),
|
||||
('state', '!=', 'draft')]}"
|
||||
type="object"
|
||||
/>
|
||||
<field name="match_multi" invisible="1"/>
|
||||
<field name="duplicate" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<button name="confirm" states="draft"
|
||||
string="Confirm transaction"
|
||||
icon="gtk-ok"
|
||||
type="object"/>
|
||||
<button name="cancel" states="confirmed"
|
||||
string="Cancel transaction"
|
||||
icon="gtk-cancel"
|
||||
type="object"/>
|
||||
<field name="invoice_id"/>
|
||||
<field name="reconcile_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- search view for bank statement lines -->
|
||||
<record id="view_account_bank_statement_line_search" model="ir.ui.view">
|
||||
<field name="name">account.bank.statement.line.search</field>
|
||||
<field name="model">account.bank.statement.line</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Bank Transactions ">
|
||||
<group>
|
||||
<filter string="Draft" domain="[('state','=','draft')]" icon="terp-camera_test"/>
|
||||
<filter string="Confirmed" domain="[('state','=','confirmed')]" icon="terp-dialog-close"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="ref"/>
|
||||
<field name="type"/>
|
||||
<field name="period_id"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="partner_bank_id"/>
|
||||
<field name="account_id"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="State" context="{'group_by': 'state'}" icon="terp-stock_effects-object-colorize"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Add a shortcut menu for bank accounts -->
|
||||
<record model="ir.actions.act_window" id="action_bank_statement_line_tree">
|
||||
<field name="name">Bank Transactions</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.bank.statement.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_account_bank_statement_line_search"/>
|
||||
</record>
|
||||
<menuitem string="Bank Transactions"
|
||||
action="action_bank_statement_line_tree"
|
||||
id="menu_bank_statement_line_tree"
|
||||
parent="account.menu_finance_bank_and_cash" sequence="8"/>
|
||||
</data>
|
||||
</openerp>
|
||||
1942
__unported__/account_banking/banking_import_transaction.py
Normal file
1942
__unported__/account_banking/banking_import_transaction.py
Normal file
File diff suppressed because it is too large
Load Diff
17
__unported__/account_banking/data/account_banking_data.xml
Normal file
17
__unported__/account_banking/data/account_banking_data.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Unset readonly state of country_id for ordinary account.
|
||||
Leaving it will make it impossible to use bank accounts with
|
||||
addresses outside the companies country.
|
||||
Ratio: one can have bank accounts in foreign banks. Foreign
|
||||
addresses not automatically involve international banking.
|
||||
-->
|
||||
<record id="base.bank_normal_field_contry" model="res.partner.bank.type.field">
|
||||
<field name="name">country_id</field>
|
||||
<field name="bank_type_id" ref="base.bank_normal"/>
|
||||
<field eval="False" name="required"/>
|
||||
<field eval="False" name="readonly"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
1626
__unported__/account_banking/i18n/account_banking.pot
Normal file
1626
__unported__/account_banking/i18n/account_banking.pot
Normal file
File diff suppressed because it is too large
Load Diff
1677
__unported__/account_banking/i18n/da.po
Normal file
1677
__unported__/account_banking/i18n/da.po
Normal file
File diff suppressed because it is too large
Load Diff
759
__unported__/account_banking/i18n/da_DK.po
Normal file
759
__unported__/account_banking/i18n/da_DK.po
Normal file
@@ -0,0 +1,759 @@
|
||||
# Danish translation for account-banking
|
||||
# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
|
||||
# This file is distributed under the same license as the account-banking package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: account-banking\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2010-07-16 14:58:26+0000\n"
|
||||
"PO-Revision-Date: 2010-02-06 14:36+0000\n"
|
||||
"Last-Translator: nanker <Unknown>\n"
|
||||
"Language-Team: Danish <da@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Number of bank costs invoices created"
|
||||
msgstr "Totalt antal transaktioner"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Results:"
|
||||
msgstr "Resultater:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of errors found"
|
||||
msgstr "Antal fejl fundet"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
msgid "Select the processing details:"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s (ref: %(ref)s) to invoice: '\n"
|
||||
" '%(no_candidates)s candidates found; can\'t choose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid format"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,date_done:0
|
||||
msgid "Date Confirmed"
|
||||
msgstr "Dato bekræftet"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_statements,open_statements:0
|
||||
msgid "_View Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,end:0
|
||||
#: wizard_button:account_banking.banking_import,view_statements,end:0
|
||||
msgid "_Close"
|
||||
msgstr "_Luk"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,bank_partner_id:0
|
||||
msgid "Bank Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_account_settings
|
||||
msgid "Default Journal for Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,init,file:0
|
||||
msgid "Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"More than one bank account was found with the same number %(account_no)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of transactions"
|
||||
msgstr "Totalt antal transaktioner"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Account move line \"%s\" is not valid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment is received. This can be "
|
||||
"needed when a customer pays in advance or when no matching invoice can be "
|
||||
"found. Mind that you can correct movements before confirming them."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Bank account %(account_no)s was not found in the database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Generation of Bank Costs Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions skipped due to errors"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The expected balance (%.2f) is different '\n"
|
||||
" 'than the computed one. (%.2f)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,invoice_journal_id:0
|
||||
#, fuzzy
|
||||
msgid "Costs Journal"
|
||||
msgstr "Journal"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements skipped due to errors"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid IBAN account number!"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Import Settings for Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment was signaled. This can happen "
|
||||
"when a direct debit payment is cancelled by a customer, or when no matching "
|
||||
"payment can be found. Mind that you can correct movements before confirming "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Unable to import parser %(parser)s. Parser class not found."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,file:0
|
||||
msgid "Raw Data"
|
||||
msgstr "Rå data"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Cancelled"
|
||||
msgstr "Annulleret"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Insufficient data to select online '\n"
|
||||
" 'conversion database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,statement_ids:0
|
||||
msgid "Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid "Default debit account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Unknown Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,end:0
|
||||
msgid "_Cancel"
|
||||
msgstr "_Annuller"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Draft"
|
||||
msgstr "Udkast"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,date:0
|
||||
msgid "Import Date"
|
||||
msgstr "Importer dato"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Confirmed"
|
||||
msgstr "Bekræftet"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_res_partner_banks
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_accounts
|
||||
msgid "Bank Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Accounts for Unknown Movements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.bank.statement:0
|
||||
msgid "Confirm"
|
||||
msgstr "Bekræft"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for account %(bank_account)s, '\n"
|
||||
msgstr " 'but no default journal was defined."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid "Default credit account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,international:0
|
||||
msgid "International Transaction"
|
||||
msgstr "International transaktion"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Please verify that an account is defined in the journal."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,trans:0
|
||||
msgid "Bank Transaction ID"
|
||||
msgstr "Bank transaktion ID"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "This is the journal used to create invoices for bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statement %(id)s known - skipped"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,costs_account_id:0
|
||||
msgid ""
|
||||
"The account to use when the bank invoices its own costs. Leave it blank to "
|
||||
"disable automatic invoice generation on bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Fejl !"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_normal_field_contry
|
||||
msgid "country_id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Rejected"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_journals
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_journals
|
||||
msgid "Default Import Settings for Bank Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.wizard,name:account_banking.wizard_account_banking_import_file
|
||||
#: model:ir.ui.menu,name:account_banking.menu_account_banking_import_wizard
|
||||
msgid "Import Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account_banking.banking_import,init,file:0
|
||||
msgid ""
|
||||
"The Transactions File to import. Please note that while it is perfectly safe "
|
||||
"to reload the same file multiple times or to load in timeframe overlapping "
|
||||
"statements files, there are formats that may introduce different sequencing, "
|
||||
"which may create double entries.\n"
|
||||
"\n"
|
||||
"To stay on the safe side, always load bank statements files using the same "
|
||||
"format."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/sepa/bbantoiban.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr "Ugyldig XML for View Architecture!"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Imported Bank Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,description:account_banking.module_meta_information
|
||||
msgid ""
|
||||
"\n"
|
||||
" Module to do banking.\n"
|
||||
"\n"
|
||||
" Note: This module is depending on BeautifulSoup.\n"
|
||||
"\n"
|
||||
" This modules tries to combine all current banking import and export\n"
|
||||
" schemes. Rationale for this is that it is quite common to have foreign\n"
|
||||
" bank account numbers next to national bank account numbers. The current\n"
|
||||
" approach, which hides the national banking interface schemes in the\n"
|
||||
" l10n_xxx modules, makes it very difficult to use these simultanious.\n"
|
||||
" A more banking oriented approach seems more logical and cleaner.\n"
|
||||
"\n"
|
||||
" Changes to default OpenERP:\n"
|
||||
"\n"
|
||||
" * Puts focus on the real life messaging with banks:\n"
|
||||
" + Bank statement lines upgraded to independent bank transactions.\n"
|
||||
" + Banking statements have no special accountancy meaning, they're "
|
||||
"just\n"
|
||||
" message envelopes for a number of bank transactions.\n"
|
||||
" + Bank statements can be either encoded by hand to reflect the "
|
||||
"document\n"
|
||||
" version of Bank Statements, or created as an optional side effect "
|
||||
"of\n"
|
||||
" importing Bank Transactions.\n"
|
||||
"\n"
|
||||
" * Preparations for SEPA:\n"
|
||||
" + IBAN accounts are the standard in the SEPA countries\n"
|
||||
" + local accounts are derived from SEPA (excluding Turkey) but are\n"
|
||||
" considered to be identical to the corresponding SEPA account.\n"
|
||||
" + Banks are identified with either Country + Bank code + Branch code "
|
||||
"or BIC\n"
|
||||
" + Each bank can have its own pace in introducing SEPA into their\n"
|
||||
" communication with their customers.\n"
|
||||
" + National online databases can be used to convert BBAN's to IBAN's.\n"
|
||||
" + The SWIFT database is consulted for bank information.\n"
|
||||
"\n"
|
||||
" * Adds dropin extensible import facility for bank communication in:\n"
|
||||
" - Drop-in input parser development.\n"
|
||||
" - MultiBank (NL) format transaction files available as\n"
|
||||
" account_banking_nl_multibank,\n"
|
||||
"\n"
|
||||
" * Extends payments for digital banking:\n"
|
||||
" + Adapted workflow in payments to reflect banking operations\n"
|
||||
" + Relies on account_payment mechanics to extend with export "
|
||||
"generators.\n"
|
||||
" - ClieOp3 (NL) payment and direct debit orders files available as\n"
|
||||
" account_banking_nl_clieop\n"
|
||||
"\n"
|
||||
" * Additional features for the import/export mechanism:\n"
|
||||
" + Automatic matching and creation of bank accounts, banks and "
|
||||
"partners,\n"
|
||||
" during import of statements.\n"
|
||||
" + Automatic matching with invoices and payments.\n"
|
||||
" + Sound import mechanism, allowing multiple imports of the same\n"
|
||||
" transactions repeated over multiple files.\n"
|
||||
" + Journal configuration per bank account.\n"
|
||||
" + Business logic and format parsing strictly separated to ease the\n"
|
||||
" development of new parsers.\n"
|
||||
" + No special configuration needed for the parsers, new parsers are\n"
|
||||
" recognized and made available at server (re)start.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Import Bank Transactions File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Account %(account_no)s is not owned by %(partner)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,import:0
|
||||
msgid "_Ok"
|
||||
msgstr "_Ok"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "More then one possible match found for partner with name %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,state:0
|
||||
#: field:payment.line,export_state:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "ERROR!"
|
||||
msgstr "FEJL!"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s '\n"
|
||||
" '(ref: %(ref)s) to invoice: '\n"
|
||||
" 'invoice %(invoice)s was already paid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number has the wrong format for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,currency:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,msg:0
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,company_id:0
|
||||
#: field:account.banking.imported.file,company_id:0
|
||||
#: wizard_field:account_banking.banking_import,init,company:0
|
||||
msgid "Company"
|
||||
msgstr "Virksomhed"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,view_error,log:0
|
||||
#: wizard_field:account_banking.banking_import,view_statements,log:0
|
||||
msgid "Log"
|
||||
msgstr "Log"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "Invalid value for transfer_type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Insufficient data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Configration Error !"
|
||||
msgstr "Konfigurationsfejl !"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.act_account_payment_account_bank_statement
|
||||
msgid "Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "No suitable period found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_imported_files
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_imported_files
|
||||
msgid "Imported Bank Statements Files"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement,banking_id:0
|
||||
msgid "Imported File"
|
||||
msgstr "Importerede filer"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,log:0
|
||||
msgid "Import Log"
|
||||
msgstr "Importer log"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping periods for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "The imported statements appear to be invalid! Check your file."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements loaded"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_actions
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_settings
|
||||
msgid "Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Error"
|
||||
msgstr "Fejl"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Unable to reconcile entry \"%s\": %.2f"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No suitable fiscal year found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Import Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,period_id:0
|
||||
msgid "Period"
|
||||
msgstr "Periode"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Done"
|
||||
msgstr "Udført"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:payment.order:0
|
||||
msgid "Select Invoices to Pay"
|
||||
msgstr "Vælg faktura til betaling"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,user_id:0
|
||||
msgid "Responsible User"
|
||||
msgstr "Ansvarlig bruger"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The statement balance is incorrect !\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Unfinished"
|
||||
msgstr "Ikke afsluttet"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for unknown account %(bank_account)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,shortdesc:account_banking.module_meta_information
|
||||
msgid "Account Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,open_import:0
|
||||
msgid "_View Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The IBAN number doesn't seem to be correct"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,format:0
|
||||
#: wizard_field:account_banking.banking_import,init,parser:0
|
||||
msgid "File Format"
|
||||
msgstr "Filformat"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping fiscal years found for date %(date)s and company %"
|
||||
"(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,journal_id:0
|
||||
msgid "Journal"
|
||||
msgstr "Journal"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,costs_account_id:0
|
||||
#, fuzzy
|
||||
msgid "Bank Costs Account"
|
||||
msgstr "Bankkonto"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Finished"
|
||||
msgstr "Afsluttet"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Bank Account Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,partner_bank_id:0
|
||||
#: field:account.banking.account.settings,partner_bank_id:0
|
||||
msgid "Bank Account"
|
||||
msgstr "Bankkonto"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions loaded"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number appears to be invalid for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_acc_number_field
|
||||
msgid "acc_number"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Number of transactions matched"
|
||||
msgstr "Totalt antal transaktioner"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,bank_partner_id:0
|
||||
msgid ""
|
||||
"The partner to use for bank costs. Banks are not partners by default. You "
|
||||
"will most likely have to create one."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account entries lines are not in valid state."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_imported_file
|
||||
msgid "Imported Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Statement %(statement_id)s for account %(bank_account)s' \n"
|
||||
" ' uses different currency than the defined bank "
|
||||
"journal."
|
||||
msgstr ""
|
||||
1695
__unported__/account_banking/i18n/en.po
Normal file
1695
__unported__/account_banking/i18n/en.po
Normal file
File diff suppressed because it is too large
Load Diff
1677
__unported__/account_banking/i18n/es_ES.po
Normal file
1677
__unported__/account_banking/i18n/es_ES.po
Normal file
File diff suppressed because it is too large
Load Diff
1689
__unported__/account_banking/i18n/hr.po
Normal file
1689
__unported__/account_banking/i18n/hr.po
Normal file
File diff suppressed because it is too large
Load Diff
774
__unported__/account_banking/i18n/hr_HR.po
Normal file
774
__unported__/account_banking/i18n/hr_HR.po
Normal file
@@ -0,0 +1,774 @@
|
||||
# Croatian translation for account-banking
|
||||
# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
|
||||
# This file is distributed under the same license as the account-banking package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: account-banking\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2010-07-16 14:58:26+0000\n"
|
||||
"PO-Revision-Date: 2010-02-12 01:28+0000\n"
|
||||
"Last-Translator: goranc <goranc@gmail.com>\n"
|
||||
"Language-Team: Croatian <hr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Number of bank costs invoices created"
|
||||
msgstr "Broj učitanih transakcija"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Results:"
|
||||
msgstr "Rezultati:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of errors found"
|
||||
msgstr "Broj pronađenih grešaka"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
msgid "Select the processing details:"
|
||||
msgstr "Odaberite detalje obrade:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s (ref: %(ref)s) to invoice: '\n"
|
||||
" '%(no_candidates)s candidates found; can\'t choose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid format"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr "Pogrešno ime modela u definiciji akcije."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,date_done:0
|
||||
msgid "Date Confirmed"
|
||||
msgstr "Datum potvrđen"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_statements,open_statements:0
|
||||
msgid "_View Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,end:0
|
||||
#: wizard_button:account_banking.banking_import,view_statements,end:0
|
||||
msgid "_Close"
|
||||
msgstr "_Zatvori"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,bank_partner_id:0
|
||||
msgid "Bank Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_account_settings
|
||||
msgid "Default Journal for Bank Account"
|
||||
msgstr "Predefinirana temeljnica za bankovni račun"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,init,file:0
|
||||
msgid "Statements File"
|
||||
msgstr "Datoteka sa stavkama"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"More than one bank account was found with the same number %(account_no)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of transactions"
|
||||
msgstr "Ukupan broj transakcija"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Account move line \"%s\" is not valid"
|
||||
msgstr "Redak prijenosa računa \"%s\" nije ispravan"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment is received. This can be "
|
||||
"needed when a customer pays in advance or when no matching invoice can be "
|
||||
"found. Mind that you can correct movements before confirming them."
|
||||
msgstr ""
|
||||
"Račun za upis primljene neočekivane uplate. To može biti potrebno kada "
|
||||
"klijent plaća unaprijed, ili ako nema podudarne fakture. Omogućeno je "
|
||||
"ispravljanje upisa prije potvrde."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Bank account %(account_no)s was not found in the database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Generation of Bank Costs Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions skipped due to errors"
|
||||
msgstr "Broj transakcija preskočenih zbog pogreški"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The expected balance (%.2f) is different '\n"
|
||||
" 'than the computed one. (%.2f)"
|
||||
msgstr ""
|
||||
"Očekivani saldo (%.2f) je različit '\n"
|
||||
" 'od izračunatog. (%.2f)"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,invoice_journal_id:0
|
||||
#, fuzzy
|
||||
msgid "Costs Journal"
|
||||
msgstr "Temeljnica"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements skipped due to errors"
|
||||
msgstr "Broj stavki preskočenih zbog pogreški"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid IBAN account number!"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Import Settings for Bank Account"
|
||||
msgstr "Predefinirane postavke za učitavanje podataka za bankovni račun"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment was signaled. This can happen "
|
||||
"when a direct debit payment is cancelled by a customer, or when no matching "
|
||||
"payment can be found. Mind that you can correct movements before confirming "
|
||||
"them."
|
||||
msgstr ""
|
||||
"Račun za upis signalizirane neočekivane uplate. To se može dogoditi kada je "
|
||||
"otkazana uplata izravnim zaduženjem od strane kupca, ili kada se ne može "
|
||||
"pronaći podudarna uplata. Omogućeno je ispravljanje upisa prije potvrde."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Unable to import parser %(parser)s. Parser class not found."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,file:0
|
||||
msgid "Raw Data"
|
||||
msgstr "nepripremljeni podaci"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Cancelled"
|
||||
msgstr "Poništeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Insufficient data to select online '\n"
|
||||
" 'conversion database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,statement_ids:0
|
||||
msgid "Statements"
|
||||
msgstr "Izvodi"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid "Default debit account"
|
||||
msgstr "Predefinirani račun terećenja"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Unknown Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,end:0
|
||||
msgid "_Cancel"
|
||||
msgstr "_Odustani"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Draft"
|
||||
msgstr "Nedovršeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,date:0
|
||||
msgid "Import Date"
|
||||
msgstr "Datum učitavanja"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Confirmed"
|
||||
msgstr "Potvrđeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_res_partner_banks
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_accounts
|
||||
msgid "Bank Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Accounts for Unknown Movements"
|
||||
msgstr "Predefinirani računi za nedefinirane promete"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.bank.statement:0
|
||||
msgid "Confirm"
|
||||
msgstr "Potvrdi"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for account %(bank_account)s, '\n"
|
||||
msgstr " 'but no default journal was defined."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid "Default credit account"
|
||||
msgstr "Predefinirani račun odobrenja"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,international:0
|
||||
msgid "International Transaction"
|
||||
msgstr "Međunaradni prijenos"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Please verify that an account is defined in the journal."
|
||||
msgstr "Molimo provjerite da je račun definiran u temeljnici"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,trans:0
|
||||
msgid "Bank Transaction ID"
|
||||
msgstr "Oznaka bankovne transakcije"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "This is the journal used to create invoices for bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statement %(id)s known - skipped"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Sent"
|
||||
msgstr "Poslano"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,costs_account_id:0
|
||||
msgid ""
|
||||
"The account to use when the bank invoices its own costs. Leave it blank to "
|
||||
"disable automatic invoice generation on bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Greška !"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_normal_field_contry
|
||||
msgid "country_id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Rejected"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_journals
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_journals
|
||||
msgid "Default Import Settings for Bank Accounts"
|
||||
msgstr "Predefinirane postavke učitavanja za bankovne račune"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.wizard,name:account_banking.wizard_account_banking_import_file
|
||||
#: model:ir.ui.menu,name:account_banking.menu_account_banking_import_wizard
|
||||
msgid "Import Bank Statements File"
|
||||
msgstr "Učitaj datoteku izvoda banke"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account_banking.banking_import,init,file:0
|
||||
msgid ""
|
||||
"The Transactions File to import. Please note that while it is perfectly safe "
|
||||
"to reload the same file multiple times or to load in timeframe overlapping "
|
||||
"statements files, there are formats that may introduce different sequencing, "
|
||||
"which may create double entries.\n"
|
||||
"\n"
|
||||
"To stay on the safe side, always load bank statements files using the same "
|
||||
"format."
|
||||
msgstr ""
|
||||
"Datoteka s transakcijama za učitavanje. Imajte na umu da je potpuno sigurno "
|
||||
"ponovno učitavanje iste datoteke ili učitati datoteku izvoda koji se "
|
||||
"vremenski preklapaju, ipak postoje formati datoteka koji mogu uzrokovati "
|
||||
"različiti redoslijed, što može dovesti do dvostrukog unosa.\n"
|
||||
"\n"
|
||||
"Za sigurnost, uvijek učitati datoteke koristeći bankovni izvod istog formata."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/sepa/bbantoiban.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr "Neispravan XML za arhitekturu prikaza!"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Imported Bank Statements"
|
||||
msgstr "Učitani izvodi banke"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,description:account_banking.module_meta_information
|
||||
msgid ""
|
||||
"\n"
|
||||
" Module to do banking.\n"
|
||||
"\n"
|
||||
" Note: This module is depending on BeautifulSoup.\n"
|
||||
"\n"
|
||||
" This modules tries to combine all current banking import and export\n"
|
||||
" schemes. Rationale for this is that it is quite common to have foreign\n"
|
||||
" bank account numbers next to national bank account numbers. The current\n"
|
||||
" approach, which hides the national banking interface schemes in the\n"
|
||||
" l10n_xxx modules, makes it very difficult to use these simultanious.\n"
|
||||
" A more banking oriented approach seems more logical and cleaner.\n"
|
||||
"\n"
|
||||
" Changes to default OpenERP:\n"
|
||||
"\n"
|
||||
" * Puts focus on the real life messaging with banks:\n"
|
||||
" + Bank statement lines upgraded to independent bank transactions.\n"
|
||||
" + Banking statements have no special accountancy meaning, they're "
|
||||
"just\n"
|
||||
" message envelopes for a number of bank transactions.\n"
|
||||
" + Bank statements can be either encoded by hand to reflect the "
|
||||
"document\n"
|
||||
" version of Bank Statements, or created as an optional side effect "
|
||||
"of\n"
|
||||
" importing Bank Transactions.\n"
|
||||
"\n"
|
||||
" * Preparations for SEPA:\n"
|
||||
" + IBAN accounts are the standard in the SEPA countries\n"
|
||||
" + local accounts are derived from SEPA (excluding Turkey) but are\n"
|
||||
" considered to be identical to the corresponding SEPA account.\n"
|
||||
" + Banks are identified with either Country + Bank code + Branch code "
|
||||
"or BIC\n"
|
||||
" + Each bank can have its own pace in introducing SEPA into their\n"
|
||||
" communication with their customers.\n"
|
||||
" + National online databases can be used to convert BBAN's to IBAN's.\n"
|
||||
" + The SWIFT database is consulted for bank information.\n"
|
||||
"\n"
|
||||
" * Adds dropin extensible import facility for bank communication in:\n"
|
||||
" - Drop-in input parser development.\n"
|
||||
" - MultiBank (NL) format transaction files available as\n"
|
||||
" account_banking_nl_multibank,\n"
|
||||
"\n"
|
||||
" * Extends payments for digital banking:\n"
|
||||
" + Adapted workflow in payments to reflect banking operations\n"
|
||||
" + Relies on account_payment mechanics to extend with export "
|
||||
"generators.\n"
|
||||
" - ClieOp3 (NL) payment and direct debit orders files available as\n"
|
||||
" account_banking_nl_clieop\n"
|
||||
"\n"
|
||||
" * Additional features for the import/export mechanism:\n"
|
||||
" + Automatic matching and creation of bank accounts, banks and "
|
||||
"partners,\n"
|
||||
" during import of statements.\n"
|
||||
" + Automatic matching with invoices and payments.\n"
|
||||
" + Sound import mechanism, allowing multiple imports of the same\n"
|
||||
" transactions repeated over multiple files.\n"
|
||||
" + Journal configuration per bank account.\n"
|
||||
" + Business logic and format parsing strictly separated to ease the\n"
|
||||
" development of new parsers.\n"
|
||||
" + No special configuration needed for the parsers, new parsers are\n"
|
||||
" recognized and made available at server (re)start.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Import Bank Transactions File"
|
||||
msgstr "Učitaj datoteku bankovnih transakcija"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Account %(account_no)s is not owned by %(partner)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,import:0
|
||||
msgid "_Ok"
|
||||
msgstr "_U redu"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "More then one possible match found for partner with name %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,state:0
|
||||
#: field:payment.line,export_state:0
|
||||
msgid "State"
|
||||
msgstr "Status"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "ERROR!"
|
||||
msgstr "Greška!"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s '\n"
|
||||
" '(ref: %(ref)s) to invoice: '\n"
|
||||
" 'invoice %(invoice)s was already paid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number has the wrong format for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,currency:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,msg:0
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,company_id:0
|
||||
#: field:account.banking.imported.file,company_id:0
|
||||
#: wizard_field:account_banking.banking_import,init,company:0
|
||||
msgid "Company"
|
||||
msgstr "Tvrtka"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,view_error,log:0
|
||||
#: wizard_field:account_banking.banking_import,view_statements,log:0
|
||||
msgid "Log"
|
||||
msgstr "Dnevnik izmjena"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "Invalid value for transfer_type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Insufficient data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Configration Error !"
|
||||
msgstr "Konfiguracijska pogreška !"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.act_account_payment_account_bank_statement
|
||||
msgid "Bank Statements File"
|
||||
msgstr "Datoteka bankovnog izvoda"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own."
|
||||
msgstr "Ovo je okvir. Izvedbu provedite sami."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "No suitable period found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_imported_files
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_imported_files
|
||||
msgid "Imported Bank Statements Files"
|
||||
msgstr "Učitana datoteka bankovnog izvoda"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement,banking_id:0
|
||||
msgid "Imported File"
|
||||
msgstr "Učitana datoteka"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,log:0
|
||||
msgid "Import Log"
|
||||
msgstr "Dnevnik učitavanja"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping periods for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "The imported statements appear to be invalid! Check your file."
|
||||
msgstr "Učitane stavke nisu korektne! Provjerite datoteku."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements loaded"
|
||||
msgstr "Broj učitanih stavki"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_actions
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_settings
|
||||
msgid "Banking"
|
||||
msgstr "Bankarstvo"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Error"
|
||||
msgstr "Greška"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of statements"
|
||||
msgstr "Ukupan broj stavki"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Unable to reconcile entry \"%s\": %.2f"
|
||||
msgstr "Nije moguće uskladiti stavku \"%s\".%.2f"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No suitable fiscal year found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Import Details"
|
||||
msgstr "Pregled učitanih stavki"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,period_id:0
|
||||
msgid "Period"
|
||||
msgstr "Razdoblje"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Done"
|
||||
msgstr "Završeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:payment.order:0
|
||||
msgid "Select Invoices to Pay"
|
||||
msgstr "Odaberite fakture za plaćanje"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,user_id:0
|
||||
msgid "Responsible User"
|
||||
msgstr "Odgovorni korisnik"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The statement balance is incorrect !\n"
|
||||
msgstr "Saldo izvoda je netočan !\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
"Naziv objekta mora početi s x_ i ne smije sadržavati specijalne znakove !"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Unfinished"
|
||||
msgstr "Nedovršeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for unknown account %(bank_account)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,shortdesc:account_banking.module_meta_information
|
||||
msgid "Account Banking"
|
||||
msgstr "Bankovni računi"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,open_import:0
|
||||
msgid "_View Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The IBAN number doesn't seem to be correct"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,format:0
|
||||
#: wizard_field:account_banking.banking_import,init,parser:0
|
||||
msgid "File Format"
|
||||
msgstr "Format datoteke"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping fiscal years found for date %(date)s and company %"
|
||||
"(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,journal_id:0
|
||||
msgid "Journal"
|
||||
msgstr "Temeljnica"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,costs_account_id:0
|
||||
#, fuzzy
|
||||
msgid "Bank Costs Account"
|
||||
msgstr "Bankovni račun"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Finished"
|
||||
msgstr "Završeno"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Bank Account Details"
|
||||
msgstr "Stavke bankovnih računa"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,partner_bank_id:0
|
||||
#: field:account.banking.account.settings,partner_bank_id:0
|
||||
msgid "Bank Account"
|
||||
msgstr "Bankovni račun"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions loaded"
|
||||
msgstr "Broj učitanih transakcija"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number appears to be invalid for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_acc_number_field
|
||||
msgid "acc_number"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Number of transactions matched"
|
||||
msgstr "Broj učitanih transakcija"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,bank_partner_id:0
|
||||
msgid ""
|
||||
"The partner to use for bank costs. Banks are not partners by default. You "
|
||||
"will most likely have to create one."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account entries lines are not in valid state."
|
||||
msgstr "Stavke ovog računa nisu u valjanom stanju."
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_imported_file
|
||||
msgid "Imported Bank Statements File"
|
||||
msgstr "Učitane datoteke bankovnih izvoda"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Statement %(statement_id)s for account %(bank_account)s' \n"
|
||||
" ' uses different currency than the defined bank "
|
||||
"journal."
|
||||
msgstr ""
|
||||
1693
__unported__/account_banking/i18n/hu.po
Normal file
1693
__unported__/account_banking/i18n/hu.po
Normal file
File diff suppressed because it is too large
Load Diff
1679
__unported__/account_banking/i18n/nb.po
Normal file
1679
__unported__/account_banking/i18n/nb.po
Normal file
File diff suppressed because it is too large
Load Diff
1750
__unported__/account_banking/i18n/nl.po
Normal file
1750
__unported__/account_banking/i18n/nl.po
Normal file
File diff suppressed because it is too large
Load Diff
1677
__unported__/account_banking/i18n/pt_BR.po
Normal file
1677
__unported__/account_banking/i18n/pt_BR.po
Normal file
File diff suppressed because it is too large
Load Diff
1686
__unported__/account_banking/i18n/ro.po
Normal file
1686
__unported__/account_banking/i18n/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
773
__unported__/account_banking/i18n/ro_RO.po
Normal file
773
__unported__/account_banking/i18n/ro_RO.po
Normal file
@@ -0,0 +1,773 @@
|
||||
# Romanian translation for account-banking
|
||||
# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
|
||||
# This file is distributed under the same license as the account-banking package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: account-banking\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2010-07-16 14:58:26+0000\n"
|
||||
"PO-Revision-Date: 2010-05-24 22:26+0000\n"
|
||||
"Last-Translator: Lavinia Loredana Bertia <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of bank costs invoices created"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Results:"
|
||||
msgstr "Resultate:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of errors found"
|
||||
msgstr "Număr de erori găsite"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
msgid "Select the processing details:"
|
||||
msgstr "Selectați detaliile de procesare:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s (ref: %(ref)s) to invoice: '\n"
|
||||
" '%(no_candidates)s candidates found; can\'t choose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid format"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr "Nume invalid de model în definirea acțiunii"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,date_done:0
|
||||
msgid "Date Confirmed"
|
||||
msgstr "Dată confirmată"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_statements,open_statements:0
|
||||
msgid "_View Statements"
|
||||
msgstr "_Vizualizează extrasurile de cont"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,end:0
|
||||
#: wizard_button:account_banking.banking_import,view_statements,end:0
|
||||
msgid "_Close"
|
||||
msgstr "_Închide"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,bank_partner_id:0
|
||||
msgid "Bank Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_account_settings
|
||||
msgid "Default Journal for Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,init,file:0
|
||||
msgid "Statements File"
|
||||
msgstr "Fișier de extrasuri de cont"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"More than one bank account was found with the same number %(account_no)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of transactions"
|
||||
msgstr "Număr total de tranzacții"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Account move line \"%s\" is not valid"
|
||||
msgstr "înregistrarea contabilă \"%s\" nu este validă"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment is received. This can be "
|
||||
"needed when a customer pays in advance or when no matching invoice can be "
|
||||
"found. Mind that you can correct movements before confirming them."
|
||||
msgstr ""
|
||||
"Contul ce trebuie folosit când este primită o plată neașteptată. Acesta "
|
||||
"poate fi necesitat când un client plătește în avans sau când nu este găsită "
|
||||
"factura aferentă. Tranzacțiile pot fi corectate înainte de a fi confirmate."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Bank account %(account_no)s was not found in the database"
|
||||
msgstr "Contul bancar %(account_no)s nu a fost găsit în baza de date."
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Generation of Bank Costs Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions skipped due to errors"
|
||||
msgstr "S-a sărit peste o serie de tranzacții din cauza unor erori."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The expected balance (%.2f) is different '\n"
|
||||
" 'than the computed one. (%.2f)"
|
||||
msgstr ""
|
||||
"Soldul preconizat (%.2f) este diferit '\n"
|
||||
" ' de cel calculat. (%.2f)"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "Costs Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements skipped due to errors"
|
||||
msgstr "S-a sărit peste o serie de extrasuri de cont din cauza unor erori"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid IBAN account number!"
|
||||
msgstr "IBAN invalid!"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Import Settings for Bank Account"
|
||||
msgstr "Setări implicite de importare pentru Contul Bancar"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment was signaled. This can happen "
|
||||
"when a direct debit payment is cancelled by a customer, or when no matching "
|
||||
"payment can be found. Mind that you can correct movements before confirming "
|
||||
"them."
|
||||
msgstr ""
|
||||
"Contul ce trebuie folosit când este semnalată o plată neașteptată. Aceasta "
|
||||
"se poate întâmpla când un client anulează un debit direct, sau când nu este "
|
||||
"găsită plata aferentă. Tranzacțiile pot fi modificate înainte de a fi "
|
||||
"confirmate."
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Unable to import parser %(parser)s. Parser class not found."
|
||||
msgstr ""
|
||||
"Nu se poate importa analizatorul %(parser)s. Categoria analizatorului nu a "
|
||||
"fost găsită."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,file:0
|
||||
msgid "Raw Data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Cancelled"
|
||||
msgstr "Anulat"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Insufficient data to select online '\n"
|
||||
" 'conversion database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,statement_ids:0
|
||||
msgid "Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid "Default debit account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Unknown Bank"
|
||||
msgstr "Bancă necunoscută"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,end:0
|
||||
msgid "_Cancel"
|
||||
msgstr "_Anulează"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Draft"
|
||||
msgstr "Schiță"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,date:0
|
||||
msgid "Import Date"
|
||||
msgstr "Importă data"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Confirmed"
|
||||
msgstr "Confirmat"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_res_partner_banks
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_accounts
|
||||
msgid "Bank Accounts"
|
||||
msgstr "Conturi bancare"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Accounts for Unknown Movements"
|
||||
msgstr "Conturi Implicite pentru Tranzacții Necunoscute"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.bank.statement:0
|
||||
msgid "Confirm"
|
||||
msgstr "Confirmă"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Statements found for account %(bank_account)s, '\n"
|
||||
msgstr ""
|
||||
"Extrasuri de cont găsite pentru contul %(bank_account)s, '\n"
|
||||
" ' dar s-a setat nici un jurnal implicit."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid "Default credit account"
|
||||
msgstr "Cont de credit implicit"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,international:0
|
||||
msgid "International Transaction"
|
||||
msgstr "Tranzacție Internațională"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Please verify that an account is defined in the journal."
|
||||
msgstr "Verificaţi dacă acest cont este definit în jurnal."
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,trans:0
|
||||
msgid "Bank Transaction ID"
|
||||
msgstr "ID-ul Tranzacției Bancare"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "This is the journal used to create invoices for bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statement %(id)s known - skipped"
|
||||
msgstr "Extrasul %(id)s este recunoscut - s-a sărit peste el"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Sent"
|
||||
msgstr "S-a trimis"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,costs_account_id:0
|
||||
msgid ""
|
||||
"The account to use when the bank invoices its own costs. Leave it blank to "
|
||||
"disable automatic invoice generation on bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_normal_field_contry
|
||||
msgid "country_id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Rejected"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_journals
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_journals
|
||||
msgid "Default Import Settings for Bank Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.wizard,name:account_banking.wizard_account_banking_import_file
|
||||
#: model:ir.ui.menu,name:account_banking.menu_account_banking_import_wizard
|
||||
msgid "Import Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account_banking.banking_import,init,file:0
|
||||
msgid ""
|
||||
"The Transactions File to import. Please note that while it is perfectly safe "
|
||||
"to reload the same file multiple times or to load in timeframe overlapping "
|
||||
"statements files, there are formats that may introduce different sequencing, "
|
||||
"which may create double entries.\n"
|
||||
"\n"
|
||||
"To stay on the safe side, always load bank statements files using the same "
|
||||
"format."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/sepa/bbantoiban.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Imported Bank Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,description:account_banking.module_meta_information
|
||||
msgid ""
|
||||
"\n"
|
||||
" Module to do banking.\n"
|
||||
"\n"
|
||||
" Note: This module is depending on BeautifulSoup.\n"
|
||||
"\n"
|
||||
" This modules tries to combine all current banking import and export\n"
|
||||
" schemes. Rationale for this is that it is quite common to have foreign\n"
|
||||
" bank account numbers next to national bank account numbers. The current\n"
|
||||
" approach, which hides the national banking interface schemes in the\n"
|
||||
" l10n_xxx modules, makes it very difficult to use these simultanious.\n"
|
||||
" A more banking oriented approach seems more logical and cleaner.\n"
|
||||
"\n"
|
||||
" Changes to default OpenERP:\n"
|
||||
"\n"
|
||||
" * Puts focus on the real life messaging with banks:\n"
|
||||
" + Bank statement lines upgraded to independent bank transactions.\n"
|
||||
" + Banking statements have no special accountancy meaning, they're "
|
||||
"just\n"
|
||||
" message envelopes for a number of bank transactions.\n"
|
||||
" + Bank statements can be either encoded by hand to reflect the "
|
||||
"document\n"
|
||||
" version of Bank Statements, or created as an optional side effect "
|
||||
"of\n"
|
||||
" importing Bank Transactions.\n"
|
||||
"\n"
|
||||
" * Preparations for SEPA:\n"
|
||||
" + IBAN accounts are the standard in the SEPA countries\n"
|
||||
" + local accounts are derived from SEPA (excluding Turkey) but are\n"
|
||||
" considered to be identical to the corresponding SEPA account.\n"
|
||||
" + Banks are identified with either Country + Bank code + Branch code "
|
||||
"or BIC\n"
|
||||
" + Each bank can have its own pace in introducing SEPA into their\n"
|
||||
" communication with their customers.\n"
|
||||
" + National online databases can be used to convert BBAN's to IBAN's.\n"
|
||||
" + The SWIFT database is consulted for bank information.\n"
|
||||
"\n"
|
||||
" * Adds dropin extensible import facility for bank communication in:\n"
|
||||
" - Drop-in input parser development.\n"
|
||||
" - MultiBank (NL) format transaction files available as\n"
|
||||
" account_banking_nl_multibank,\n"
|
||||
"\n"
|
||||
" * Extends payments for digital banking:\n"
|
||||
" + Adapted workflow in payments to reflect banking operations\n"
|
||||
" + Relies on account_payment mechanics to extend with export "
|
||||
"generators.\n"
|
||||
" - ClieOp3 (NL) payment and direct debit orders files available as\n"
|
||||
" account_banking_nl_clieop\n"
|
||||
"\n"
|
||||
" * Additional features for the import/export mechanism:\n"
|
||||
" + Automatic matching and creation of bank accounts, banks and "
|
||||
"partners,\n"
|
||||
" during import of statements.\n"
|
||||
" + Automatic matching with invoices and payments.\n"
|
||||
" + Sound import mechanism, allowing multiple imports of the same\n"
|
||||
" transactions repeated over multiple files.\n"
|
||||
" + Journal configuration per bank account.\n"
|
||||
" + Business logic and format parsing strictly separated to ease the\n"
|
||||
" development of new parsers.\n"
|
||||
" + No special configuration needed for the parsers, new parsers are\n"
|
||||
" recognized and made available at server (re)start.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Import Bank Transactions File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Account %(account_no)s is not owned by %(partner)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,import:0
|
||||
msgid "_Ok"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "More then one possible match found for partner with name %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,state:0
|
||||
#: field:payment.line,export_state:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "ERROR!"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s '\n"
|
||||
" '(ref: %(ref)s) to invoice: '\n"
|
||||
" 'invoice %(invoice)s was already paid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number has the wrong format for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,currency:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,msg:0
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,company_id:0
|
||||
#: field:account.banking.imported.file,company_id:0
|
||||
#: wizard_field:account_banking.banking_import,init,company:0
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,view_error,log:0
|
||||
#: wizard_field:account_banking.banking_import,view_statements,log:0
|
||||
msgid "Log"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "Invalid value for transfer_type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Insufficient data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Configration Error !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.act_account_payment_account_bank_statement
|
||||
msgid "Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "No suitable period found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_imported_files
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_imported_files
|
||||
msgid "Imported Bank Statements Files"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement,banking_id:0
|
||||
msgid "Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,log:0
|
||||
msgid "Import Log"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping periods for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "The imported statements appear to be invalid! Check your file."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements loaded"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_actions
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_settings
|
||||
msgid "Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Unable to reconcile entry \"%s\": %.2f"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No suitable fiscal year found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Import Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,period_id:0
|
||||
msgid "Period"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:payment.order:0
|
||||
msgid "Select Invoices to Pay"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,user_id:0
|
||||
msgid "Responsible User"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The statement balance is incorrect !\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Unfinished"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for unknown account %(bank_account)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,shortdesc:account_banking.module_meta_information
|
||||
msgid "Account Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,open_import:0
|
||||
msgid "_View Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The IBAN number doesn't seem to be correct"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,format:0
|
||||
#: wizard_field:account_banking.banking_import,init,parser:0
|
||||
msgid "File Format"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping fiscal years found for date %(date)s and company %"
|
||||
"(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,journal_id:0
|
||||
msgid "Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,costs_account_id:0
|
||||
#, fuzzy
|
||||
msgid "Bank Costs Account"
|
||||
msgstr "Conturi bancare"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Finished"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Bank Account Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,partner_bank_id:0
|
||||
#: field:account.banking.account.settings,partner_bank_id:0
|
||||
msgid "Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions loaded"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number appears to be invalid for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_acc_number_field
|
||||
msgid "acc_number"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid "Number of transactions matched"
|
||||
msgstr "Număr total de tranzacții"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,bank_partner_id:0
|
||||
msgid ""
|
||||
"The partner to use for bank costs. Banks are not partners by default. You "
|
||||
"will most likely have to create one."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account entries lines are not in valid state."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_imported_file
|
||||
msgid "Imported Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, fuzzy, python-format
|
||||
msgid ""
|
||||
"Statement %(statement_id)s for account %(bank_account)s' \n"
|
||||
" ' uses different currency than the defined bank "
|
||||
"journal."
|
||||
msgstr ""
|
||||
"Extrasuri de cont găsite pentru contul %(bank_account)s, '\n"
|
||||
" ' dar s-a setat nici un jurnal implicit."
|
||||
1678
__unported__/account_banking/i18n/tr.po
Normal file
1678
__unported__/account_banking/i18n/tr.po
Normal file
File diff suppressed because it is too large
Load Diff
766
__unported__/account_banking/i18n/tr_TR.po
Normal file
766
__unported__/account_banking/i18n/tr_TR.po
Normal file
@@ -0,0 +1,766 @@
|
||||
# Turkish translation for account-banking
|
||||
# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
|
||||
# This file is distributed under the same license as the account-banking package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: account-banking\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2010-07-16 14:58+0000\n"
|
||||
"PO-Revision-Date: 2010-10-10 11:17+0000\n"
|
||||
"Last-Translator: Engin BAHADIR <Unknown>\n"
|
||||
"Language-Team: Turkish <tr@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: 2010-10-11 12:32+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of bank costs invoices created"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Results:"
|
||||
msgstr "Sonuçlar:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of errors found"
|
||||
msgstr "Bulunan hataların sayısı"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
msgid "Select the processing details:"
|
||||
msgstr "İşlem ayrıntılarını seçin:"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s (ref: %(ref)s) to invoice: '\n"
|
||||
" '%(no_candidates)s candidates found; can't choose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid format"
|
||||
msgstr "Geçersiz biçim"
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,date_done:0
|
||||
msgid "Date Confirmed"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_statements,open_statements:0
|
||||
msgid "_View Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,end:0
|
||||
#: wizard_button:account_banking.banking_import,view_statements,end:0
|
||||
msgid "_Close"
|
||||
msgstr "_Kapat"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,bank_partner_id:0
|
||||
msgid "Bank Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_account_settings
|
||||
msgid "Default Journal for Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,init,file:0
|
||||
msgid "Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"More than one bank account was found with the same number %(account_no)s"
|
||||
msgstr ""
|
||||
"%(account_no)s ile aynı numaraya sahip birden fazla banka hesabı bulundu"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of transactions"
|
||||
msgstr "Toplam işlem sayısı"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Account move line \"%s\" is not valid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment is received. This can be "
|
||||
"needed when a customer pays in advance or when no matching invoice can be "
|
||||
"found. Mind that you can correct movements before confirming them."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Bank account %(account_no)s was not found in the database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Generation of Bank Costs Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions skipped due to errors"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The expected balance (%.2f) is different '\n"
|
||||
" 'than the computed one. (%.2f)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "Costs Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements skipped due to errors"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid IBAN account number!"
|
||||
msgstr "Geçersiz IBAN hesap numarası"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Import Settings for Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid ""
|
||||
"The account to use when an unexpected payment was signaled. This can happen "
|
||||
"when a direct debit payment is cancelled by a customer, or when no matching "
|
||||
"payment can be found. Mind that you can correct movements before confirming "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Unable to import parser %(parser)s. Parser class not found."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,file:0
|
||||
msgid "Raw Data"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Cancelled"
|
||||
msgstr "İptal Edildi"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Insufficient data to select online '\n"
|
||||
" 'conversion database"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,statement_ids:0
|
||||
msgid "Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_debit_account_id:0
|
||||
msgid "Default debit account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Unknown Bank"
|
||||
msgstr "Bilinmeyen Banka"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,end:0
|
||||
msgid "_Cancel"
|
||||
msgstr "_iptal"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Draft"
|
||||
msgstr "Taslak"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,date:0
|
||||
msgid "Import Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Confirmed"
|
||||
msgstr "Onaylandı"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_res_partner_banks
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_accounts
|
||||
msgid "Bank Accounts"
|
||||
msgstr "Banka Hesapları"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Default Accounts for Unknown Movements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.bank.statement:0
|
||||
msgid "Confirm"
|
||||
msgstr "Onayla"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Statements found for account %(bank_account)s, '\n"
|
||||
" 'but no default journal was defined."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,default_credit_account_id:0
|
||||
msgid "Default credit account"
|
||||
msgstr "Varsayılan kredi hesabı"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,international:0
|
||||
msgid "International Transaction"
|
||||
msgstr "Uluslararası İşlem"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Please verify that an account is defined in the journal."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,trans:0
|
||||
msgid "Bank Transaction ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,invoice_journal_id:0
|
||||
msgid "This is the journal used to create invoices for bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statement %(id)s known - skipped"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Sent"
|
||||
msgstr "Gönderildi"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,costs_account_id:0
|
||||
msgid ""
|
||||
"The account to use when the bank invoices its own costs. Leave it blank to "
|
||||
"disable automatic invoice generation on bank costs."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Hata !"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Invalid data"
|
||||
msgstr "Geçersiz veri"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_normal_field_contry
|
||||
msgid "country_id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Rejected"
|
||||
msgstr "Reddedildi"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_journals
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_bank_journals
|
||||
msgid "Default Import Settings for Bank Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.wizard,name:account_banking.wizard_account_banking_import_file
|
||||
#: model:ir.ui.menu,name:account_banking.menu_account_banking_import_wizard
|
||||
msgid "Import Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account_banking.banking_import,init,file:0
|
||||
msgid ""
|
||||
"The Transactions File to import. Please note that while it is perfectly safe "
|
||||
"to reload the same file multiple times or to load in timeframe overlapping "
|
||||
"statements files, there are formats that may introduce different sequencing, "
|
||||
"which may create double entries.\n"
|
||||
"\n"
|
||||
"To stay on the safe side, always load bank statements files using the same "
|
||||
"format."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/sepa/bbantoiban.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr "Görüntüleme Yapısı için Geçersiz XML!"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Imported Bank Statements"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,description:account_banking.module_meta_information
|
||||
msgid ""
|
||||
"\n"
|
||||
" Module to do banking.\n"
|
||||
"\n"
|
||||
" Note: This module is depending on BeautifulSoup.\n"
|
||||
"\n"
|
||||
" This modules tries to combine all current banking import and export\n"
|
||||
" schemes. Rationale for this is that it is quite common to have foreign\n"
|
||||
" bank account numbers next to national bank account numbers. The current\n"
|
||||
" approach, which hides the national banking interface schemes in the\n"
|
||||
" l10n_xxx modules, makes it very difficult to use these simultanious.\n"
|
||||
" A more banking oriented approach seems more logical and cleaner.\n"
|
||||
"\n"
|
||||
" Changes to default OpenERP:\n"
|
||||
"\n"
|
||||
" * Puts focus on the real life messaging with banks:\n"
|
||||
" + Bank statement lines upgraded to independent bank transactions.\n"
|
||||
" + Banking statements have no special accountancy meaning, they're "
|
||||
"just\n"
|
||||
" message envelopes for a number of bank transactions.\n"
|
||||
" + Bank statements can be either encoded by hand to reflect the "
|
||||
"document\n"
|
||||
" version of Bank Statements, or created as an optional side effect "
|
||||
"of\n"
|
||||
" importing Bank Transactions.\n"
|
||||
"\n"
|
||||
" * Preparations for SEPA:\n"
|
||||
" + IBAN accounts are the standard in the SEPA countries\n"
|
||||
" + local accounts are derived from SEPA (excluding Turkey) but are\n"
|
||||
" considered to be identical to the corresponding SEPA account.\n"
|
||||
" + Banks are identified with either Country + Bank code + Branch code "
|
||||
"or BIC\n"
|
||||
" + Each bank can have its own pace in introducing SEPA into their\n"
|
||||
" communication with their customers.\n"
|
||||
" + National online databases can be used to convert BBAN's to IBAN's.\n"
|
||||
" + The SWIFT database is consulted for bank information.\n"
|
||||
"\n"
|
||||
" * Adds dropin extensible import facility for bank communication in:\n"
|
||||
" - Drop-in input parser development.\n"
|
||||
" - MultiBank (NL) format transaction files available as\n"
|
||||
" account_banking_nl_multibank,\n"
|
||||
"\n"
|
||||
" * Extends payments for digital banking:\n"
|
||||
" + Adapted workflow in payments to reflect banking operations\n"
|
||||
" + Relies on account_payment mechanics to extend with export "
|
||||
"generators.\n"
|
||||
" - ClieOp3 (NL) payment and direct debit orders files available as\n"
|
||||
" account_banking_nl_clieop\n"
|
||||
"\n"
|
||||
" * Additional features for the import/export mechanism:\n"
|
||||
" + Automatic matching and creation of bank accounts, banks and "
|
||||
"partners,\n"
|
||||
" during import of statements.\n"
|
||||
" + Automatic matching with invoices and payments.\n"
|
||||
" + Sound import mechanism, allowing multiple imports of the same\n"
|
||||
" transactions repeated over multiple files.\n"
|
||||
" + Journal configuration per bank account.\n"
|
||||
" + Business logic and format parsing strictly separated to ease the\n"
|
||||
" development of new parsers.\n"
|
||||
" + No special configuration needed for the parsers, new parsers are\n"
|
||||
" recognized and made available at server (re)start.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_view:account_banking.banking_import,init:0
|
||||
#: wizard_view:account_banking.banking_import,view_error:0
|
||||
#: wizard_view:account_banking.banking_import,view_statements:0
|
||||
msgid "Import Bank Transactions File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "Account %(account_no)s is not owned by %(partner)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,init,import:0
|
||||
msgid "_Ok"
|
||||
msgstr "_Tamam"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid "More then one possible match found for partner with name %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,state:0
|
||||
#: field:payment.line,export_state:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "ERROR!"
|
||||
msgstr "HATA!"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unable to link transaction id %(trans)s '\n"
|
||||
" '(ref: %(ref)s) to invoice: '\n"
|
||||
" 'invoice %(invoice)s was already paid"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number has the wrong format for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,currency:0
|
||||
msgid "Currency"
|
||||
msgstr "Para Birimi"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:payment.line,msg:0
|
||||
msgid "Message"
|
||||
msgstr "İleti"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,company_id:0
|
||||
#: field:account.banking.imported.file,company_id:0
|
||||
#: wizard_field:account_banking.banking_import,init,company:0
|
||||
msgid "Company"
|
||||
msgstr "Firma"
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_field:account_banking.banking_import,view_error,log:0
|
||||
#: wizard_field:account_banking.banking_import,view_statements,log:0
|
||||
msgid "Log"
|
||||
msgstr "Kayıt"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "Invalid value for transfer_type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Insufficient data"
|
||||
msgstr "Yetersiz veri"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Configration Error !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.actions.act_window,name:account_banking.act_account_payment_account_bank_statement
|
||||
msgid "Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/parsers/models.py:0
|
||||
#, python-format
|
||||
msgid "This is a stub. Please implement your own."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No suitable period found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: model:ir.actions.act_window,name:account_banking.action_account_banking_imported_files
|
||||
#: model:ir.ui.menu,name:account_banking.menu_action_account_banking_imported_files
|
||||
msgid "Imported Bank Statements Files"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement,banking_id:0
|
||||
msgid "Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
#: field:account.banking.imported.file,log:0
|
||||
msgid "Import Log"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping periods for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "The imported statements appear to be invalid! Check your file."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of statements loaded"
|
||||
msgstr "Yüklü beyanların sayısı"
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_actions
|
||||
#: model:ir.ui.menu,name:account_banking.menu_finance_banking_settings
|
||||
msgid "Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Error"
|
||||
msgstr "Hata"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Total number of statements"
|
||||
msgstr "Beyanların toplam sayısı"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "Unable to reconcile entry \"%s\": %.2f"
|
||||
msgstr "\"%s\": %.2f girdisi bağdaştırılamadı"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No suitable fiscal year found for date %(date)s and company %(company_name)s"
|
||||
msgstr ""
|
||||
"%(company_name)s şirketi ve %(date)s tarihi için uygun mali yıl bulunamadı"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.imported.file:0
|
||||
msgid "Import Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,period_id:0
|
||||
msgid "Period"
|
||||
msgstr "Dönem"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:payment.line,export_state:0
|
||||
msgid "Done"
|
||||
msgstr "Tamamlandı"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:payment.order:0
|
||||
msgid "Select Invoices to Pay"
|
||||
msgstr "Ödeme için Faturaları Seç"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,user_id:0
|
||||
msgid "Responsible User"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The statement balance is incorrect !\n"
|
||||
msgstr "Beyan dengesi doğru değil\n"
|
||||
|
||||
#. module: account_banking
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr "Nesne adı x_ ile başlamalı ve özel karakter içermemelidir!"
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Unfinished"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Statements found for unknown account %(bank_account)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.module.module,shortdesc:account_banking.module_meta_information
|
||||
msgid "Account Banking"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: wizard_button:account_banking.banking_import,view_error,open_import:0
|
||||
msgid "_View Imported File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The IBAN number doesn't seem to be correct"
|
||||
msgstr "IBAN numarası yanlış gibi gözüküyor"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.imported.file,format:0
|
||||
#: wizard_field:account_banking.banking_import,init,parser:0
|
||||
msgid "File Format"
|
||||
msgstr "Dosya Biçimi"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/banktools.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Multiple overlapping fiscal years found for date %(date)s and company "
|
||||
"%(company_name)s"
|
||||
msgstr ""
|
||||
"%(company_name)s şireketi ve %(date)s tarihine ait eşleşen birçok mali yıl "
|
||||
"bulundu"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,journal_id:0
|
||||
msgid "Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.banking.account.settings,costs_account_id:0
|
||||
msgid "Bank Costs Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: selection:account.banking.imported.file,state:0
|
||||
msgid "Finished"
|
||||
msgstr "Tamamlandı"
|
||||
|
||||
#. module: account_banking
|
||||
#: view:account.banking.account.settings:0
|
||||
msgid "Bank Account Details"
|
||||
msgstr "Banka Hesabı Ayrıntıları"
|
||||
|
||||
#. module: account_banking
|
||||
#: field:account.bank.statement.line,partner_bank_id:0
|
||||
#: field:account.banking.account.settings,partner_bank_id:0
|
||||
msgid "Bank Account"
|
||||
msgstr "Banka Hesabı"
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions loaded"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account number appears to be invalid for %(country)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:res.partner.bank.type.field,name:account_banking.bank_acc_number_field
|
||||
msgid "acc_number"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid "Number of transactions matched"
|
||||
msgstr "Eşleşen işlem sayısı"
|
||||
|
||||
#. module: account_banking
|
||||
#: help:account.banking.account.settings,bank_partner_id:0
|
||||
msgid ""
|
||||
"The partner to use for bank costs. Banks are not partners by default. You "
|
||||
"will most likely have to create one."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/account_banking.py:0
|
||||
#, python-format
|
||||
msgid "The account entries lines are not in valid state."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: model:ir.model,name:account_banking.model_account_banking_imported_file
|
||||
msgid "Imported Bank Statements File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking
|
||||
#: code:addons/account_banking/wizard/bank_import.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Statement %(statement_id)s for account %(bank_account)s' \n"
|
||||
" ' uses different currency than the defined bank "
|
||||
"journal."
|
||||
msgstr ""
|
||||
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 Therp BV (<http://therp.nl>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
""" r81: introduction of bank statement line state
|
||||
"""
|
||||
__name__ = ("account.bank.statement.line:: set new field 'state' to "
|
||||
"confirmed for all statement lines belonging to confirmed "
|
||||
"statements")
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
cr.execute("UPDATE account_bank_statement_line as sl "
|
||||
" SET state = 'confirmed'"
|
||||
" FROM account_bank_statement as s "
|
||||
" WHERE sl.statement_id = s.id "
|
||||
" AND s.state = 'confirm' "
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
if not version:
|
||||
return
|
||||
|
||||
# workflow state moved to another, new module
|
||||
cr.execute(
|
||||
"""
|
||||
UPDATE ir_model_data
|
||||
SET module = 'account_banking_payment'
|
||||
WHERE name = 'trans_done_sent'
|
||||
AND module = 'account_direct_debit'
|
||||
""")
|
||||
@@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2014 Therp BV (<http://therp.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
if not version:
|
||||
return
|
||||
|
||||
# Rename value date column
|
||||
cr.execute(
|
||||
"""
|
||||
ALTER TABLE banking_import_transaction
|
||||
RENAME COLUMN effective_date TO value_date
|
||||
""")
|
||||
@@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
def table_exists(cr, table):
|
||||
""" Check whether a certain table or view exists """
|
||||
cr.execute(
|
||||
'SELECT count(relname) FROM pg_class WHERE relname = %s',
|
||||
(table,))
|
||||
return cr.fetchone()[0] == 1
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
"""
|
||||
Migration script for semantic changes in account_banking_payment_export.
|
||||
Putting the same script in this module for users migrating from 6.1,
|
||||
before the export module was refactored out.
|
||||
"""
|
||||
if not version or not table_exists(cr, 'payment_line'):
|
||||
return
|
||||
cr.execute(
|
||||
"UPDATE payment_line SET communication = communication2, "
|
||||
"communication2 = null "
|
||||
"FROM payment_order "
|
||||
"WHERE payment_line.order_id = payment_order.id "
|
||||
"AND payment_order.state in ('draft', 'open') "
|
||||
"AND payment_line.state = 'normal' "
|
||||
"AND communication2 is not null")
|
||||
24
__unported__/account_banking/parsers/__init__.py
Normal file
24
__unported__/account_banking/parsers/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 models
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
73
__unported__/account_banking/parsers/convert.py
Normal file
73
__unported__/account_banking/parsers/convert.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 unicodedata
|
||||
|
||||
__all__ = ['str2date', 'date2str', 'date2date', 'to_swift']
|
||||
|
||||
try:
|
||||
from datetime import datetime
|
||||
datetime.strptime
|
||||
except AttributeError:
|
||||
from mx import DateTime as datetime
|
||||
|
||||
|
||||
def str2date(datestr, format='%d/%m/%y'):
|
||||
'''Convert a string to a datatime object'''
|
||||
return datetime.strptime(datestr, format)
|
||||
|
||||
|
||||
def date2str(date, format='%Y-%m-%d'):
|
||||
'''Convert a datetime object to a string'''
|
||||
return date.strftime(format)
|
||||
|
||||
|
||||
def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'):
|
||||
'''
|
||||
Convert a date in a string to another string, in a different
|
||||
format
|
||||
'''
|
||||
return date2str(str2date(datestr, fromfmt), tofmt)
|
||||
|
||||
_SWIFT = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
"/-?:().,'+ ")
|
||||
|
||||
|
||||
def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']):
|
||||
'''
|
||||
Reduce a string to SWIFT format
|
||||
'''
|
||||
if not isinstance(astr, unicode):
|
||||
for scheme in schemes:
|
||||
try:
|
||||
astr = unicode(astr, scheme)
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
if not isinstance(astr, unicode):
|
||||
return astr
|
||||
|
||||
s = [x in _SWIFT and x or ' '
|
||||
for x in unicodedata.normalize('NFKD', astr).encode('ascii', 'ignore')
|
||||
]
|
||||
return ''.join(s)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
422
__unported__/account_banking/parsers/models.py
Normal file
422
__unported__/account_banking/parsers/models.py
Normal file
@@ -0,0 +1,422 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 re
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class mem_bank_statement(object):
|
||||
'''
|
||||
A mem_bank_statement is a real life projection of a bank statement paper
|
||||
containing a report of one or more transactions done. As these reports can
|
||||
contain payments that originate in several accounting periods, period is an
|
||||
attribute of mem_bank_transaction, not of mem_bank_statement.
|
||||
Also note that the statement_id is copied from the bank statement, and not
|
||||
generated from any sequence. This enables us to skip old data in new
|
||||
statement files.
|
||||
'''
|
||||
# Lock attributes to enable parsers to trigger non-conformity faults
|
||||
__slots__ = [
|
||||
'start_balance',
|
||||
'end_balance',
|
||||
'date',
|
||||
'local_account',
|
||||
'local_currency',
|
||||
'id',
|
||||
'transactions'
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(mem_bank_statement, self).__init__(*args, **kwargs)
|
||||
self.id = ''
|
||||
self.local_account = ''
|
||||
self.local_currency = ''
|
||||
self.start_balance = 0.0
|
||||
self.end_balance = 0.0
|
||||
self.date = ''
|
||||
self.transactions = []
|
||||
|
||||
def is_valid(self):
|
||||
'''
|
||||
Final check: ok if calculated end_balance and parsed end_balance are
|
||||
identical and perform a heuristic check on the transactions.
|
||||
'''
|
||||
if any([x for x in self.transactions if not x.is_valid()]):
|
||||
return False
|
||||
check = float(self.start_balance)
|
||||
for transaction in self.transactions:
|
||||
check += float(transaction.transferred_amount)
|
||||
return abs(check - float(self.end_balance)) < 0.0001
|
||||
|
||||
|
||||
class mem_bank_transaction(object):
|
||||
'''
|
||||
A mem_bank_transaction is a real life copy of a bank transfer. Mapping to
|
||||
OpenERP moves and linking to invoices and the like is done afterwards.
|
||||
'''
|
||||
# Lock attributes to enable parsers to trigger non-conformity faults
|
||||
__slots__ = [
|
||||
|
||||
'id',
|
||||
# Message id
|
||||
|
||||
'statement_id',
|
||||
# The bank statement this message was reported on
|
||||
|
||||
'transfer_type',
|
||||
# Action type that initiated this message
|
||||
|
||||
'reference',
|
||||
# A reference to this message for communication
|
||||
|
||||
'local_account',
|
||||
# The account this message was meant for
|
||||
|
||||
'local_currency',
|
||||
# The currency the bank used to process the transferred amount
|
||||
|
||||
'execution_date',
|
||||
# The posted date of the action
|
||||
|
||||
'value_date',
|
||||
# The value date of the action
|
||||
|
||||
'remote_account',
|
||||
# The account of the other party
|
||||
|
||||
'remote_currency',
|
||||
# The currency used by the other party
|
||||
|
||||
'exchange_rate',
|
||||
# The exchange rate used for conversion of local_currency and
|
||||
# remote_currency
|
||||
|
||||
'transferred_amount',
|
||||
# The actual amount transferred -
|
||||
# negative means sent, positive means received
|
||||
# Most banks use the local_currency to express this amount, but there
|
||||
# may be exceptions I'm unaware of.
|
||||
|
||||
'message',
|
||||
# A direct message from the initiating party to the receiving party
|
||||
# A lot of banks abuse this to stuff all kinds of structured
|
||||
# information in this message. It is the task of the parser to split
|
||||
# this up into the appropriate attributes.
|
||||
|
||||
'remote_owner',
|
||||
# The name of the other party
|
||||
|
||||
'remote_owner_address',
|
||||
# The other parties address lines - the only attribute that is a list
|
||||
|
||||
'remote_owner_city',
|
||||
# The other parties city name belonging to the previous
|
||||
|
||||
'remote_owner_postalcode',
|
||||
# The other parties postal code belonging to the address
|
||||
|
||||
'remote_owner_country_code',
|
||||
# The other parties two letter ISO country code belonging to the
|
||||
# previous
|
||||
|
||||
'remote_owner_custno',
|
||||
# The other parties customer number
|
||||
|
||||
# For identification of private other parties, the following attributes
|
||||
# are available and self explaining. Most banks allow only one per
|
||||
# message.
|
||||
'remote_owner_ssn',
|
||||
'remote_owner_tax_id',
|
||||
'remote_owner_employer_id',
|
||||
'remote_owner_passport_no',
|
||||
'remote_owner_idcard_no',
|
||||
'remote_owner_driverslicense_no',
|
||||
|
||||
# Other private party information fields. Not all banks use it, but
|
||||
# at least SEPA messaging allowes it.
|
||||
'remote_owner_birthdate',
|
||||
'remote_owner_cityofbirth',
|
||||
'remote_owner_countryofbirth',
|
||||
'remote_owner_provinceofbirth',
|
||||
|
||||
# For the identification of remote banks, the following attributes are
|
||||
# available and self explaining. Most banks allow only one per
|
||||
# message.
|
||||
'remote_bank_bic',
|
||||
'remote_bank_bei',
|
||||
'remote_bank_ibei',
|
||||
'remote_bank_eangln',
|
||||
'remote_bank_chips_uid',
|
||||
'remote_bank_duns',
|
||||
'remote_bank_tax_id',
|
||||
|
||||
# For other identification purposes: both of the next attributes must
|
||||
# be filled.
|
||||
'remote_bank_proprietary_id',
|
||||
'remote_bank_proprietary_id_issuer',
|
||||
|
||||
# The following attributes are for allowing banks to communicate about
|
||||
# specific transactions. The transferred_amount must include these
|
||||
# costs.
|
||||
# Please make sure that the costs are signed for the right direction.
|
||||
'provision_costs',
|
||||
'provision_costs_currency',
|
||||
'provision_costs_description',
|
||||
|
||||
# An error message for interaction with the user
|
||||
# Only used when mem_transaction.valid returns False.
|
||||
'error_message',
|
||||
|
||||
# Storno attribute. When True, make the cancelled debit eligible for
|
||||
# a next direct debit run
|
||||
'storno_retry',
|
||||
|
||||
]
|
||||
|
||||
# transfer_type's to be used by the business logic.
|
||||
# Depending on the type your parser gives a transaction, different
|
||||
# behavior can be triggered in the business logic.
|
||||
#
|
||||
# BANK_COSTS Automated credited costs by the bank.
|
||||
# Used to generate an automated invoice from the bank
|
||||
# Will be excluded from matching.
|
||||
# BANK_TERMINAL A cash withdrawal from a bank terminal.
|
||||
# Will be excluded from matching.
|
||||
# CHECK A delayed payment. Can be used to trigger extra
|
||||
# moves from temporary accounts. (Money away).
|
||||
# TODO: No special treatment yet.
|
||||
# Will be selected for matching.
|
||||
# DIRECT_DEBIT Speaks for itself. When outgoing (credit) and
|
||||
# matched, can signal the matched invoice triaged.
|
||||
# Will be selected for matching.
|
||||
# ORDER Order to the bank. Can work both ways.
|
||||
# Will be selected for matching.
|
||||
# PAYMENT_BATCH A payment batch. Can work in both directions.
|
||||
# Incoming payment batch transactions can't be
|
||||
# matched with payments, outgoing can.
|
||||
# Will be selected for matching.
|
||||
# PAYMENT_TERMINAL A payment with debit/credit card in a (web)shop
|
||||
# Invoice numbers and other hard criteria are most
|
||||
# likely missing.
|
||||
# Will be selected for matching
|
||||
# PERIODIC_ORDER An automated payment by the bank on your behalf.
|
||||
# Always outgoing.
|
||||
# Will be selected for matching.
|
||||
# STORNO A failed or reversed attempt at direct debit.
|
||||
# Either due to an action on the payer's side
|
||||
# or a failure observed by the bank (lack of
|
||||
# credit for instance)
|
||||
#
|
||||
# Perhaps more will follow.
|
||||
#
|
||||
# When writing parsers, map other types with similar meaning to these to
|
||||
# prevent cluttering the API. For example: the Dutch ING Bank has a
|
||||
# transfer type Post Office, meaning a cash withdrawal from one of their
|
||||
# agencies. This can be mapped to BANK_TERMINAL without losing any
|
||||
# significance for OpenERP.
|
||||
|
||||
BANK_COSTS = 'BC'
|
||||
BANK_TERMINAL = 'BT'
|
||||
CHECK = 'CK'
|
||||
DIRECT_DEBIT = 'DD'
|
||||
ORDER = 'DO'
|
||||
PAYMENT_BATCH = 'PB'
|
||||
PAYMENT_TERMINAL = 'PT'
|
||||
PERIODIC_ORDER = 'PO'
|
||||
STORNO = 'ST'
|
||||
|
||||
types = [
|
||||
BANK_COSTS, BANK_TERMINAL, CHECK, DIRECT_DEBIT, ORDER,
|
||||
PAYMENT_BATCH, PAYMENT_TERMINAL, PERIODIC_ORDER, STORNO,
|
||||
]
|
||||
type_map = {
|
||||
# This can be a translation map of type versus bank type. Each key is
|
||||
# the real transfer_type, each value is the mem_bank_transaction.type
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
Initialize values
|
||||
'''
|
||||
super(mem_bank_transaction, self).__init__(*args, **kwargs)
|
||||
for attr in self.__slots__:
|
||||
setattr(self, attr, '')
|
||||
self.remote_owner_address = []
|
||||
|
||||
def copy(self):
|
||||
'''
|
||||
Return a copy of self
|
||||
'''
|
||||
retval = mem_bank_transaction()
|
||||
for attr in self.__slots__:
|
||||
setattr(retval, attr, getattr(self, attr))
|
||||
return retval
|
||||
|
||||
def _get_type(self):
|
||||
if self.transfer_type in self.type_map:
|
||||
return self.type_map[self.transfer_type]
|
||||
return self.transfer_type
|
||||
|
||||
def _set_type(self, value):
|
||||
if value in self.types:
|
||||
self.transfer_type = value
|
||||
else:
|
||||
raise ValueError(_('Invalid value for transfer_type'))
|
||||
|
||||
type = property(_get_type, _set_type)
|
||||
|
||||
def is_valid(self):
|
||||
'''
|
||||
Heuristic check: at least id, execution_date, remote_account and
|
||||
transferred_amount should be filled to create a valid transfer.
|
||||
'''
|
||||
return (self.execution_date and self.remote_account
|
||||
and self.transferred_amount and True) or False
|
||||
|
||||
|
||||
class parser_type(type):
|
||||
'''
|
||||
Meta annex factory class for house keeping and collecting parsers.
|
||||
'''
|
||||
parsers = []
|
||||
parser_by_name = {}
|
||||
parser_by_code = {}
|
||||
parser_by_classname = {}
|
||||
|
||||
def __new__(metacls, clsname, bases, clsdict):
|
||||
newcls = type.__new__(metacls, clsname, bases, clsdict)
|
||||
if 'name' in clsdict and newcls.name:
|
||||
metacls.parsers.append(newcls)
|
||||
metacls.parser_by_name[newcls.name] = newcls
|
||||
metacls.parser_by_code[newcls.code] = newcls
|
||||
metacls.parser_by_classname[clsname] = newcls
|
||||
return newcls
|
||||
|
||||
@classmethod
|
||||
def get_parser_types(cls, sort='name'):
|
||||
'''
|
||||
Return the parser class names, optional in sort order.
|
||||
'''
|
||||
if sort == 'name':
|
||||
keys = cls.parser_by_name.keys()
|
||||
parsers = cls.parser_by_name
|
||||
else:
|
||||
keys = cls.parser_by_code.itervalues()
|
||||
parsers = cls.parser_by_code
|
||||
keys.sort()
|
||||
return [(parsers[x].code, parsers[x].name) for x in keys]
|
||||
|
||||
|
||||
def create_parser(code):
|
||||
if code in parser_type.parser_by_code:
|
||||
return parser_type.parser_by_code[code]()
|
||||
return None
|
||||
|
||||
|
||||
class parser(object):
|
||||
'''
|
||||
A parser delivers the interface for any parser object. Inherit from
|
||||
it to implement your own.
|
||||
You should at least implement the following at the class level:
|
||||
name -> the name of the parser, shown to the user and
|
||||
translatable.
|
||||
code -> the identifier you care to give it. Not translatable
|
||||
country_code -> the two letter ISO code of the country this parser is
|
||||
built for: used to recreate country when new partners
|
||||
are auto created
|
||||
doc -> the description of the identifier. Shown to the user.
|
||||
Translatable.
|
||||
|
||||
parse -> the method for the actual parsing.
|
||||
'''
|
||||
__metaclass__ = parser_type
|
||||
name = None
|
||||
code = None
|
||||
country_code = None
|
||||
doc = __doc__
|
||||
|
||||
def get_unique_statement_id(self, cr, base):
|
||||
name = base
|
||||
suffix = 1
|
||||
while True:
|
||||
cr.execute(
|
||||
"select id from account_bank_statement where name = %s",
|
||||
(name,))
|
||||
if not cr.rowcount:
|
||||
break
|
||||
suffix += 1
|
||||
name = "%s-%d" % (base, suffix)
|
||||
return name
|
||||
|
||||
def get_unique_account_identifier(self, cr, account):
|
||||
"""
|
||||
Get an identifier for a local bank account, based on the last
|
||||
characters of the account number with minimum length 3.
|
||||
The identifier should be unique amongst the company accounts
|
||||
|
||||
Presumably, the bank account is one of the company accounts
|
||||
itself but importing bank statements for non-company accounts
|
||||
is not prevented anywhere else in the system so the 'account'
|
||||
param being a company account is not enforced here either.
|
||||
"""
|
||||
def normalize(account_no):
|
||||
return re.sub('\s', '', account_no)
|
||||
|
||||
account = normalize(account)
|
||||
cr.execute(
|
||||
"""SELECT acc_number FROM res_partner_bank
|
||||
WHERE company_id IS NOT NULL""")
|
||||
accounts = [normalize(row[0]) for row in cr.fetchall()]
|
||||
tail_length = 3
|
||||
while tail_length <= len(account):
|
||||
tail = account[-tail_length:]
|
||||
if len([acc for acc in accounts if acc.endswith(tail)]) < 2:
|
||||
return tail
|
||||
tail_length += 1
|
||||
return account
|
||||
|
||||
def parse(self, cr, data):
|
||||
'''
|
||||
Parse data.
|
||||
|
||||
data is a raw in memory file object. You have to split it in
|
||||
whatever chunks you see fit for parsing. It should return a list
|
||||
of mem_bank_statement objects. Every mem_bank_statement object
|
||||
should contain a list of mem_bank_transaction objects.
|
||||
|
||||
For identification purposes, don't invent numbering of the transaction
|
||||
numbers or bank statements ids on your own - stick with those provided
|
||||
by your bank. Doing so enables the users to re-load old transaction
|
||||
files without creating multiple identical bank statements.
|
||||
|
||||
If your bank does not provide transaction ids, take a high resolution
|
||||
and a repeatable algorithm for the numbering. For example the date can
|
||||
be used as a prefix. Adding a tracer (day resolution) can create
|
||||
uniqueness. Adding unique statement ids can add to the robustness of
|
||||
your transaction numbering.
|
||||
|
||||
Just mind that users can create random (file)containers with
|
||||
transactions in it. Try not to depend on order of appearance within
|
||||
these files. If in doubt: sort.
|
||||
'''
|
||||
raise NotImplementedError(
|
||||
_('This is a stub. Please implement your own.')
|
||||
)
|
||||
209
__unported__/account_banking/record.py
Normal file
209
__unported__/account_banking/record.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
__all__ = [
|
||||
'Field', 'Filler', 'DateField', 'NumberField', 'RightAlignedField',
|
||||
'RecordType', 'Record', 'asciify'
|
||||
]
|
||||
|
||||
__doc__ = '''Ease working with fixed length records in files'''
|
||||
|
||||
from datetime import datetime, date
|
||||
|
||||
# Correct python2.4 issues
|
||||
try:
|
||||
datetime.strptime
|
||||
|
||||
def strpdate(str, format):
|
||||
return datetime.strptime(str, format).date()
|
||||
except AttributeError:
|
||||
import time
|
||||
|
||||
def strpdate(str, format):
|
||||
tm = time.strptime(str, format)
|
||||
return date(tm.tm_year, tm.tm_mon, tm.tm_mday)
|
||||
|
||||
import unicodedata
|
||||
|
||||
|
||||
class Field(object):
|
||||
'''Base Field class - fixed length left aligned string field in a record'''
|
||||
def __init__(self, name, length=1, fillchar=' ', cast=str):
|
||||
self.name = name.replace(' ', '_')
|
||||
self.length = length
|
||||
self.fillchar = fillchar
|
||||
self.cast = cast
|
||||
|
||||
def format(self, value):
|
||||
value = self.cast(value)
|
||||
if len(value) > self.length:
|
||||
return value[:self.length]
|
||||
return value.ljust(self.length, self.fillchar)
|
||||
|
||||
def take(self, buffer):
|
||||
offset = hasattr(self, 'offset') and self.offset or 0
|
||||
return self.cast(buffer[offset:offset + self.length].rstrip(
|
||||
self.fillchar)
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s "%s"' % (self.__class__.__name__, self.name)
|
||||
|
||||
|
||||
class Filler(Field):
|
||||
'''Constant value field'''
|
||||
def __init__(self, name, length=1, value=' '):
|
||||
super(Filler, self).__init__(name, length, cast=str)
|
||||
self.value = str(value)
|
||||
|
||||
def take(self, buffer):
|
||||
return self.format(buffer)
|
||||
|
||||
def format(self, value):
|
||||
return super(Filler, self).format(
|
||||
self.value * (self.length / len(self.value) + 1)
|
||||
)
|
||||
|
||||
|
||||
class DateField(Field):
|
||||
'''Variable date field'''
|
||||
def __init__(self, name, format='%Y-%m-%d', auto=False, cast=str):
|
||||
length = len(date.today().strftime(format))
|
||||
super(DateField, self).__init__(name, length, cast=cast)
|
||||
self.dateformat = format
|
||||
self.auto = auto
|
||||
|
||||
def format(self, value):
|
||||
if isinstance(value, (str, unicode)) and \
|
||||
len(value.strip()) == self.length:
|
||||
value = strpdate(value, self.dateformat)
|
||||
elif not isinstance(value, (datetime, date)):
|
||||
value = date.today()
|
||||
return value.strftime(self.dateformat)
|
||||
|
||||
def take(self, buffer):
|
||||
value = super(DateField, self).take(buffer)
|
||||
if value:
|
||||
return strpdate(value, self.dateformat)
|
||||
return self.auto and date.today() or None
|
||||
|
||||
|
||||
class RightAlignedField(Field):
|
||||
'''Deviation of Field: right aligned'''
|
||||
def format(self, value):
|
||||
if len(value) > self.length:
|
||||
return value[-self.length:]
|
||||
return value.rjust(self.length, self.fillchar)
|
||||
|
||||
def take(self, buffer):
|
||||
offset = hasattr(self, 'offset') and self.offset or 0
|
||||
return self.cast(buffer[offset:offset + self.length].lstrip(
|
||||
self.fillchar)
|
||||
)
|
||||
|
||||
|
||||
class NumberField(RightAlignedField):
|
||||
'''Deviation of Field: left zero filled'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['fillchar'] = '0'
|
||||
super(NumberField, self).__init__(*args, **kwargs)
|
||||
|
||||
def format(self, value):
|
||||
return super(NumberField, self).format(self.cast(value or ''))
|
||||
|
||||
|
||||
class RecordType(object):
|
||||
fields = []
|
||||
|
||||
def __init__(self, fields=[]):
|
||||
if fields:
|
||||
self.fields = fields
|
||||
offset = 0
|
||||
for field in self.fields:
|
||||
field.offset = offset
|
||||
offset += field.length
|
||||
|
||||
def __len__(self):
|
||||
return reduce(lambda x, y: x + y.length, self.fields, 0)
|
||||
|
||||
def __contains__(self, key):
|
||||
return any(lambda x, y=key: x.name == y, self.fields)
|
||||
|
||||
def __getitem__(self, key):
|
||||
for field in self.fields:
|
||||
if field.name == key:
|
||||
return field
|
||||
raise KeyError('No such field: %s' % key)
|
||||
|
||||
def format(self, buffer):
|
||||
result = []
|
||||
for field in self.fields:
|
||||
result.append(field.format(field.take(buffer)))
|
||||
return ''.join(result)
|
||||
|
||||
def take(self, buffer):
|
||||
return dict(zip([x.name for x in self.fields],
|
||||
[x.take(buffer) for x in self.fields]
|
||||
))
|
||||
|
||||
|
||||
class Record(object):
|
||||
_recordtype = None
|
||||
|
||||
def __init__(self, recordtype=None, value=''):
|
||||
if hasattr(self, '_fields') and self._fields:
|
||||
self._recordtype = RecordType(self._fields)
|
||||
if not self._recordtype and not recordtype:
|
||||
raise ValueError('No recordtype specified')
|
||||
if not self._recordtype:
|
||||
self._recordtype = recordtype()
|
||||
self._length = len(self._recordtype)
|
||||
self._value = value.ljust(self._length)[:self._length]
|
||||
|
||||
def __len__(self):
|
||||
return self._length
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr.startswith('_'):
|
||||
super(Record, self).__setattr__(attr, value)
|
||||
else:
|
||||
field = self._recordtype[attr]
|
||||
self._value = (
|
||||
self._value[:field.offset] +
|
||||
field.format(value) +
|
||||
self._value[field.offset + field.length:]
|
||||
)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr.startswith('_'):
|
||||
return super(Record, self).__getattr__(attr)
|
||||
field = self._recordtype[attr]
|
||||
return field.take(self._value)
|
||||
|
||||
def __str__(self):
|
||||
return self._recordtype.format(self._value)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.cast(self))
|
||||
|
||||
|
||||
def asciify(str):
|
||||
return unicodedata.normalize('NFKD', str).encode('ascii', 'ignore')
|
||||
31
__unported__/account_banking/res_bank.py
Normal file
31
__unported__/account_banking/res_bank.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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 openerp.osv import orm
|
||||
|
||||
|
||||
class ResBank(orm.Model):
|
||||
_inherit = 'res.bank'
|
||||
|
||||
def online_bank_info(self, cr, uid, bic, context=None):
|
||||
"""
|
||||
API hook for legacy online lookup of BICs,
|
||||
to be removed in OpenERP 8.0.
|
||||
"""
|
||||
return False, False
|
||||
72
__unported__/account_banking/res_partner.py
Normal file
72
__unported__/account_banking/res_partner.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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.osv import orm
|
||||
|
||||
|
||||
class ResPartner(orm.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
def def_journal_account_bank(
|
||||
self, cr, uid, ids, get_property_account, context=None):
|
||||
"""
|
||||
Returns the property journal account for the given partners ids.
|
||||
|
||||
:param get_property_account: method of this object that takes
|
||||
a partner browse record and returns a field name of type many2one.
|
||||
"""
|
||||
if not ids:
|
||||
return {}
|
||||
res = dict([(res_id, False) for res_id in ids])
|
||||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
property_account = get_property_account(partner)
|
||||
if partner[property_account]:
|
||||
res[partner.id] = partner[property_account].id
|
||||
return res
|
||||
|
||||
def get_property_account_decrease(self, partner):
|
||||
if partner.customer and not partner.supplier:
|
||||
return 'property_account_receivable'
|
||||
return 'property_account_payable'
|
||||
|
||||
def get_property_account_increase(self, partner):
|
||||
if partner.supplier and not partner.customer:
|
||||
return 'property_account_payable'
|
||||
return 'property_account_receivable'
|
||||
|
||||
def def_journal_account_bank_decr(
|
||||
self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Return the default journal account to be used for this partner
|
||||
in the case of bank transactions that decrease the balance.
|
||||
"""
|
||||
return self.def_journal_account_bank(
|
||||
cr, uid, ids, self.get_property_account_decrease, context=context)
|
||||
|
||||
def def_journal_account_bank_incr(
|
||||
self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Return the default journal account to be used for this partner
|
||||
in the case of bank transactions that increase the balance.
|
||||
"""
|
||||
return self.def_journal_account_bank(
|
||||
cr, uid, ids, self.get_property_account_increase, context=context)
|
||||
101
__unported__/account_banking/res_partner_bank.py
Normal file
101
__unported__/account_banking/res_partner_bank.py
Normal file
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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 openerp.osv import orm
|
||||
from openerp.addons.account_banking import sepa
|
||||
|
||||
|
||||
class ResPartnerBank(orm.Model):
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def online_account_info(
|
||||
self, cr, uid, country_code, acc_number, context=None):
|
||||
"""
|
||||
API hook for legacy online lookup of account info,
|
||||
to be removed in OpenERP 8.0.
|
||||
"""
|
||||
return False
|
||||
|
||||
def search(self, cr, uid, args, *rest, **kwargs):
|
||||
"""
|
||||
When a complete IBAN is searched, also search for its BBAN
|
||||
if we have the domestic column. Disregard spaces
|
||||
when comparing IBANs.
|
||||
"""
|
||||
|
||||
def is_term(arg):
|
||||
'''Flag an arg as term or otherwise'''
|
||||
return isinstance(arg, (list, tuple)) and len(arg) == 3
|
||||
|
||||
def extended_filter_term(term):
|
||||
'''
|
||||
Extend the search criteria in term when appropriate.
|
||||
'''
|
||||
result = [term]
|
||||
extra_terms = []
|
||||
if term[0].lower() == 'acc_number' and term[1] in ('=', '=='):
|
||||
iban = sepa.IBAN(term[2])
|
||||
if iban.valid:
|
||||
# Disregard spaces when comparing IBANs
|
||||
cr.execute(
|
||||
"""
|
||||
SELECT id FROM res_partner_bank
|
||||
WHERE replace(acc_number, ' ', '') = %s
|
||||
""", (term[2].replace(' ', ''),))
|
||||
ids = [row[0] for row in cr.fetchall()]
|
||||
result = [('id', 'in', ids)]
|
||||
|
||||
if 'acc_number_domestic' in self._columns:
|
||||
bban = iban.localized_BBAN
|
||||
# Prevent empty search filters
|
||||
if bban:
|
||||
extra_terms.append(
|
||||
('acc_number_domestic', term[1], bban))
|
||||
for extra_term in extra_terms:
|
||||
result = ['|'] + result + [extra_term]
|
||||
return result
|
||||
|
||||
def extended_search_expression(args):
|
||||
'''
|
||||
Extend the search expression in args when appropriate.
|
||||
The expression itself is in reverse polish notation, so recursion
|
||||
is not needed.
|
||||
'''
|
||||
if not args:
|
||||
return []
|
||||
|
||||
result = []
|
||||
if is_term(args[0]) and len(args) > 1:
|
||||
# Classic filter, implicit '&'
|
||||
result += ['&']
|
||||
|
||||
for arg in args:
|
||||
if is_term(arg):
|
||||
result += extended_filter_term(arg)
|
||||
else:
|
||||
result += arg
|
||||
return result
|
||||
|
||||
# Extend search filter
|
||||
newargs = extended_search_expression(args)
|
||||
|
||||
# Original search
|
||||
return super(ResPartnerBank, self).search(
|
||||
cr, uid, newargs, *rest, **kwargs)
|
||||
@@ -0,0 +1,5 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_account_banking_settings","account.banking.account.settings","model_account_banking_account_settings","account.group_account_manager",1,1,1,1
|
||||
"access_account_banking_settings_user","account.banking.account.settings user","model_account_banking_account_settings","account.group_account_user",1,0,0,0
|
||||
"access_account_banking_import","account.bankimport","model_account_banking_imported_file","account.group_account_user",1,1,1,1
|
||||
"access_banking_import_transaction","Banking addons - Bank import transaction","model_banking_import_transaction","account.group_account_user",1,1,1,1
|
||||
|
23
__unported__/account_banking/sepa/__init__.py
Normal file
23
__unported__/account_banking/sepa/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 iban
|
||||
IBAN = iban.IBAN
|
||||
BBAN = iban.BBAN
|
||||
534
__unported__/account_banking/sepa/iban.py
Normal file
534
__unported__/account_banking/sepa/iban.py
Normal file
@@ -0,0 +1,534 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# The information about SEPA account numbers in this module are collected
|
||||
# from ISO 13616-1, which can be found at SWIFT's website:
|
||||
# http://www.swift.com/solutions/messaging/information_products/bic_downloads_documents/pdfs/IBAN_Registry.pdf
|
||||
#
|
||||
# This module uses both SEPA and IBAN as seemingly interchangeble terms.
|
||||
# However, a SEPA account is a bank account in the SEPA zone, which is
|
||||
# represented by a IBAN number, which is build up from a ISO-693-1 two letter
|
||||
# country code, two check digits and a BBAN number, representing the
|
||||
# local/national accounting scheme.
|
||||
#
|
||||
# With the exception of Turkey, all countries use the full local adressing
|
||||
# scheme in the IBAN numbers, making it possible to deduce the BBAN from the
|
||||
# IBAN. As Turkey uses an additional code in the local scheme which is not
|
||||
# part of the BBAN, for accounts located in Turkeys banks it is not possible
|
||||
# to use the BBAN to reconstruct the local account.
|
||||
#
|
||||
# WARNING:
|
||||
# This module contains seemingly enough info to create IBAN's from BBAN's.
|
||||
# Although many BBAN/IBAN conversions seem algorithmic, there is enough
|
||||
# deviation to take the warning from SEPA seriously: this is the domain of the
|
||||
# account owning banks. Don't use it, unless you are prepared to loose your
|
||||
# money. It is for heuristic validation purposes only.
|
||||
|
||||
__all__ = ['IBAN', 'BBAN']
|
||||
|
||||
|
||||
def modulo_97_base10(abuffer):
|
||||
'''
|
||||
Calculate the modulo 97 value of a string in base10
|
||||
'''
|
||||
checksum = int(abuffer[0])
|
||||
for digit in abuffer[1:]:
|
||||
checksum *= 10
|
||||
checksum += int(digit)
|
||||
checksum %= 97
|
||||
return checksum
|
||||
|
||||
|
||||
def base36_to_base10str(abuffer):
|
||||
'''
|
||||
Convert a base36 string value to a string of base10 digits.
|
||||
'''
|
||||
result = ''
|
||||
for digit in abuffer:
|
||||
if digit.isalpha():
|
||||
result += str(ord(digit) - 55)
|
||||
else:
|
||||
result += digit
|
||||
return result
|
||||
|
||||
|
||||
class BBANFormat(object):
|
||||
'''
|
||||
A BBANFormat is an auxilliary class for IBAN. It represents the composition
|
||||
of a BBAN number from the different elements in order to translate a
|
||||
IBAN number to a localized number. The reverse route, transforming a local
|
||||
account to a SEPA account, is the sole responsibility of the banks.
|
||||
'''
|
||||
|
||||
def __init__(self, ibanfmt, bbanfmt='%A', nolz=False):
|
||||
'''
|
||||
Specify the structure of the SEPA account in relation to the local
|
||||
account. The XXZZ prefix that all SEPA accounts have is not part of
|
||||
the structure in BBANFormat.
|
||||
|
||||
ibanfmt: string of identifiers from position 5 (start = 1):
|
||||
A = Account position
|
||||
N = Account digit
|
||||
B = Bank code digit
|
||||
C = Branch code digit
|
||||
V = Account check digit
|
||||
W = Bank code check digit
|
||||
X = Additional check digit (some countries check everything)
|
||||
P = Account prefix digit
|
||||
|
||||
The combination of N and A can be used to encode minimum length
|
||||
leading-zero-stripped account numbers.
|
||||
|
||||
Example: (NL) 'CCCCAAAAAAAAAA'
|
||||
will convert 'INGB0001234567' into
|
||||
bankcode 'INGB' and account '0001234567'
|
||||
|
||||
bbanfmt: string of placeholders for the local bank account
|
||||
%C: bank code
|
||||
%B: branch code
|
||||
%I: IBAN number (complete)
|
||||
%T: account type
|
||||
%P: account prefix
|
||||
%A: account number. This will include the 'N' placeholder
|
||||
positions in the ibanfmt.
|
||||
%V, %W, %X: check digits (separate meanings)
|
||||
%Z: IBAN check digits (only Poland uses these)
|
||||
%%: %
|
||||
anything else: literal copy
|
||||
|
||||
Example: (AT): '%A BLZ %C'
|
||||
|
||||
nolz: boolean indicating stripping of leading zeroes in the account
|
||||
number. Defaults to False
|
||||
'''
|
||||
self._iban = ibanfmt
|
||||
self._bban = bbanfmt
|
||||
self._nolz = nolz
|
||||
|
||||
def __extract__(self, spec, value):
|
||||
'''Extract the value based on the spec'''
|
||||
i = self._iban.find(spec)
|
||||
if i < 0:
|
||||
return ''
|
||||
result = ''
|
||||
j = len(self._iban)
|
||||
while i < j and self._iban[i] == spec:
|
||||
result += value[i+4]
|
||||
i += 1
|
||||
return self._nolz and result.lstrip('0') or result
|
||||
|
||||
def bankcode(self, iban):
|
||||
'''Return the bankcode'''
|
||||
return self.__extract__('B', iban)
|
||||
|
||||
def branchcode(self, iban):
|
||||
'''Return the branch code'''
|
||||
return self.__extract__('C', iban)
|
||||
|
||||
def account(self, iban):
|
||||
'''Return the account number'''
|
||||
if self._iban.find('N') >= 0:
|
||||
prefix = self.__extract__('N', iban).lstrip('0')
|
||||
else:
|
||||
prefix = ''
|
||||
return prefix + self.__extract__('A', iban)
|
||||
|
||||
def BBAN(self, iban):
|
||||
'''
|
||||
Format the BBAN part of the IBAN in iban following the local
|
||||
addressing scheme. We need the full IBAN in order to be able to use
|
||||
the IBAN check digits in it, as Poland needs.
|
||||
'''
|
||||
res = ''
|
||||
i = 0
|
||||
while i < len(self._bban):
|
||||
if self._bban[i] == '%':
|
||||
i += 1
|
||||
parm = self._bban[i]
|
||||
if parm == 'I':
|
||||
res += unicode(iban)
|
||||
elif parm in 'BCDPTVWX':
|
||||
res += self.__extract__(parm, iban)
|
||||
elif parm == 'A':
|
||||
res += self.account(iban)
|
||||
elif parm == 'S':
|
||||
res += iban
|
||||
elif parm == 'Z':
|
||||
# IBAN check digits (Poland)
|
||||
res += iban[2:4]
|
||||
elif parm == '%':
|
||||
res += '%'
|
||||
else:
|
||||
res += self._bban[i]
|
||||
i += 1
|
||||
return res
|
||||
|
||||
|
||||
class IBAN(str):
|
||||
'''
|
||||
A IBAN string represents a SEPA bank account number. This class provides
|
||||
the interpretation and some validation of such strings.
|
||||
|
||||
Mind that, although there is sufficient reason to comment on the chosen
|
||||
approach, we are talking about a transition period of at max. 1 year. Good
|
||||
is good enough.
|
||||
'''
|
||||
BBAN_formats = {
|
||||
'AL': BBANFormat('CCBBBBVAAAAAAAAAAAAAAAAAA', '%B%A'),
|
||||
'AD': BBANFormat('CCCCBBBBAAAAAAAAAAAA', '%A'),
|
||||
'AT': BBANFormat('BBBBBAAAAAAAAAAA', '%A BLZ %B'),
|
||||
'BE': BBANFormat('CCCAAAAAAAVV', '%C-%A-%V'),
|
||||
'BA': BBANFormat('BBBCCCAAAAAAAA', '%I'),
|
||||
'BG': BBANFormat('BBBBCCCCAAAAAAAAAA', '%I'),
|
||||
'CH': BBANFormat('CCCCCAAAAAAAAAAAAV', '%C %A', nolz=True),
|
||||
'CS': BBANFormat('BBBAAAAAAAAAAAAAVV', '%B-%A-%V'),
|
||||
'CY': BBANFormat('BBBCCCCCAAAAAAAAAAAAAAAA', '%B%C%A'),
|
||||
'CZ': BBANFormat('BBBBPPPPPPAAAAAAAAAA', '%B-%P/%A'),
|
||||
'DE': BBANFormat('BBBBBBBBAAAAAAAAAAV', '%A BLZ %B'),
|
||||
'DK': BBANFormat('CCCCAAAAAAAAAV', '%C %A%V'),
|
||||
'EE': BBANFormat('BBCCAAAAAAAAAAAV', '%A%V'),
|
||||
'ES': BBANFormat('BBBBCCCCWVAAAAAAAAAA', '%B%C%W%V%A'),
|
||||
'FI': BBANFormat('CCCCTTAAAAAAAV', '%C%T-%A%V', nolz=True),
|
||||
'FR': BBANFormat('BBBBBCCCCCAAAAAAAAAAAVV', '%B %C %A %V'),
|
||||
'FO': BBANFormat('BBBBAAAAAAAAAV', '%B %A%V'),
|
||||
# Great Brittain uses a special display for the branch code, which we
|
||||
# can't honor using the current system. If this appears to be a
|
||||
# problem, we can come up with something later.
|
||||
'GB': BBANFormat('BBBBCCCCCCAAAAAAAAV', '%C %A'),
|
||||
'GI': BBANFormat('BBBBAAAAAAAAAAAAAAA', '%A'),
|
||||
'GL': BBANFormat('CCCCAAAAAAAAAV', '%C %A%V'),
|
||||
'GR': BBANFormat('BBBCCCCAAAAAAAAAAAAAAAA', '%B-%C-%A', nolz=True),
|
||||
'HR': BBANFormat('BBBBBBBAAAAAAAAAA', '%B-%A'),
|
||||
'HU': BBANFormat('BBBCCCCXAAAAAAAAAAAAAAAV', '%B%C%X %A%V'),
|
||||
'IE': BBANFormat('BBBBCCCCCCAAAAAAAA', '%C %A'),
|
||||
'IL': BBANFormat('BBBCCCAAAAAAAAAAAAA', '%C%A'),
|
||||
# Iceland uses an extra identification number, split in two on
|
||||
# display. Coded here as %P%V.
|
||||
'IS': BBANFormat('CCCCTTAAAAAAPPPPPPVVVV', '%C-%T-%A-%P-%V'),
|
||||
'IT': BBANFormat('WBBBBBCCCCCAAAAAAAAAAAA', '%W/%B/%C/%A'),
|
||||
'LV': BBANFormat('BBBBAAAAAAAAAAAAA', '%I'),
|
||||
'LI': BBANFormat('CCCCCAAAAAAAAAAAA', '%C %A', nolz=True),
|
||||
'LT': BBANFormat('BBBBBAAAAAAAAAAA', '%I'),
|
||||
'LU': BBANFormat('BBBAAAAAAAAAAAAA', '%I'),
|
||||
'MC': BBANFormat('BBBBBCCCCCAAAAAAAAAAAVV', '%B %C %A %V'),
|
||||
'ME': BBANFormat('CCCAAAAAAAAAAAAAVV', '%C-%A-%V'),
|
||||
'MK': BBANFormat('BBBAAAAAAAAAAVV', '%B-%A-%V', nolz=True),
|
||||
'MT': BBANFormat('BBBBCCCCCAAAAAAAAAAAAAAAAAA', '%A', nolz=True),
|
||||
# Mauritius has an aditional bank identifier, a reserved part and the
|
||||
# currency as part of the IBAN encoding. As there is no representation
|
||||
# given for the local account in ISO 13616-1 we assume IBAN, which
|
||||
# circumvents the BBAN display problem.
|
||||
'MU': BBANFormat('BBBBBBCCAAAAAAAAAAAAVVVWWW', '%I'),
|
||||
# Netherlands has two different local account schemes: one with and
|
||||
# one without check digit (9-scheme and 7-scheme). Luckily most Dutch
|
||||
# financial services can keep the two apart without telling, so leave
|
||||
# that. Also leave the leading zero issue, as most banks are already
|
||||
# converting their local account numbers to BBAN format.
|
||||
'NL': BBANFormat('BBBBAAAAAAAAAA', '%A'),
|
||||
# Norway seems to split the account number in two on display. For now
|
||||
# we leave that. If this appears to be a problem, we can fix it later.
|
||||
'NO': BBANFormat('CCCCAAAAAV', '%C.%A%V'),
|
||||
'PL': BBANFormat('CCCCCCCCAAAAAAAAAAAAAAAA', '%Z%C %A'),
|
||||
'PT': BBANFormat('BBBBCCCCAAAAAAAAAAAVV', '%B.%C.%A.%V'),
|
||||
'RO': BBANFormat('BBBBAAAAAAAAAAAAAAAA', '%A'),
|
||||
'SA': BBANFormat('BBAAAAAAAAAAAAAAAA', '%B%A'),
|
||||
'SE': BBANFormat('CCCAAAAAAAAAAAAAAAAV', '%A'),
|
||||
'SI': BBANFormat('CCCCCAAAAAAAAVV', '%C-%A%V', ),
|
||||
# Slovakia uses two different format for local display. We stick with
|
||||
# their formal BBAN specs
|
||||
'SK': BBANFormat('BBBBPPPPPPAAAAAAAAAAAA', '%B%P%A'),
|
||||
# San Marino: No information for display of BBAN, so stick with IBAN
|
||||
'SM': BBANFormat('WBBBBBCCCCCCAAAAAAAAAAAAV', '%I'),
|
||||
'TN': BBANFormat('BBCCCAAAAAAAAAAAAAVV', '%B %C %A %V'),
|
||||
# Turkey has insufficient information in the IBAN number to regenerate
|
||||
# the BBAN: the branch code for local addressing is missing (5n).
|
||||
'TR': BBANFormat('BBBBBWAAAAAAAAAAAAAAAA', '%B%C%A'),
|
||||
}
|
||||
countries = BBAN_formats.keys()
|
||||
unknown_BBAN_format = BBANFormat('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', '%I')
|
||||
|
||||
def __new__(cls, arg, **kwargs):
|
||||
'''
|
||||
All letters should be uppercase and acceptable. As str is an
|
||||
in 'C' implemented class, this can't be done in __init__.
|
||||
'''
|
||||
init = ''
|
||||
if arg:
|
||||
for item in arg.upper():
|
||||
if item.isalnum():
|
||||
init += item
|
||||
elif item not in ' \t.-':
|
||||
raise ValueError('Invalid chars found in IBAN number')
|
||||
return str.__new__(cls, init)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
Sanity check: don't offer extensions unless the base is sound.
|
||||
'''
|
||||
super(IBAN, self).__init__()
|
||||
if self.countrycode not in self.countries:
|
||||
self.BBAN_format = self.unknown_BBAN_format
|
||||
else:
|
||||
self.BBAN_format = self.BBAN_formats[self.countrycode]
|
||||
|
||||
@classmethod
|
||||
def create(cls, BIC=None, countrycode=None, BBAN=None, bankcode=None,
|
||||
branchcode=None, account=None):
|
||||
'''
|
||||
Create a IBAN number from a BBAN and a country code. Optionaly create
|
||||
a BBAN from BBAN components before generation.
|
||||
|
||||
Incomplete: can only work with valid BBAN now.
|
||||
'''
|
||||
if BIC:
|
||||
if not bankcode:
|
||||
bankcode = BIC[:4]
|
||||
if not countrycode:
|
||||
countrycode = BIC[4:6]
|
||||
else:
|
||||
if countrycode:
|
||||
countrycode = countrycode.upper()
|
||||
else:
|
||||
raise ValueError('Either BIC or countrycode is required')
|
||||
|
||||
if countrycode not in cls.countries:
|
||||
raise ValueError('%s is not a SEPA country' % countrycode)
|
||||
format = cls.BBAN_formats[countrycode]
|
||||
|
||||
if BBAN:
|
||||
if len(BBAN) == len(format._iban):
|
||||
ibanno = cls(countrycode + '00' + BBAN)
|
||||
return cls(countrycode + ibanno.checksum + BBAN)
|
||||
raise ValueError('Insufficient data to generate IBAN')
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
'''
|
||||
Check if the string + check digits deliver a valid checksum
|
||||
'''
|
||||
_buffer = self[4:] + self[:4]
|
||||
return (
|
||||
self.countrycode in self.countries
|
||||
and int(base36_to_base10str(_buffer)) % 97 == 1
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
'''
|
||||
Formal representation is in chops of four characters, devided by a
|
||||
space.
|
||||
'''
|
||||
parts = []
|
||||
for i in range(0, len(self), 4):
|
||||
parts.append(self[i:i+4])
|
||||
return ' '.join(parts)
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
Return unicode representation of self
|
||||
'''
|
||||
return u'%r' % self
|
||||
|
||||
@property
|
||||
def checksum(self):
|
||||
'''
|
||||
Generate a new checksum for an otherwise correct layed out BBAN in a
|
||||
IBAN string.
|
||||
NOTE: This is the responsability of the banks. No guaranties whatsoever
|
||||
that this delivers usable IBAN accounts. Mind your money!
|
||||
'''
|
||||
_buffer = self[4:] + self[:2] + '00'
|
||||
_buffer = base36_to_base10str(_buffer)
|
||||
return '%.2d' % (98 - modulo_97_base10(_buffer))
|
||||
|
||||
@property
|
||||
def checkdigits(self):
|
||||
'''
|
||||
Return the digits which form the checksum in the IBAN string
|
||||
'''
|
||||
return self[2:4]
|
||||
|
||||
@property
|
||||
def countrycode(self):
|
||||
'''
|
||||
Return the ISO country code
|
||||
'''
|
||||
return self[:2]
|
||||
|
||||
@property
|
||||
def bankcode(self):
|
||||
'''
|
||||
Return the bank code
|
||||
'''
|
||||
return self.BBAN_format.bankcode(self)
|
||||
|
||||
@property
|
||||
def BIC_searchkey(self):
|
||||
'''
|
||||
BIC's, or Bank Identification Numbers, are composed of the bank
|
||||
code, followed by the country code, followed by the localization
|
||||
code, followed by an optional department number.
|
||||
|
||||
The bank code seems to be world wide unique. Knowing this,
|
||||
one can use the country + bankcode info from BIC to narrow a
|
||||
search for the bank itself.
|
||||
|
||||
Note that some countries use one single localization code for
|
||||
all bank transactions in that country, while others do not. This
|
||||
makes it impossible to use an algorithmic approach for generating
|
||||
the full BIC.
|
||||
'''
|
||||
return self.bankcode[:4] + self.countrycode
|
||||
|
||||
@property
|
||||
def branchcode(self):
|
||||
'''
|
||||
Return the branch code
|
||||
'''
|
||||
return self.BBAN_format.branchcode(self)
|
||||
|
||||
@property
|
||||
def localized_BBAN(self):
|
||||
'''
|
||||
Localized format of local or Basic Bank Account Number, aka BBAN
|
||||
'''
|
||||
if self.countrycode == 'TR':
|
||||
# The Turkish BBAN requires information that is not in the
|
||||
# IBAN number.
|
||||
return False
|
||||
return self.BBAN_format.BBAN(self)
|
||||
|
||||
@property
|
||||
def BBAN(self):
|
||||
'''
|
||||
Return full encoded BBAN, which is for all countries the IBAN string
|
||||
after the ISO-639 code and the two check digits.
|
||||
'''
|
||||
return self[4:]
|
||||
|
||||
|
||||
class BBAN(object):
|
||||
'''
|
||||
Class to reformat a local BBAN account number to IBAN specs.
|
||||
Simple validation based on length of spec string elements and real data.
|
||||
'''
|
||||
|
||||
@staticmethod
|
||||
def _get_length(fmt, element):
|
||||
'''
|
||||
Internal method to calculate the length of a parameter in a
|
||||
formatted string
|
||||
'''
|
||||
i = 0
|
||||
max_i = len(fmt._iban)
|
||||
while i < max_i:
|
||||
if fmt._iban[i] == element:
|
||||
next = i + 1
|
||||
while next < max_i and fmt._iban[next] == element:
|
||||
next += 1
|
||||
return next - i
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
def __init__(self, bban, countrycode):
|
||||
'''
|
||||
Reformat and sanity check on BBAN format.
|
||||
Note that this is not a fail safe check, it merely checks the format of
|
||||
the BBAN following the IBAN specifications.
|
||||
'''
|
||||
self._bban = None
|
||||
if countrycode.upper() in IBAN.countries:
|
||||
self._fmt = IBAN.BBAN_formats[countrycode.upper()]
|
||||
res = ''
|
||||
i = 0
|
||||
j = 0
|
||||
max_i = len(self._fmt._bban)
|
||||
max_j = len(bban)
|
||||
while i < max_i and j < max_j:
|
||||
while bban[j] in ' \t' and j < max_j:
|
||||
j += 1
|
||||
if self._fmt._bban[i] == '%':
|
||||
i += 1
|
||||
parm = self._fmt._bban[i]
|
||||
if parm == 'I':
|
||||
_bban = IBAN(bban)
|
||||
if _bban.valid:
|
||||
self._bban = str(_bban)
|
||||
else:
|
||||
self._bban = None
|
||||
# Valid, so nothing else to do
|
||||
return
|
||||
elif parm in 'ABCDPSTVWXZ':
|
||||
_len = self._get_length(self._fmt, parm)
|
||||
addon = bban[j:j+_len]
|
||||
if len(addon) != _len:
|
||||
# Note that many accounts in the IBAN standard
|
||||
# are allowed to have leading zeros, so zfill
|
||||
# to full spec length for visual validation.
|
||||
#
|
||||
# Note 2: this may look funny to some, as most
|
||||
# local schemes strip leading zeros. It allows
|
||||
# us however to present the user a visual feedback
|
||||
# in order to catch simple user mistakes as
|
||||
# missing digits.
|
||||
if parm == 'A':
|
||||
res += addon.zfill(_len)
|
||||
else:
|
||||
# Invalid, just drop the work and leave
|
||||
return
|
||||
else:
|
||||
res += addon
|
||||
j += _len
|
||||
elif self._fmt._bban[i] in [bban[j], ' ', '/', '-', '.']:
|
||||
res += self._fmt._bban[i]
|
||||
if self._fmt._bban[i] == bban[j]:
|
||||
j += 1
|
||||
elif self._fmt._bban[i].isalpha():
|
||||
res += self._fmt._bban[i]
|
||||
i += 1
|
||||
if i == max_i:
|
||||
self._bban = res
|
||||
|
||||
def __str__(self):
|
||||
'''String representation'''
|
||||
return self._bban
|
||||
|
||||
def __unicode__(self):
|
||||
'''Unicode representation'''
|
||||
return unicode(self._bban)
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
'''Simple check if BBAN is in the right format'''
|
||||
return self._bban and True or False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
for arg in sys.argv[1:]:
|
||||
iban = IBAN(arg)
|
||||
print('IBAN:', iban)
|
||||
print('country code:', iban.countrycode)
|
||||
print('bank code:', iban.bankcode)
|
||||
print('branch code:', iban.branchcode)
|
||||
print('BBAN:', iban.BBAN)
|
||||
print('localized BBAN:', iban.localized_BBAN)
|
||||
print('check digits:', iban.checkdigits)
|
||||
print('checksum:', iban.checksum)
|
||||
187
__unported__/account_banking/sepa/postalcode.py
Normal file
187
__unported__/account_banking/sepa/postalcode.py
Normal file
@@ -0,0 +1,187 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
'''
|
||||
This module provides a utility class to extract postal codes from address
|
||||
strings.
|
||||
'''
|
||||
import re
|
||||
|
||||
__all__ = ['split', 'get', 'PostalCode']
|
||||
|
||||
|
||||
class PostalCode(object):
|
||||
'''
|
||||
The PostalCode class is a wrapper around PostCodeFormat and an internal
|
||||
database of postalcode formats. It provides the class methods split() and
|
||||
get(), both of which must be called with the two character iso country
|
||||
code as first parameter.
|
||||
'''
|
||||
|
||||
class PostalCodeFormat(object):
|
||||
'''
|
||||
Utility class of PostalCode.
|
||||
Allows finding and splitting of postalcode in strings
|
||||
'''
|
||||
def __init__(self, format):
|
||||
'''
|
||||
Create regexp patterns for matching
|
||||
'''
|
||||
# Sort formats on length, longest first
|
||||
formats = [(len(x), x) for x in format.split('|')]
|
||||
formats = [x[1] for x in sorted(formats, lambda x, y: -cmp(x, y))]
|
||||
self.res = [re.compile(x.replace('#', '\\d').replace('@', '[A-Z]'))
|
||||
for x in formats
|
||||
]
|
||||
|
||||
def get(self, str_):
|
||||
'''
|
||||
Return the postal code from the string str_
|
||||
'''
|
||||
for re_ in self.res:
|
||||
retval = re_.findall(str_)
|
||||
if retval:
|
||||
break
|
||||
return retval and retval[0] or ''
|
||||
|
||||
def split(self, str_):
|
||||
'''
|
||||
Split str_ into (postalcode, remainder)
|
||||
'''
|
||||
for re_ in self.res:
|
||||
pos = re_.search(str_)
|
||||
if pos:
|
||||
break
|
||||
if pos:
|
||||
return (pos.group(), str_[pos.end():])
|
||||
return ('', str_)
|
||||
|
||||
_formats = {
|
||||
'AF': '', 'AX': '', 'AL': '', 'DZ': '#####', 'AS': '', 'AD': 'AD###',
|
||||
'AO': '', 'AI': '', 'AQ': '', 'AG': '', 'AR': '@####@@@',
|
||||
'AM': '######', 'AW': '', 'AU': '####', 'AT': '####', 'AZ': 'AZ ####',
|
||||
'BS': '', 'BH': '####|###', 'BD': '####', 'BB': 'BB#####',
|
||||
'BY': '######', 'BE': '####', 'BZ': '', 'BJ': '', 'BM': '@@ ##',
|
||||
'BT': '', 'BO': '', 'BA': '#####', 'BW': '', 'BV': '',
|
||||
'BR': '#####-###', 'IO': '', 'BN': '@@####', 'BG': '####', 'BF': '',
|
||||
'BI': '', 'KH': '#####', 'CM': '', 'CA': '@#@ #@#', 'CV': '####',
|
||||
'KY': '', 'CF': '', 'TD': '', 'CL': '#######', 'CN': '######',
|
||||
'CX': '####', 'CC': '', 'CO': '', 'KM': '', 'CG': '', 'CD': '',
|
||||
'CK': '', 'CR': '####', 'CI': '', 'HR': 'HR-#####', 'CU': 'CP #####',
|
||||
'CY': '####', 'CZ': '### ##', 'DK': '####', 'DJ': '', 'DM': '',
|
||||
'DO': '#####', 'EC': '@####@', 'EG': '#####', 'SV': 'CP ####',
|
||||
'GQ': '', 'ER': '', 'EE': '#####', 'ET': '####', 'FK': '',
|
||||
'FO': 'FO-###', 'FJ': '', 'FI': 'FI-#####', 'FR': '#####',
|
||||
'GF': '#####', 'PF': '#####', 'TF': '', 'GA': '', 'GM': '',
|
||||
'GE': '####', 'DE': '#####', 'GH': '', 'GI': '', 'GR': '### ##',
|
||||
'GL': '####', 'GD': '', 'GP': '#####', 'GU': '969##', 'GT': '#####',
|
||||
'GG': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
|
||||
'GN': '', 'GW': '####', 'GY': '', 'HT': 'HT####', 'HM': '', 'VA': '',
|
||||
'HN': '@@####', 'HK': '', 'HU': '####', 'IS': '###', 'IN': '######',
|
||||
'ID': '#####', 'IR': '##########', 'IQ': '#####', 'IE': '',
|
||||
'IM': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
|
||||
'IL': '#####', 'IT': '####', 'JM': '', 'JP': '###-####',
|
||||
'JE': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
|
||||
'JO': '#####', 'KZ': '######', 'KE': '#####', 'KI': '',
|
||||
'KP': '###-###',
|
||||
'KR': 'SEOUL ###-###', 'KW': '#####', 'KG': '######', 'LA': '#####',
|
||||
'LV': 'LV-####', 'LB': '#### ####|####', 'LS': '###', 'LR': '####',
|
||||
'LY': '', 'LI': '####', 'LT': 'LT-#####', 'LU': '####', 'MO': '',
|
||||
'MK': '####', 'MG': '###', 'MW': '', 'MY': '#####', 'MV': '#####',
|
||||
'ML': '', 'MT': '@@@ ###|@@@ ##', 'MH': '', 'MQ': '#####', 'MR': '',
|
||||
'MU': '', 'YT': '#####', 'MX': '#####', 'FM': '#####', 'MD': 'MD-####',
|
||||
'MC': '#####', 'MN': '######', 'ME': '#####', 'MS': '', 'MA': '#####',
|
||||
'MZ': '####', 'MM': '#####', 'NA': '', 'NR': '', 'NP': '#####',
|
||||
'NL': '#### @@', 'AN': '', 'NC': '#####', 'NZ': '####',
|
||||
'NI': '###-###-#', 'NE': '####', 'NG': '######', 'NU': '', 'NF': '',
|
||||
'MP': '', 'NO': '####', 'OM': '###', 'PK': '#####', 'PW': '96940',
|
||||
'PS': '', 'PA': '', 'PG': '###', 'PY': '####', 'PE': '', 'PH': '####',
|
||||
'PN': '', 'PL': '##-###', 'PT': '####-###', 'PR': '#####-####',
|
||||
'QA': '', 'RE': '#####', 'RO': '######', 'RU': '######', 'RW': '',
|
||||
'BL': '### ###', 'SH': 'STHL 1ZZ', 'KN': '', 'LC': '', 'MF': '### ###',
|
||||
'PM': '', 'VC': '', 'WS': '', 'SM': '4789#', 'ST': '', 'SA': '#####',
|
||||
'SN': '#####', 'RS': '######', 'SC': '', 'SL': '', 'SG': '######',
|
||||
'SK': '### ##', 'SI': 'SI- ####', 'SB': '', 'SO': '@@ #####',
|
||||
'ZA': '####', 'GS': '', 'ES': '#####', 'LK': '#####', 'SD': '#####',
|
||||
'SR': '', 'SJ': '', 'SZ': '@###', 'SE': 'SE-### ##', 'CH': '####',
|
||||
'SY': '', 'TW': '#####', 'TJ': '######', 'TZ': '', 'TH': '#####',
|
||||
'TL': '', 'TG': '', 'TK': '', 'TO': '', 'TT': '', 'TN': '####',
|
||||
'TR': '#####', 'TM': '######', 'TC': 'TKCA 1ZZ', 'TV': '', 'UG': '',
|
||||
'UA': '#####', 'AE': '',
|
||||
'GB': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
|
||||
'US': '#####-####', 'UM': '', 'UY': '#####', 'UZ': '######', 'VU': '',
|
||||
'VE': '####', 'VN': '######', 'VG': '', 'VI': '', 'WF': '', 'EH': '',
|
||||
'YE': '', 'ZM': '#####', 'ZW': ''
|
||||
}
|
||||
for iso, formatstr in _formats.iteritems():
|
||||
_formats[iso] = PostalCodeFormat(formatstr)
|
||||
|
||||
@classmethod
|
||||
def split(cls, str_, iso=''):
|
||||
'''
|
||||
Split string <str_> in (postalcode, remainder) following the specs of
|
||||
country <iso>.
|
||||
|
||||
Returns iso, postal code and the remaining part of <str_>.
|
||||
|
||||
When iso is filled but postal code remains empty, no postal code could
|
||||
be found according to the rules of iso.
|
||||
|
||||
When iso is empty but postal code is not, a proximity match was
|
||||
made where multiple hits gave similar results. A postal code is
|
||||
likely, but a unique iso code could not be identified.
|
||||
|
||||
When neither iso or postal code are filled, no proximity match could
|
||||
be made.
|
||||
'''
|
||||
if iso in cls._formats:
|
||||
return (iso,) + tuple(cls._formats[iso].split(str_))
|
||||
|
||||
# Find optimum (= max length postalcode) when iso code is unknown
|
||||
all = {}
|
||||
max_l = 0
|
||||
for key in cls._formats.iterkeys():
|
||||
i, p, c = cls.split(str_, key)
|
||||
l = len(p)
|
||||
if l > max_l:
|
||||
max_l = l
|
||||
if l in all:
|
||||
all[l].append((i, p, c))
|
||||
else:
|
||||
all[l] = [(i, p, c)]
|
||||
if max_l > 0:
|
||||
if len(all[max_l]) > 1:
|
||||
return ('',) + all[max_l][0][1:]
|
||||
return all[max_l][0]
|
||||
return ('', '', str_)
|
||||
|
||||
@classmethod
|
||||
def get(cls, iso, str_):
|
||||
'''
|
||||
Extracts the postal code from str_ following the specs of country
|
||||
<iso>.
|
||||
'''
|
||||
if iso in cls._formats:
|
||||
return cls._formats[iso].get(str_)
|
||||
return ''
|
||||
|
||||
get = PostalCode.get
|
||||
split = PostalCode.split
|
||||
@@ -0,0 +1,51 @@
|
||||
/*############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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/>.
|
||||
#
|
||||
############################################################################*/
|
||||
|
||||
openerp.account_banking = function(instance)
|
||||
{
|
||||
var _t = instance.web._t;
|
||||
instance.web.Dialog.include(
|
||||
{
|
||||
close: function()
|
||||
{
|
||||
this._super.apply(this, arguments);
|
||||
if (this.dialog_title == _t("Match transaction"))
|
||||
{
|
||||
// The match wizard can create or unlink a statement line
|
||||
// Force a reload of the view so that the correct lines
|
||||
// are shown.
|
||||
var parent = this.getParent()
|
||||
if (parent)
|
||||
{
|
||||
var child = this.getParent().getChildren()[0];
|
||||
if (child.views) {
|
||||
_.each(child.views, function(view)
|
||||
{
|
||||
if (view && view.controller)
|
||||
{
|
||||
view.controller.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
57
__unported__/account_banking/struct.py
Normal file
57
__unported__/account_banking/struct.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
'''
|
||||
Define a struct class which behaves like a dict, but allows using
|
||||
object.attr alongside object['attr'].
|
||||
'''
|
||||
|
||||
__all__ = ['struct']
|
||||
|
||||
|
||||
class struct(dict):
|
||||
'''
|
||||
Ease working with dicts. Allow dict.key alongside dict['key']
|
||||
'''
|
||||
def __setattr__(self, item, value):
|
||||
self.__setitem__(item, value)
|
||||
|
||||
def __getattr__(self, item):
|
||||
return self.__getitem__(item)
|
||||
|
||||
def show(self, indent=0, align=False, ralign=False):
|
||||
'''
|
||||
PrettyPrint method. Aligns keys right (ralign) or left (align).
|
||||
'''
|
||||
if align or ralign:
|
||||
width = 0
|
||||
for key in self.iterkeys():
|
||||
width = max(width, len(key))
|
||||
alignment = ''
|
||||
if not ralign:
|
||||
alignment = '-'
|
||||
fmt = '%*.*s%%%s%d.%ds: %%s' % (
|
||||
indent, indent, '', alignment, width, width
|
||||
)
|
||||
else:
|
||||
fmt = '%*.*s%%s: %%s' % (indent, indent, '')
|
||||
for item in self.iteritems():
|
||||
print(fmt % item)
|
||||
24
__unported__/account_banking/wizard/__init__.py
Normal file
24
__unported__/account_banking/wizard/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 bank_import
|
||||
from . import banking_transaction_wizard
|
||||
from . import link_partner
|
||||
451
__unported__/account_banking/wizard/bank_import.py
Normal file
451
__unported__/account_banking/wizard/bank_import.py
Normal file
@@ -0,0 +1,451 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Many thanks to our contributors
|
||||
#
|
||||
# Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes
|
||||
# Stefan Rijnhart (Therp): bugreport and bugfix
|
||||
#
|
||||
|
||||
'''
|
||||
This module contains the business logic of the wizard account_banking_import.
|
||||
The parsing is done in the parser modules. Every parser module is required to
|
||||
use parser.models as a mean of communication with the business logic.
|
||||
'''
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.account_banking.parsers import models
|
||||
from openerp.addons.account_banking.parsers import convert
|
||||
from openerp.addons.account_banking.struct import struct
|
||||
from openerp.addons.account_banking.wizard import banktools
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
# This variable is used to match supplier invoices with an invoice date after
|
||||
# the real payment date. This can occur with online transactions (web shops).
|
||||
payment_window = datetime.timedelta(days=10)
|
||||
|
||||
|
||||
def parser_types(*args, **kwargs):
|
||||
'''Delay evaluation of parser types until start of wizard, to allow
|
||||
depending modules to initialize and add their parsers to the list
|
||||
'''
|
||||
return models.parser_type.get_parser_types()
|
||||
|
||||
|
||||
class banking_import_line(orm.TransientModel):
|
||||
_name = 'banking.import.line'
|
||||
_description = 'Bank import lines'
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64),
|
||||
'date': fields.date('Date', readonly=True),
|
||||
'amount': fields.float(
|
||||
'Amount',
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
),
|
||||
'statement_line_id': fields.many2one(
|
||||
'account.bank.statement.line',
|
||||
'Resulting statement line', readonly=True),
|
||||
'type': fields.selection([
|
||||
('supplier', 'Supplier'),
|
||||
('customer', 'Customer'),
|
||||
('general', 'General')
|
||||
], 'Type', required=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'statement_id': fields.many2one(
|
||||
'account.bank.statement',
|
||||
'Statement',
|
||||
select=True,
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
),
|
||||
'ref': fields.char('Reference', size=32),
|
||||
'note': fields.text('Notes'),
|
||||
'period_id': fields.many2one('account.period', 'Period'),
|
||||
'currency': fields.many2one('res.currency', 'Currency'),
|
||||
'banking_import_id': fields.many2one(
|
||||
'account.banking.bank.import', 'Bank import',
|
||||
readonly=True, ondelete='cascade'),
|
||||
'reconcile_id': fields.many2one(
|
||||
'account.move.reconcile', 'Reconciliaton'),
|
||||
'account_id': fields.many2one('account.account', 'Account'),
|
||||
'invoice_ids': fields.many2many(
|
||||
'account.invoice', 'banking_import_line_invoice_rel',
|
||||
'line_id', 'invoice_id'),
|
||||
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
|
||||
'transaction_type': fields.selection(
|
||||
[
|
||||
# TODO: payment terminal etc...
|
||||
('invoice', 'Invoice payment'),
|
||||
('storno', 'Canceled debit order'),
|
||||
('bank_costs', 'Bank costs'),
|
||||
('unknown', 'Unknown'),
|
||||
],
|
||||
'Transaction type',
|
||||
),
|
||||
'duplicate': fields.boolean('Duplicate'),
|
||||
}
|
||||
|
||||
|
||||
class banking_import(orm.TransientModel):
|
||||
_name = 'account.banking.bank.import'
|
||||
|
||||
def import_statements_file(self, cr, uid, ids, context):
|
||||
'''
|
||||
Import bank statements / bank transactions file.
|
||||
This method is a wrapper for the business logic on the transaction.
|
||||
The parser modules represent the decoding logic.
|
||||
'''
|
||||
banking_import = self.browse(cr, uid, ids, context)[0]
|
||||
statements_file = banking_import.file
|
||||
data = base64.decodestring(statements_file)
|
||||
|
||||
user_obj = self.pool.get('res.user')
|
||||
statement_obj = self.pool.get('account.bank.statement')
|
||||
statement_file_obj = self.pool.get('account.banking.imported.file')
|
||||
import_transaction_obj = self.pool.get('banking.import.transaction')
|
||||
period_obj = self.pool.get('account.period')
|
||||
|
||||
# get the parser to parse the file
|
||||
parser_code = banking_import.parser
|
||||
parser = models.create_parser(parser_code)
|
||||
if not parser:
|
||||
raise orm.except_orm(
|
||||
_('ERROR!'),
|
||||
_('Unable to import parser %(parser)s. Parser class not '
|
||||
'found.') %
|
||||
{'parser': parser_code}
|
||||
)
|
||||
|
||||
# Get the company
|
||||
company = (banking_import.company or
|
||||
user_obj.browse(cr, uid, uid, context).company_id)
|
||||
|
||||
# Parse the file
|
||||
statements = parser.parse(cr, data)
|
||||
|
||||
if any([x for x in statements if not x.is_valid()]):
|
||||
raise orm.except_orm(
|
||||
_('ERROR!'),
|
||||
_('The imported statements appear to be invalid! Check your '
|
||||
'file.')
|
||||
)
|
||||
|
||||
# Create the file now, as the statements need to be linked to it
|
||||
import_id = statement_file_obj.create(cr, uid, dict(
|
||||
company_id=company.id,
|
||||
file=statements_file,
|
||||
file_name=banking_import.file_name,
|
||||
state='unfinished',
|
||||
format=parser.name,
|
||||
))
|
||||
|
||||
bank_country_code = False
|
||||
if hasattr(parser, 'country_code'):
|
||||
bank_country_code = parser.country_code
|
||||
|
||||
# Results
|
||||
results = struct(
|
||||
stat_loaded_cnt=0,
|
||||
trans_loaded_cnt=0,
|
||||
stat_skipped_cnt=0,
|
||||
trans_skipped_cnt=0,
|
||||
trans_matched_cnt=0,
|
||||
bank_costs_invoice_cnt=0,
|
||||
error_cnt=0,
|
||||
log=[],
|
||||
)
|
||||
|
||||
# Caching
|
||||
error_accounts = {}
|
||||
info = {}
|
||||
imported_statement_ids = []
|
||||
|
||||
transaction_ids = []
|
||||
for statement in statements:
|
||||
if statement.local_account in error_accounts:
|
||||
# Don't repeat messages
|
||||
results.stat_skipped_cnt += 1
|
||||
results.trans_skipped_cnt += len(statement.transactions)
|
||||
continue
|
||||
|
||||
# Create fallback currency code
|
||||
currency_code = (
|
||||
statement.local_currency or company.currency_id.name
|
||||
)
|
||||
|
||||
# Check cache for account info/currency
|
||||
if statement.local_account in info and \
|
||||
currency_code in info[statement.local_account]:
|
||||
account_info = info[statement.local_account][currency_code]
|
||||
|
||||
else:
|
||||
# Pull account info/currency
|
||||
account_info = banktools.get_company_bank_account(
|
||||
self.pool, cr, uid, statement.local_account,
|
||||
statement.local_currency, company, results.log
|
||||
)
|
||||
if not account_info:
|
||||
results.log.append(
|
||||
_('Statements found for unknown account '
|
||||
'%(bank_account)s') % {
|
||||
'bank_account': statement.local_account
|
||||
}
|
||||
)
|
||||
error_accounts[statement.local_account] = True
|
||||
results.error_cnt += 1
|
||||
continue
|
||||
if 'journal_id' not in account_info.keys():
|
||||
results.log.append(
|
||||
_('Statements found for account %(bank_account)s, '
|
||||
'but no default journal was defined.'
|
||||
) % {'bank_account': statement.local_account}
|
||||
)
|
||||
error_accounts[statement.local_account] = True
|
||||
results.error_cnt += 1
|
||||
continue
|
||||
|
||||
# Get required currency code
|
||||
currency_code = account_info.currency_id.name
|
||||
|
||||
# Cache results
|
||||
if statement.local_account not in info:
|
||||
info[statement.local_account] = {
|
||||
currency_code: account_info
|
||||
}
|
||||
else:
|
||||
info[statement.local_account][currency_code] = account_info
|
||||
|
||||
# Final check: no coercion of currencies!
|
||||
if statement.local_currency \
|
||||
and account_info.currency_id.name != statement.local_currency:
|
||||
# TODO: convert currencies?
|
||||
results.log.append(
|
||||
_('Statement %(statement_id)s for account %(bank_account)s'
|
||||
' uses different currency than the defined bank journal.'
|
||||
) % {
|
||||
'bank_account': statement.local_account,
|
||||
'statement_id': statement.id
|
||||
}
|
||||
)
|
||||
error_accounts[statement.local_account] = True
|
||||
results.error_cnt += 1
|
||||
continue
|
||||
|
||||
# Check existence of previous statement
|
||||
# Less well defined formats can resort to a
|
||||
# dynamically generated statement identification
|
||||
# (e.g. a datetime string of the moment of import)
|
||||
# and have potential duplicates flagged by the
|
||||
# matching procedure
|
||||
statement_ids = statement_obj.search(cr, uid, [
|
||||
('name', '=', statement.id),
|
||||
('date', '=', convert.date2str(statement.date)),
|
||||
])
|
||||
if statement_ids:
|
||||
results.log.append(
|
||||
_('Statement %(id)s known - skipped') % {
|
||||
'id': statement.id
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
# Get the period for the statement (as bank statement object
|
||||
# checks this)
|
||||
period_ids = period_obj.search(
|
||||
cr, uid, [
|
||||
('company_id', '=', company.id),
|
||||
('date_start', '<=', statement.date),
|
||||
('date_stop', '>=', statement.date),
|
||||
('special', '=', False),
|
||||
], context=context)
|
||||
|
||||
if not period_ids:
|
||||
results.log.append(
|
||||
_('No period found covering statement date %(date)s, '
|
||||
'statement %(id)s skipped') % {
|
||||
'date': statement.date,
|
||||
'id': statement.id,
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
# Create the bank statement record
|
||||
statement_id = statement_obj.create(cr, uid, dict(
|
||||
name=statement.id,
|
||||
journal_id=account_info.journal_id.id,
|
||||
date=convert.date2str(statement.date),
|
||||
balance_start=statement.start_balance,
|
||||
balance_end_real=statement.end_balance,
|
||||
balance_end=statement.end_balance,
|
||||
state='draft',
|
||||
user_id=uid,
|
||||
banking_id=import_id,
|
||||
company_id=company.id,
|
||||
period_id=period_ids[0],
|
||||
))
|
||||
imported_statement_ids.append(statement_id)
|
||||
|
||||
subno = 0
|
||||
for transaction in statement.transactions:
|
||||
subno += 1
|
||||
if not transaction.id:
|
||||
transaction.id = str(subno)
|
||||
values = {}
|
||||
for attr in transaction.__slots__ + ['type']:
|
||||
if attr in import_transaction_obj.column_map:
|
||||
values[import_transaction_obj.column_map[attr]] = \
|
||||
eval('transaction.%s' % attr)
|
||||
elif attr in import_transaction_obj._columns:
|
||||
values[attr] = eval('transaction.%s' % attr)
|
||||
values['statement_id'] = statement_id
|
||||
values['bank_country_code'] = bank_country_code
|
||||
values['local_account'] = statement.local_account
|
||||
values['local_currency'] = statement.local_currency
|
||||
|
||||
transaction_id = import_transaction_obj.create(
|
||||
cr, uid, values, context=context)
|
||||
transaction_ids.append(transaction_id)
|
||||
|
||||
results.stat_loaded_cnt += 1
|
||||
|
||||
import_transaction_obj.match(
|
||||
cr, uid, transaction_ids, results=results, context=context
|
||||
)
|
||||
|
||||
# recompute statement end_balance for validation
|
||||
statement_obj.button_dummy(
|
||||
cr, uid, imported_statement_ids, context=context)
|
||||
|
||||
report = [
|
||||
'%s: %s' % (_('Total number of statements'),
|
||||
results.stat_skipped_cnt + results.stat_loaded_cnt),
|
||||
'%s: %s' % (_('Total number of transactions'),
|
||||
results.trans_skipped_cnt + results.trans_loaded_cnt),
|
||||
'%s: %s' % (_('Number of errors found'),
|
||||
results.error_cnt),
|
||||
'%s: %s' % (_('Number of statements skipped due to errors'),
|
||||
results.stat_skipped_cnt),
|
||||
'%s: %s' % (_('Number of transactions skipped due to errors'),
|
||||
results.trans_skipped_cnt),
|
||||
'%s: %s' % (_('Number of statements loaded'),
|
||||
results.stat_loaded_cnt),
|
||||
'%s: %s' % (_('Number of transactions loaded'),
|
||||
results.trans_loaded_cnt),
|
||||
'%s: %s' % (_('Number of transactions matched'),
|
||||
results.trans_matched_cnt),
|
||||
'%s: %s' % (_('Number of bank costs invoices created'),
|
||||
results.bank_costs_invoice_cnt),
|
||||
'',
|
||||
'%s:' % (_('Error report')),
|
||||
'',
|
||||
]
|
||||
text_log = '\n'.join(report + results.log)
|
||||
state = results.error_cnt and 'error' or 'ready'
|
||||
statement_file_obj.write(cr, uid, import_id, dict(
|
||||
state=state,
|
||||
log=text_log,
|
||||
), context)
|
||||
if not imported_statement_ids or not results.trans_loaded_cnt:
|
||||
# file state can be 'ready' while import state is 'error'
|
||||
state = 'error'
|
||||
self.write(cr, uid, [ids[0]], dict(
|
||||
import_id=import_id,
|
||||
log=text_log,
|
||||
state=state,
|
||||
statement_ids=[(6, 0, imported_statement_ids)],
|
||||
), context)
|
||||
return {
|
||||
'name': (state == 'ready' and _('Review Bank Statements') or
|
||||
_('Error')),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'view_id': False,
|
||||
'res_model': self._name,
|
||||
'domain': [],
|
||||
'context': dict(context, active_ids=ids),
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'res_id': ids[0] or False,
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'company': fields.many2one(
|
||||
'res.company', 'Company', required=True,
|
||||
states={
|
||||
'ready': [('readonly', True)],
|
||||
'error': [('readonly', True)],
|
||||
},
|
||||
),
|
||||
'file_name': fields.char('File name', size=256),
|
||||
'file': fields.binary(
|
||||
'Statements File',
|
||||
required=True,
|
||||
help=('The Transactions File to import. Please note that while it '
|
||||
'is perfectly safe to reload the same file multiple times '
|
||||
'or to load in timeframe overlapping statements files, '
|
||||
'there are formats that may introduce different '
|
||||
'sequencing, which may create double entries.\n\n'
|
||||
'To stay on the safe side, always load bank statements '
|
||||
'files using the same format.'),
|
||||
states={
|
||||
'ready': [('readonly', True)],
|
||||
'error': [('readonly', True)],
|
||||
},
|
||||
),
|
||||
'parser': fields.selection(
|
||||
parser_types, 'File Format', required=True,
|
||||
states={
|
||||
'ready': [('readonly', True)],
|
||||
'error': [('readonly', True)],
|
||||
},
|
||||
),
|
||||
'log': fields.text('Log', readonly=True),
|
||||
'state': fields.selection(
|
||||
[('init', 'init'),
|
||||
('ready', 'ready'),
|
||||
('error', 'error')
|
||||
],
|
||||
'State', readonly=True),
|
||||
'import_id': fields.many2one(
|
||||
'account.banking.imported.file', 'Import File'),
|
||||
'statement_ids': fields.many2many(
|
||||
'account.bank.statement', 'rel_wiz_statements', 'wizard_id',
|
||||
'statement_id', 'Imported Bank Statements'),
|
||||
'line_ids': fields.one2many(
|
||||
'banking.import.line', 'banking_import_id', 'Transactions',
|
||||
),
|
||||
}
|
||||
|
||||
def _default_parser_type(self, cr, uid, context=None):
|
||||
types = models.parser_type.get_parser_types()
|
||||
return types and types[0][0] or False
|
||||
|
||||
_defaults = {
|
||||
'state': 'init',
|
||||
'company': lambda s, cr, uid, c:
|
||||
s.pool.get('res.company')._company_default_get(
|
||||
cr, uid, 'bank.import.transaction', context=c),
|
||||
'parser': _default_parser_type,
|
||||
}
|
||||
80
__unported__/account_banking/wizard/bank_import_view.xml
Normal file
80
__unported__/account_banking/wizard/bank_import_view.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_banking_import" model="ir.ui.view">
|
||||
<field name="name">account.banking.bank.import</field>
|
||||
<field name="model">account.banking.bank.import</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Import Bank Transactions File" version="7.0">
|
||||
<group colspan="4" states="init,ready,error">
|
||||
<separator colspan="4" string="Select the processing details:"/>
|
||||
<field name="company" colspan="1"/>
|
||||
<field name="file" filename="file_name"/>
|
||||
<field name="file_name" invisible="1"/>
|
||||
<newline />
|
||||
<field name="parser"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page attrs="{'invisible': [('state', '!=', 'review')]}" string="Transactions">
|
||||
<field name="line_ids" colspan="4" nolabel="1">
|
||||
<tree string="Transaction" colors="red:duplicate;blue:reconcile_id">
|
||||
<field name="date"/>
|
||||
<field name="amount"/>
|
||||
<field name="ref"/>
|
||||
<field name="partner_bank_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="account_id"/>
|
||||
<field name="reconcile_id"/>
|
||||
<field name="duplicate"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page attrs="{'invisible': [('state', '=', 'init')]}" string="Log">
|
||||
<field name="log" colspan="4" nolabel="1" width="500"/>
|
||||
</page>
|
||||
<page attrs="{'invisible': [('state', '!=', 'ready')]}" string="Statements">
|
||||
<field name="statement_ids" colspan="4" nolabel="1"
|
||||
attrs="{'invisible': [('state', '!=', 'ready')]}" />
|
||||
</page>
|
||||
</notebook>
|
||||
<footer>
|
||||
<div attrs="{'invisible': [('state', '!=', 'init')]}">
|
||||
<button string="Import" class="oe_highlight"
|
||||
states="init" name="import_statements_file"
|
||||
type="object"/>
|
||||
or
|
||||
<button class="oe_link" special="cancel"
|
||||
states="init" string="Cancel"/>
|
||||
</div>
|
||||
|
||||
<button icon="gtk-close"
|
||||
special="cancel"
|
||||
string="Close"
|
||||
states="ready,error"/>
|
||||
<button icon="gtk-close"
|
||||
name="cancel_statement_lines"
|
||||
type="object"
|
||||
string="Cancel"
|
||||
states="review"/>
|
||||
<button icon="gtk-ok"
|
||||
name="create_statement_lines"
|
||||
type="object"
|
||||
string="Confirm"
|
||||
states="review"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="wizard_account_banking_import_file" model="ir.actions.act_window">
|
||||
<field name="name">Import Bank Statements File</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.banking.bank.import</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_banking_import"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,453 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
|
||||
# (C) 2011 Smile (<http://smile.fr>).
|
||||
# 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 openerp.osv import orm, fields
|
||||
from openerp.tools.translate import _
|
||||
|
||||
"""
|
||||
|
||||
The banking transaction wizard is linked to a button in the statement line
|
||||
tree view. It allows the user to undo the duplicate flag, select between
|
||||
multiple matches or select a manual match.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class banking_transaction_wizard(orm.TransientModel):
|
||||
_name = 'banking.transaction.wizard'
|
||||
_description = 'Match transaction'
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
"""
|
||||
Make sure that the statement line has an import transaction
|
||||
"""
|
||||
res = super(banking_transaction_wizard, self).create(
|
||||
cr, uid, vals, context=context)
|
||||
if res and vals.get('statement_line_id'):
|
||||
line_pool = self.pool.get('account.bank.statement.line')
|
||||
line_pool.create_instant_transaction(
|
||||
cr, uid, vals['statement_line_id'], context=context)
|
||||
return res
|
||||
|
||||
def create_act_window(self, cr, uid, ids, nodestroy=True, context=None):
|
||||
"""
|
||||
Return a popup window for this model
|
||||
"""
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
return {
|
||||
'name': self._description,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': self._name,
|
||||
'domain': [],
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'res_id': ids[0],
|
||||
'nodestroy': nodestroy,
|
||||
}
|
||||
|
||||
def trigger_match(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Call the automatic matching routine for one or
|
||||
more bank transactions
|
||||
"""
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
import_transaction_obj = self.pool.get('banking.import.transaction')
|
||||
trans_id = self.read(
|
||||
cr, uid, ids[0], ['import_transaction_id'],
|
||||
context=context)['import_transaction_id'][0] # many2one tuple
|
||||
import_transaction_obj.match(cr, uid, [trans_id], context=context)
|
||||
return self.create_act_window(cr, uid, ids, context=None)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
"""
|
||||
Implement a trigger to retrieve the corresponding move line
|
||||
when the invoice_id changes
|
||||
"""
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
transaction_obj = self.pool.get('banking.import.transaction')
|
||||
|
||||
if not vals or not ids:
|
||||
return True
|
||||
|
||||
wiz = self.browse(cr, uid, ids[0], context=context)
|
||||
|
||||
# The following fields get never written
|
||||
# they are just triggers for manual matching
|
||||
# which populates regular fields on the transaction
|
||||
manual_invoice_ids = vals.pop('manual_invoice_ids', [])
|
||||
manual_move_line_ids = vals.pop('manual_move_line_ids', [])
|
||||
|
||||
res = super(banking_transaction_wizard, self).write(
|
||||
cr, uid, ids, vals, context=context)
|
||||
wiz.refresh()
|
||||
|
||||
# Process the logic of the written values
|
||||
|
||||
# An invoice is selected from multiple candidates
|
||||
if vals and 'invoice_id' in vals:
|
||||
if (wiz.import_transaction_id.match_type == 'invoice' and
|
||||
wiz.import_transaction_id.invoice_id):
|
||||
found = False
|
||||
# the current value might apply
|
||||
if (wiz.move_line_id and wiz.move_line_id.invoice and
|
||||
wiz.move_line_id.invoice == wiz.invoice_id):
|
||||
found = True
|
||||
else:
|
||||
# Otherwise, retrieve the move line for this invoice
|
||||
# Given the arity of the relation, there is are always
|
||||
# multiple possibilities but the move lines here are
|
||||
# prefiltered for having account_id.type payable/receivable
|
||||
# and the regular invoice workflow should only come up with
|
||||
# one of those only.
|
||||
for move_line in wiz.import_transaction_id.move_line_ids:
|
||||
if (move_line.invoice ==
|
||||
wiz.import_transaction_id.invoice_id):
|
||||
transaction_obj.write(
|
||||
cr, uid, wiz.import_transaction_id.id,
|
||||
{'move_line_id': move_line.id, },
|
||||
context=context
|
||||
)
|
||||
statement_line_obj.write(
|
||||
cr, uid,
|
||||
wiz.import_transaction_id.statement_line_id.id,
|
||||
{
|
||||
'partner_id': (
|
||||
move_line.partner_id.id or False),
|
||||
'account_id': move_line.account_id.id,
|
||||
}, context=context)
|
||||
found = True
|
||||
break
|
||||
# Cannot match the invoice
|
||||
if not found:
|
||||
orm.except_orm(
|
||||
_("No entry found for the selected invoice"),
|
||||
_("No entry found for the selected invoice. " +
|
||||
"Try manual reconciliation."))
|
||||
|
||||
if manual_move_line_ids or manual_invoice_ids:
|
||||
move_line_obj = self.pool.get('account.move.line')
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
# Rewrite *2many directive notation
|
||||
if manual_invoice_ids:
|
||||
manual_invoice_ids = (
|
||||
[i[1] for i in manual_invoice_ids if i[0] == 4] +
|
||||
[j for i in manual_invoice_ids if i[0] == 6 for j in i[2]])
|
||||
if manual_move_line_ids:
|
||||
manual_move_line_ids = (
|
||||
[i[1] for i in manual_move_line_ids if i[0] == 4] +
|
||||
[j for i in manual_move_line_ids
|
||||
if i[0] == 6 for j in i[2]])
|
||||
for wiz in self.browse(cr, uid, ids, context=context):
|
||||
# write can be called multiple times for the same values
|
||||
# that doesn't hurt above, but it does here
|
||||
if wiz.match_type and (
|
||||
len(manual_move_line_ids) > 1 or
|
||||
len(manual_invoice_ids) > 1):
|
||||
continue
|
||||
|
||||
todo = []
|
||||
|
||||
for invoice in invoice_obj.browse(
|
||||
cr, uid, manual_invoice_ids, context=context):
|
||||
found_move_line = False
|
||||
if invoice.move_id:
|
||||
for line in invoice.move_id.line_id:
|
||||
if line.account_id.type in ('receivable',
|
||||
'payable'):
|
||||
todo.append((invoice.id, line.id))
|
||||
found_move_line = True
|
||||
break
|
||||
if not found_move_line:
|
||||
raise orm.except_orm(
|
||||
_("Cannot select for reconcilion"),
|
||||
_("No entry found for the selected invoice. "))
|
||||
for move_line_id in manual_move_line_ids:
|
||||
todo_entry = [False, move_line_id]
|
||||
move_line = move_line_obj.read(
|
||||
cr,
|
||||
uid,
|
||||
move_line_id,
|
||||
['invoice'],
|
||||
context=context
|
||||
)
|
||||
if move_line['invoice']:
|
||||
todo_entry[0] = move_line['invoice'][0]
|
||||
todo.append(todo_entry)
|
||||
|
||||
while todo:
|
||||
todo_entry = todo.pop()
|
||||
move_line = move_line_obj.browse(
|
||||
cr, uid, todo_entry[1], context)
|
||||
transaction_id = wiz.import_transaction_id.id
|
||||
statement_line_id = wiz.statement_line_id.id
|
||||
|
||||
if len(todo) > 0:
|
||||
statement_line_id = wiz.statement_line_id.split_off(
|
||||
move_line.debit or -move_line.credit)[0]
|
||||
transaction_id = statement_line_obj.browse(
|
||||
cr,
|
||||
uid,
|
||||
statement_line_id,
|
||||
context=context
|
||||
).import_transaction_id.id
|
||||
|
||||
vals = {
|
||||
'move_line_id': todo_entry[1],
|
||||
'move_line_ids': [(6, 0, [todo_entry[1]])],
|
||||
'invoice_id': todo_entry[0],
|
||||
'invoice_ids': [
|
||||
(6, 0, [todo_entry[0]] if todo_entry[0] else [])
|
||||
],
|
||||
'match_type': 'manual',
|
||||
}
|
||||
|
||||
transaction_obj.clear_and_write(
|
||||
cr, uid, transaction_id, vals, context=context)
|
||||
|
||||
st_line_vals = {
|
||||
'account_id': move_line_obj.read(
|
||||
cr, uid, todo_entry[1],
|
||||
['account_id'], context=context)['account_id'][0],
|
||||
}
|
||||
|
||||
if todo_entry[0]:
|
||||
st_line_vals['partner_id'] = invoice_obj.browse(
|
||||
cr, uid, todo_entry[0], context=context
|
||||
).partner_id.commercial_partner_id.id
|
||||
|
||||
statement_line_obj.write(
|
||||
cr, uid, statement_line_id,
|
||||
st_line_vals, context=context)
|
||||
return res
|
||||
|
||||
def trigger_write(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Just a button that triggers a write.
|
||||
"""
|
||||
return self.create_act_window(cr, uid, ids, context=None)
|
||||
|
||||
def disable_match(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Clear manual and automatic match information
|
||||
"""
|
||||
settings_pool = self.pool.get('account.banking.account.settings')
|
||||
statement_pool = self.pool.get('account.bank.statement.line')
|
||||
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
||||
for wiz in self.browse(cr, uid, ids, context=context):
|
||||
# Get the bank account setting record, to reset the account
|
||||
account_id = False
|
||||
journal_id = wiz.statement_line_id.statement_id.journal_id.id
|
||||
setting_ids = settings_pool.find(
|
||||
cr, uid, journal_id, context=context
|
||||
)
|
||||
|
||||
# Restore partner id from the bank account or else reset
|
||||
partner_id = False
|
||||
if (wiz.statement_line_id.partner_bank_id and
|
||||
wiz.statement_line_id.partner_bank_id.partner_id):
|
||||
partner_id = (
|
||||
wiz.statement_line_id.partner_bank_id.partner_id.id
|
||||
)
|
||||
wiz.write({'partner_id': partner_id})
|
||||
|
||||
bank_partner = False
|
||||
if partner_id:
|
||||
bank_partner = wiz.statement_line_id.partner_bank_id.partner_id
|
||||
if wiz.amount < 0:
|
||||
if bank_partner:
|
||||
account_id = bank_partner.\
|
||||
def_journal_account_bank_decr()[bank_partner.id]
|
||||
elif setting_ids:
|
||||
account_id = settings_pool.browse(
|
||||
cr, uid, setting_ids[0],
|
||||
context=context).default_credit_account_id.id
|
||||
else:
|
||||
if bank_partner:
|
||||
account_id = bank_partner.\
|
||||
def_journal_account_bank_incr()[bank_partner.id]
|
||||
elif setting_ids:
|
||||
account_id = settings_pool.browse(
|
||||
cr, uid, setting_ids[0],
|
||||
context=context).default_debit_account_id.id
|
||||
|
||||
if account_id:
|
||||
wiz.statement_line_id.write({'account_id': account_id})
|
||||
|
||||
if wiz.statement_line_id:
|
||||
# delete splits causing an unsplit if this is a split
|
||||
# transaction
|
||||
statement_pool.unlink(
|
||||
cr,
|
||||
uid,
|
||||
statement_pool.search(
|
||||
cr, uid,
|
||||
[('parent_id', '=', wiz.statement_line_id.id)],
|
||||
context=context
|
||||
),
|
||||
context=context
|
||||
)
|
||||
|
||||
if wiz.import_transaction_id:
|
||||
wiz.import_transaction_id.clear_and_write()
|
||||
|
||||
return self.create_act_window(cr, uid, ids, context=None)
|
||||
|
||||
def reverse_duplicate(self, cr, uid, ids, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
transaction_obj = self.pool.get('banking.import.transaction')
|
||||
for wiz in self.read(
|
||||
cr, uid, ids, ['duplicate', 'import_transaction_id'],
|
||||
context=context):
|
||||
transaction_obj.write(
|
||||
cr, uid, wiz['import_transaction_id'][0],
|
||||
{'duplicate': not wiz['duplicate']}, context=context)
|
||||
return self.create_act_window(cr, uid, ids, context=None)
|
||||
|
||||
def button_done(self, cr, uid, ids, context=None):
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64),
|
||||
'statement_line_id': fields.many2one(
|
||||
'account.bank.statement.line', 'Statement line',
|
||||
),
|
||||
'amount': fields.related(
|
||||
'statement_line_id', 'amount', type='float',
|
||||
string="Amount", readonly=True),
|
||||
'date': fields.related(
|
||||
'statement_line_id', 'date', type='date',
|
||||
string="Date", readonly=True),
|
||||
'ref': fields.related(
|
||||
'statement_line_id', 'ref', type='char', size=32,
|
||||
string="Reference", readonly=True),
|
||||
'message': fields.related(
|
||||
'statement_line_id', 'import_transaction_id', 'message',
|
||||
type='char', size=1024,
|
||||
string="Message", readonly=True),
|
||||
'partner_id': fields.related(
|
||||
'statement_line_id', 'partner_id',
|
||||
type='many2one', relation='res.partner',
|
||||
string="Partner", readonly=True),
|
||||
'statement_line_parent_id': fields.related(
|
||||
'statement_line_id', 'parent_id', type='many2one',
|
||||
relation='account.bank.statement.line', readonly=True),
|
||||
'import_transaction_id': fields.related(
|
||||
'statement_line_id', 'import_transaction_id',
|
||||
string="Import transaction",
|
||||
type='many2one', relation='banking.import.transaction'),
|
||||
'residual': fields.related(
|
||||
'import_transaction_id', 'residual', type='float',
|
||||
string='Residual', readonly=True),
|
||||
'writeoff_account_id': fields.related(
|
||||
'import_transaction_id', 'writeoff_account_id',
|
||||
type='many2one', relation='account.account',
|
||||
string='Write-off account'),
|
||||
'invoice_ids': fields.related(
|
||||
'import_transaction_id', 'invoice_ids', string="Matching invoices",
|
||||
type='many2many', relation='account.invoice'),
|
||||
'invoice_id': fields.related(
|
||||
'import_transaction_id',
|
||||
'invoice_id',
|
||||
string="Invoice to reconcile",
|
||||
type='many2one',
|
||||
relation='account.invoice',
|
||||
),
|
||||
'move_line_ids': fields.related(
|
||||
'import_transaction_id', 'move_line_ids', string="Entry lines",
|
||||
type='many2many', relation='account.move.line'),
|
||||
'move_line_id': fields.related(
|
||||
'import_transaction_id', 'move_line_id', string="Entry line",
|
||||
type='many2one', relation='account.move.line'),
|
||||
'duplicate': fields.related(
|
||||
'import_transaction_id',
|
||||
'duplicate',
|
||||
string='Flagged as duplicate',
|
||||
type='boolean',
|
||||
),
|
||||
'match_multi': fields.related(
|
||||
'import_transaction_id', 'match_multi',
|
||||
type="boolean", string='Multiple matches'),
|
||||
'match_type': fields.related(
|
||||
'import_transaction_id',
|
||||
'match_type',
|
||||
type='selection',
|
||||
selection=[
|
||||
('move', 'Move'),
|
||||
('invoice', 'Invoice'),
|
||||
('payment', 'Payment line'),
|
||||
('payment_order', 'Payment order'),
|
||||
('storno', 'Storno'),
|
||||
('manual', 'Manual'),
|
||||
('payment_manual', 'Payment line (manual)'),
|
||||
('payment_order_manual', 'Payment order (manual)'),
|
||||
],
|
||||
string='Match type',
|
||||
readonly=True,
|
||||
),
|
||||
'manual_invoice_ids': fields.many2many(
|
||||
'account.invoice',
|
||||
'banking_transaction_wizard_account_invoice_rel',
|
||||
'wizard_id', 'invoice_id', string='Match one or more invoices',
|
||||
domain=[('reconciled', '=', False)]),
|
||||
'manual_move_line_ids': fields.many2many(
|
||||
'account.move.line',
|
||||
'banking_transaction_wizard_account_move_line_rel',
|
||||
'wizard_id', 'move_line_id', string='Or match one or more entries',
|
||||
domain=[('account_id.reconcile', '=', True),
|
||||
('reconcile_id', '=', False)]),
|
||||
'payment_option': fields.related(
|
||||
'import_transaction_id',
|
||||
'payment_option',
|
||||
string='Payment Difference',
|
||||
type='selection',
|
||||
required=True,
|
||||
selection=[
|
||||
('without_writeoff', 'Keep Open'),
|
||||
('with_writeoff', 'Reconcile Payment Balance')
|
||||
],
|
||||
),
|
||||
'writeoff_analytic_id': fields.related(
|
||||
'import_transaction_id', 'writeoff_analytic_id',
|
||||
type='many2one', relation='account.analytic.account',
|
||||
string='Write-off analytic account'),
|
||||
'analytic_account_id': fields.related(
|
||||
'statement_line_id', 'analytic_account_id',
|
||||
type='many2one', relation='account.analytic.account',
|
||||
string="Analytic Account"),
|
||||
'move_currency_amount': fields.related(
|
||||
'import_transaction_id',
|
||||
'move_currency_amount',
|
||||
type='float',
|
||||
string='Match Currency Amount',
|
||||
readonly=True,
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="transaction_wizard_first">
|
||||
<field name="name">transaction.wizard.first</field>
|
||||
<field name="model">banking.transaction.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Match transaction" version="7.0">
|
||||
<!-- fields used for form logic -->
|
||||
<field name="statement_line_parent_id" invisible="True"/>
|
||||
<field name="invoice_ids" invisible="True"/>
|
||||
<field name="move_line_ids" invisible="True"/>
|
||||
<field name="match_multi" invisible="True"/>
|
||||
<field name="duplicate" invisible="True"/>
|
||||
<group colspan="2" col="2">
|
||||
<group colspan="2" col="4">
|
||||
<separator string="Transaction data" colspan="4"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="date"/>
|
||||
<field name="amount"/>
|
||||
<field name="ref"/>
|
||||
<field name="message" colspan="4"/>
|
||||
</group>
|
||||
|
||||
<!-- (semi-) automatic matching and selection -->
|
||||
|
||||
<group colspan="2" col="4">
|
||||
|
||||
<separator string="Current match" colspan="4"/>
|
||||
<field name="match_type"/>
|
||||
<newline />
|
||||
<field name="move_currency_amount" />
|
||||
<newline />
|
||||
<field name="residual"/>
|
||||
<group attrs="{'invisible': [('match_multi', '=', False)]}" colspan="4" col="2">
|
||||
<separator string="Multiple matches" colspan="2"/>
|
||||
<label colspan="2" string="Multiple matches were found for this bank transfer. You must pick one of the matches or select a match manually below." />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<newline/>
|
||||
<!-- show if we have an invoice type match (but the user may need to select from multiple options)
|
||||
or whenever there is an invoice_id (e.g. in case of a manual match)
|
||||
-->
|
||||
<field name='invoice_id'
|
||||
attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'invoice'),('invoice_id', '=', False)]}" colspan="2"
|
||||
domain="[('id', 'in', invoice_ids[0][2])]"
|
||||
/>
|
||||
<!-- show if we have a move type match or a manual match without an invoice_id
|
||||
-->
|
||||
<field name='move_line_id'
|
||||
attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'move'),('invoice_id', '=', False)]}" colspan="2"
|
||||
domain="[('id', 'in', move_line_ids[0][2])]"
|
||||
/>
|
||||
<newline/>
|
||||
<field colspan="2" name='analytic_account_id' />
|
||||
<button colspan="1"
|
||||
name="trigger_write"
|
||||
type="object"
|
||||
attrs="{'invisible': [('match_multi', '=', False)]}"
|
||||
string="Select"/>
|
||||
<newline/>
|
||||
|
||||
<!-- residual and write off -->
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<!-- Duplicate flagging -->
|
||||
<page string="Duplicate" attrs="{'invisible': [('duplicate', '=', False)]}">
|
||||
<group colspan="2" col="2">
|
||||
<label colspan="2" string="This bank transfer was marked as a duplicate. You can either confirm that this is not the case, or remove the bank transfer from the system."/>
|
||||
<newline/>
|
||||
<button colspan="1"
|
||||
name="reverse_duplicate"
|
||||
type="object"
|
||||
string="Remove duplicate flag"/>
|
||||
</group>
|
||||
</page>
|
||||
<!-- Redo automatic match -->
|
||||
<page string="Match again">
|
||||
<label string="You can let the system try to match this bank statement line again after you have made any changes in the database (for instance, add an invoice or a bank account)." colspan="2"/>
|
||||
<newline/>
|
||||
<button colspan="1"
|
||||
name="trigger_match"
|
||||
type="object"
|
||||
string="Match again"/>
|
||||
</page>
|
||||
<!-- Manual selection -->
|
||||
<page string="Manual match">
|
||||
<separator string="Match one or more invoices" colspan="4"/>
|
||||
<field name="manual_invoice_ids" colspan="4"
|
||||
context="{'search_default_partner_id': partner_id}"
|
||||
/>
|
||||
<separator string="Or match one or more entries" colspan="4"/>
|
||||
<field name="manual_move_line_ids" colspan="4"
|
||||
context="{'search_default_partner_id': partner_id}"
|
||||
/>
|
||||
<button name="trigger_write"
|
||||
type="object"
|
||||
string="Match" />
|
||||
</page>
|
||||
<page string="Write-Off" attrs="{'invisible': [('match_type', '=', False)]}">
|
||||
<group colspan="2" col="2">
|
||||
<label string="Choose what you want to do with the eventual difference between the paid amount and the sum of allocated amounts. You can either choose to keep open this difference on the partner's account, or reconcile it with the payment." colspan="2"/>
|
||||
<field name="payment_option" />
|
||||
<field name="writeoff_account_id" attrs="{'required':[('payment_option','=','with_writeoff')],'invisible':[('payment_option','=','without_writeoff')]}" />
|
||||
<field name="writeoff_analytic_id"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
attrs="{'invisible':[('payment_option','=','without_writeoff')]}" />
|
||||
<button colspan="1"
|
||||
name="trigger_write"
|
||||
type="object"
|
||||
string="Set write-off account"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Disable reconciliation" attrs="{'invisible': [('match_type', '==', False)]}">
|
||||
<group colspan="2" col="2">
|
||||
<label string="You can disable the reconciliation of this bank transfer" colspan="2"/>
|
||||
<newline/>
|
||||
<button colspan="1"
|
||||
name="disable_match"
|
||||
type="object"
|
||||
string="Disable reconciliation"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<footer>
|
||||
<button icon="gtk-ok" string="Close" special="cancel"/>
|
||||
</footer>
|
||||
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
338
__unported__/account_banking/wizard/banktools.py
Normal file
338
__unported__/account_banking/wizard/banktools.py
Normal file
@@ -0,0 +1,338 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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 openerp.tools.translate import _
|
||||
from openerp.addons.account_banking import sepa
|
||||
from openerp.addons.account_banking.struct import struct
|
||||
|
||||
__all__ = [
|
||||
'get_period',
|
||||
'get_bank_accounts',
|
||||
'get_partner',
|
||||
'get_country_id',
|
||||
'get_company_bank_account',
|
||||
'create_bank_account',
|
||||
]
|
||||
|
||||
|
||||
def get_period(pool, cr, uid, date, company, log=None):
|
||||
'''
|
||||
Wrapper over account_period.find() to log exceptions of
|
||||
missing periods instead of raising.
|
||||
'''
|
||||
context = {'account_period_prefer_normal': True}
|
||||
if company:
|
||||
context['company_id'] = company.id
|
||||
try:
|
||||
period_ids = pool.get('account.period').find(
|
||||
cr, uid, dt=date, context=context)
|
||||
except Exception as e:
|
||||
if log is None:
|
||||
raise
|
||||
else:
|
||||
log.append(e)
|
||||
return False
|
||||
return period_ids[0]
|
||||
|
||||
|
||||
def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
|
||||
'''
|
||||
Get the bank account with account number account_number
|
||||
'''
|
||||
# No need to search for nothing
|
||||
if not account_number:
|
||||
return []
|
||||
|
||||
partner_bank_obj = pool.get('res.partner.bank')
|
||||
bank_account_ids = partner_bank_obj.search(cr, uid, [
|
||||
('acc_number', '=', account_number)
|
||||
])
|
||||
if not bank_account_ids:
|
||||
if not fail:
|
||||
log.append(
|
||||
_('Bank account %(account_no)s was not found in the database')
|
||||
% dict(account_no=account_number)
|
||||
)
|
||||
return []
|
||||
return partner_bank_obj.browse(cr, uid, bank_account_ids)
|
||||
|
||||
|
||||
def _has_attr(obj, attr):
|
||||
# Needed for dangling addresses and a weird exception scheme in
|
||||
# OpenERP's orm.
|
||||
try:
|
||||
return bool(getattr(obj, attr))
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
def get_partner(pool, cr, uid, name, address, postal_code, city,
|
||||
country_id, log, context=None):
|
||||
'''
|
||||
Get the partner belonging to the account holders name <name>
|
||||
|
||||
If multiple partners are found with the same name, select the first and
|
||||
add a warning to the import log.
|
||||
|
||||
TODO: revive the search by lines from the address argument
|
||||
'''
|
||||
partner_obj = pool.get('res.partner')
|
||||
partner_ids = partner_obj.search(
|
||||
cr, uid, [
|
||||
'|', ('is_company', '=', True), ('parent_id', '=', False),
|
||||
('name', 'ilike', name),
|
||||
], context=context)
|
||||
if not partner_ids:
|
||||
# Try brute search on address and then match reverse
|
||||
criteria = []
|
||||
if country_id:
|
||||
criteria.append(('country_id', '=', country_id))
|
||||
if city:
|
||||
criteria.append(('city', 'ilike', city))
|
||||
if postal_code:
|
||||
criteria.append(('zip', 'ilike', postal_code))
|
||||
partner_search_ids = partner_obj.search(
|
||||
cr, uid, criteria, context=context)
|
||||
if (not partner_search_ids and country_id):
|
||||
# Try again with country_id = False
|
||||
criteria[0] = ('country_id', '=', False)
|
||||
partner_search_ids = partner_obj.search(
|
||||
cr, uid, criteria, context=context)
|
||||
key = name.lower()
|
||||
partners = []
|
||||
for partner in partner_obj.read(
|
||||
cr, uid, partner_search_ids, ['name', 'commercial_partner_id'],
|
||||
context=context):
|
||||
if (len(partner['name']) > 3 and partner['name'].lower() in key):
|
||||
partners.append(partner)
|
||||
partners.sort(key=lambda x: len(x['name']), reverse=True)
|
||||
partner_ids = [x['commercial_partner_id'][0] for x in partners]
|
||||
if len(partner_ids) > 1:
|
||||
log.append(
|
||||
_('More than one possible match found for partner with '
|
||||
'name %(name)s') % {'name': name})
|
||||
return partner_ids and partner_ids[0] or False
|
||||
|
||||
|
||||
def get_company_bank_account(pool, cr, uid, account_number, currency,
|
||||
company, log):
|
||||
'''
|
||||
Get the matching bank account for this company. Currency is the ISO code
|
||||
for the requested currency.
|
||||
'''
|
||||
results = struct()
|
||||
bank_accounts = get_bank_accounts(pool, cr, uid, account_number, log,
|
||||
fail=True)
|
||||
if not bank_accounts:
|
||||
return False
|
||||
elif len(bank_accounts) != 1:
|
||||
log.append(
|
||||
_('More than one bank account was found with the same number '
|
||||
'%(account_no)s') % dict(account_no=account_number)
|
||||
)
|
||||
return False
|
||||
if bank_accounts[0].partner_id.id != company.partner_id.id:
|
||||
log.append(
|
||||
_('Account %(account_no)s is not owned by %(partner)s')
|
||||
% dict(account_no=account_number,
|
||||
partner=company.partner_id.name,
|
||||
))
|
||||
return False
|
||||
results.account = bank_accounts[0]
|
||||
bank_settings_obj = pool.get('account.banking.account.settings')
|
||||
criteria = [('partner_bank_id', '=', bank_accounts[0].id)]
|
||||
|
||||
# Find matching journal for currency
|
||||
journal_obj = pool.get('account.journal')
|
||||
journal_ids = journal_obj.search(cr, uid, [
|
||||
('type', '=', 'bank'),
|
||||
('currency.name', '=', currency or company.currency_id.name)
|
||||
])
|
||||
if currency == company.currency_id.name:
|
||||
journal_ids_no_curr = journal_obj.search(cr, uid, [
|
||||
('type', '=', 'bank'), ('currency', '=', False)
|
||||
])
|
||||
journal_ids.extend(journal_ids_no_curr)
|
||||
if journal_ids:
|
||||
criteria.append(('journal_id', 'in', journal_ids))
|
||||
|
||||
# Find bank account settings
|
||||
bank_settings_ids = bank_settings_obj.search(cr, uid, criteria)
|
||||
if bank_settings_ids:
|
||||
settings = bank_settings_obj.browse(cr, uid, bank_settings_ids)[0]
|
||||
results.company_id = company
|
||||
results.journal_id = settings.journal_id
|
||||
|
||||
# Take currency from settings or from company
|
||||
if settings.journal_id.currency.id:
|
||||
results.currency_id = settings.journal_id.currency
|
||||
else:
|
||||
results.currency_id = company.currency_id
|
||||
# Rest just copy/paste from settings. Why am I doing this?
|
||||
results.default_debit_account_id = settings.default_debit_account_id
|
||||
results.default_credit_account_id = settings.default_credit_account_id
|
||||
results.costs_account_id = settings.costs_account_id
|
||||
results.invoice_journal_id = settings.invoice_journal_id
|
||||
results.bank_partner_id = settings.bank_partner_id
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
|
||||
name=None, context=None):
|
||||
'''
|
||||
Find or create the bank with the provided BIC code.
|
||||
When online, the SWIFT database will be consulted in order to
|
||||
provide for missing information.
|
||||
'''
|
||||
# UPDATE: Free SWIFT databases are since 2/22/2010 hidden behind an
|
||||
# image challenge/response interface.
|
||||
|
||||
bank_obj = pool.get('res.bank')
|
||||
|
||||
# Self generated key?
|
||||
if len(bic) < 8:
|
||||
# search key
|
||||
bank_ids = bank_obj.search(
|
||||
cr, uid, [
|
||||
('bic', '=', bic[:6])
|
||||
])
|
||||
if not bank_ids:
|
||||
bank_ids = bank_obj.search(
|
||||
cr, uid, [
|
||||
('bic', 'ilike', bic + '%')
|
||||
])
|
||||
else:
|
||||
bank_ids = bank_obj.search(
|
||||
cr, uid, [
|
||||
('bic', '=', bic)
|
||||
])
|
||||
|
||||
if bank_ids and len(bank_ids) == 1:
|
||||
banks = bank_obj.browse(cr, uid, bank_ids)
|
||||
return banks[0].id, banks[0].country.id
|
||||
|
||||
country_obj = pool.get('res.country')
|
||||
country_ids = country_obj.search(
|
||||
cr, uid, [('code', '=', bic[4:6])]
|
||||
)
|
||||
country_id = country_ids and country_ids[0] or False
|
||||
bank_id = False
|
||||
|
||||
if online:
|
||||
info, address = bank_obj.online_bank_info(
|
||||
cr, uid, bic, context=context
|
||||
)
|
||||
if info:
|
||||
bank_id = bank_obj.create(cr, uid, dict(
|
||||
code=info.code,
|
||||
name=info.name,
|
||||
street=address.street,
|
||||
street2=address.street2,
|
||||
zip=address.zip,
|
||||
city=address.city,
|
||||
country=country_id,
|
||||
bic=info.bic[:8],
|
||||
))
|
||||
else:
|
||||
info = struct(name=name, code=code)
|
||||
|
||||
if not online or not bank_id:
|
||||
bank_id = bank_obj.create(cr, uid, dict(
|
||||
code=info.code or 'UNKNOW', # FIXME: Typo?
|
||||
name=info.name or _('Unknown Bank'),
|
||||
country=country_id,
|
||||
bic=bic,
|
||||
))
|
||||
return bank_id, country_id
|
||||
|
||||
|
||||
def get_country_id(pool, cr, uid, transaction, context=None):
|
||||
"""
|
||||
Derive a country id from the info on the transaction.
|
||||
|
||||
:param transaction: browse record of a transaction
|
||||
:returns: res.country id or False
|
||||
"""
|
||||
|
||||
country_code = False
|
||||
iban = sepa.IBAN(transaction.remote_account)
|
||||
if iban.valid:
|
||||
country_code = iban.countrycode
|
||||
elif transaction.remote_owner_country_code:
|
||||
country_code = transaction.remote_owner_country_code
|
||||
# fallback on the import parsers country code
|
||||
elif transaction.bank_country_code:
|
||||
country_code = transaction.bank_country_code
|
||||
if country_code:
|
||||
country_ids = pool.get('res.country').search(
|
||||
cr, uid, [('code', '=', country_code.upper())],
|
||||
context=context)
|
||||
country_id = country_ids and country_ids[0] or False
|
||||
if not country_id:
|
||||
company = transaction.statement_line_id.company_id
|
||||
if company.partner_id.country:
|
||||
country_id = company.partner_id.country.id
|
||||
return country_id
|
||||
|
||||
|
||||
def create_bank_account(pool, cr, uid, partner_id,
|
||||
account_number, holder_name, address, city,
|
||||
country_id, bic=False,
|
||||
context=None):
|
||||
'''
|
||||
Create a matching bank account with this holder for this partner.
|
||||
'''
|
||||
values = struct(
|
||||
partner_id=partner_id,
|
||||
owner_name=holder_name,
|
||||
country_id=country_id,
|
||||
)
|
||||
|
||||
# Are we dealing with IBAN?
|
||||
iban = sepa.IBAN(account_number)
|
||||
if iban.valid:
|
||||
# Take as much info as possible from IBAN
|
||||
values.state = 'iban'
|
||||
values.acc_number = str(iban)
|
||||
else:
|
||||
# No, try to convert to IBAN
|
||||
values.state = 'bank'
|
||||
values.acc_number = account_number
|
||||
|
||||
if country_id:
|
||||
country_code = pool.get('res.country').read(
|
||||
cr, uid, country_id, ['code'], context=context)['code']
|
||||
if country_code in sepa.IBAN.countries:
|
||||
account_info = pool['res.partner.bank'].online_account_info(
|
||||
cr, uid, country_code, values.acc_number, context=context)
|
||||
if account_info:
|
||||
values.acc_number = iban = account_info.iban
|
||||
values.state = 'iban'
|
||||
bic = account_info.bic
|
||||
|
||||
if bic:
|
||||
values.bank = get_or_create_bank(pool, cr, uid, bic)[0]
|
||||
values.bank_bic = bic
|
||||
|
||||
# Create bank account and return
|
||||
return pool.get('res.partner.bank').create(
|
||||
cr, uid, values, context=context)
|
||||
208
__unported__/account_banking/wizard/link_partner.py
Normal file
208
__unported__/account_banking/wizard/link_partner.py
Normal file
@@ -0,0 +1,208 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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.osv import orm, fields
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.account_banking.wizard import banktools
|
||||
import ast
|
||||
|
||||
|
||||
class link_partner(orm.TransientModel):
|
||||
_name = 'banking.link_partner'
|
||||
_description = 'Link partner'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char(
|
||||
'Create partner with name', size=128, required=True),
|
||||
'supplier': fields.boolean('Supplier'),
|
||||
'customer': fields.boolean('Customer'),
|
||||
'partner_id': fields.many2one(
|
||||
'res.partner', 'or link existing partner',
|
||||
domain=['|', ('is_company', '=', True),
|
||||
('parent_id', '=', False)],
|
||||
),
|
||||
'statement_line_id': fields.many2one(
|
||||
'account.bank.statement.line',
|
||||
'Statement line', required=True),
|
||||
'amount': fields.related(
|
||||
'statement_line_id', 'amount', type='float',
|
||||
string="Amount", readonly=True),
|
||||
'ref': fields.related(
|
||||
'statement_line_id', 'ref', type='char', size=32,
|
||||
string="Reference", readonly=True),
|
||||
'message': fields.related(
|
||||
'statement_line_id', 'import_transaction_id', 'message',
|
||||
type='char', size=1024,
|
||||
string="Message", readonly=True),
|
||||
'remote_account': fields.char(
|
||||
'Account number', size=24, readonly=True),
|
||||
# Partner values
|
||||
'street': fields.char('Street', size=128),
|
||||
'street2': fields.char('Street2', size=128),
|
||||
'zip': fields.char('Zip', change_default=True, size=24),
|
||||
'city': fields.char('City', size=128),
|
||||
'state_id': fields.many2one("res.country.state", 'State'),
|
||||
'country_id': fields.many2one('res.country', 'Country'),
|
||||
'email': fields.char('Email', size=240),
|
||||
'phone': fields.char('Phone', size=64),
|
||||
'fax': fields.char('Fax', size=64),
|
||||
'mobile': fields.char('Mobile', size=64),
|
||||
'is_company': fields.boolean('Is a Company'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'is_company': True,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
"""
|
||||
Get default values from the transaction data
|
||||
on the statement line
|
||||
"""
|
||||
if vals and vals.get('statement_line_id'):
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
statement_line = statement_line_obj.browse(
|
||||
cr, uid, vals['statement_line_id'], context=context)
|
||||
transaction = statement_line.import_transaction_id
|
||||
|
||||
if statement_line.partner_bank_id:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('Statement line is already linked to a bank account '))
|
||||
|
||||
if not(transaction
|
||||
and transaction.remote_account):
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('No transaction data on statement line'))
|
||||
|
||||
if 'supplier' not in vals and statement_line.amount < 0:
|
||||
vals['supplier'] = True
|
||||
if 'customer' not in vals and statement_line.amount > 0:
|
||||
vals['customer'] = True
|
||||
|
||||
address_list = []
|
||||
try:
|
||||
address_list = ast.literal_eval(
|
||||
transaction.remote_owner_address or [])
|
||||
except ValueError:
|
||||
pass
|
||||
if address_list and not vals.get('street'):
|
||||
vals['street'] = address_list.pop(0)
|
||||
if address_list and not vals.get('street2'):
|
||||
vals['street2'] = address_list.pop(0)
|
||||
if transaction.remote_owner_postalcode and not vals.get('zip'):
|
||||
vals['zip'] = transaction.remote_owner_postalcode
|
||||
if transaction.remote_owner_city and not vals.get('city'):
|
||||
vals['city'] = transaction.remote_owner_city
|
||||
if not vals.get('country_id'):
|
||||
vals['country_id'] = banktools.get_country_id(
|
||||
self.pool, cr, uid, transaction, context=context)
|
||||
if not vals.get('name'):
|
||||
vals['name'] = transaction.remote_owner
|
||||
if not vals['name']:
|
||||
vals['name'] = '/'
|
||||
if not vals.get('remote_account'):
|
||||
vals['remote_account'] = transaction.remote_account
|
||||
|
||||
return super(link_partner, self).create(
|
||||
cr, uid, vals, context=context)
|
||||
|
||||
def update_partner_values(self, cr, uid, wizard, values, context=None):
|
||||
"""
|
||||
Updates the new partner values with the values from the wizard
|
||||
|
||||
:param wizard: read record of wizard (with load='_classic_write')
|
||||
:param values: the dictionary of partner values that will be updated
|
||||
"""
|
||||
for field in ['is_company',
|
||||
'name',
|
||||
'street',
|
||||
'street2',
|
||||
'zip',
|
||||
'city',
|
||||
'country_id',
|
||||
'state_id',
|
||||
'phone',
|
||||
'fax',
|
||||
'mobile',
|
||||
'email'
|
||||
]:
|
||||
if wizard[field]:
|
||||
values[field] = wizard[field]
|
||||
return True
|
||||
|
||||
def link_partner(self, cr, uid, ids, context=None):
|
||||
statement_line_obj = self.pool.get(
|
||||
'account.bank.statement.line')
|
||||
wiz = self.browse(cr, uid, ids[0], context=context)
|
||||
|
||||
if wiz.partner_id:
|
||||
partner_id = wiz.partner_id.id
|
||||
else:
|
||||
wiz_read = self.read(
|
||||
cr, uid, ids[0], context=context, load='_classic_write')
|
||||
partner_vals = {
|
||||
'type': 'default',
|
||||
}
|
||||
self.update_partner_values(
|
||||
cr, uid, wiz_read, partner_vals, context=context)
|
||||
partner_id = self.pool.get('res.partner').create(
|
||||
cr, uid, partner_vals, context=context)
|
||||
|
||||
partner_bank_id = banktools.create_bank_account(
|
||||
self.pool, cr, uid, partner_id,
|
||||
wiz.remote_account, wiz.name,
|
||||
wiz.street, wiz.city,
|
||||
wiz.country_id and wiz.country_id.id or False,
|
||||
bic=wiz.statement_line_id.import_transaction_id.remote_bank_bic,
|
||||
context=context)
|
||||
|
||||
statement_line_ids = statement_line_obj.search(
|
||||
cr, uid,
|
||||
[('import_transaction_id.remote_account', '=', wiz.remote_account),
|
||||
('partner_bank_id', '=', False),
|
||||
('state', '=', 'draft')], context=context)
|
||||
statement_line_obj.write(
|
||||
cr, uid, statement_line_ids,
|
||||
{'partner_bank_id': partner_bank_id,
|
||||
'partner_id': partner_id}, context=context)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def create_act_window(self, cr, uid, ids, nodestroy=True, context=None):
|
||||
"""
|
||||
Return a popup window for this model
|
||||
"""
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
return {
|
||||
'name': self._description,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': self._name,
|
||||
'domain': [],
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'res_id': ids[0],
|
||||
'nodestroy': nodestroy,
|
||||
}
|
||||
61
__unported__/account_banking/wizard/link_partner.xml
Normal file
61
__unported__/account_banking/wizard/link_partner.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="link_partner_view">
|
||||
<field name="name">Link partner wizard view</field>
|
||||
<field name="type">form</field>
|
||||
<field name="model">banking.link_partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Link partner" version="7.0" >
|
||||
<group colspan="4" col="6" string="Transaction data">
|
||||
<field name="ref" />
|
||||
<field name="amount" />
|
||||
<field name="remote_account" />
|
||||
<field name="message" colspan="6"/>
|
||||
</group>
|
||||
<group colspan="4" col="4" string="Create or link partner">
|
||||
<field name="name"
|
||||
attrs="{'readonly': [('partner_id', '!=', False)]}" />
|
||||
<field name="partner_id"/>
|
||||
</group>
|
||||
<group colspan="2">
|
||||
<field name="is_company" />
|
||||
</group>
|
||||
<group colspan="4"
|
||||
string="Address"
|
||||
attrs="{'invisible': [('partner_id', '!=', False)]}"
|
||||
col="4">
|
||||
<group colspan="2" col="2">
|
||||
<field name="street"/>
|
||||
<field name="street2"/>
|
||||
<field name="zip"/>
|
||||
<field name="city"/>
|
||||
<field name="country_id"/>
|
||||
<field name="state_id"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<field name="phone"/>
|
||||
<field name="fax"/>
|
||||
<field name="mobile"/>
|
||||
<field name="email" widget="email"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Create partner"
|
||||
name="link_partner" type="object"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('partner_id', '!=', False)]}"
|
||||
/>
|
||||
<button string="Link existing partner"
|
||||
class="oe_highlight"
|
||||
name="link_partner" type="object"
|
||||
attrs="{'invisible': [('partner_id', '==', False)]}"
|
||||
/>
|
||||
or
|
||||
<button class="oe_link" string="Cancel" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
18
__unported__/account_banking/workflow/account_invoice.xml
Normal file
18
__unported__/account_banking/workflow/account_invoice.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!--
|
||||
Transition to reopening the invoice, triggered by
|
||||
cancelling a bank transaction with which the invoice
|
||||
was paid.
|
||||
the existing workflow contains a similar step
|
||||
but without the test on being reconciled
|
||||
-->
|
||||
<record id="paid_to_open" model="workflow.transition">
|
||||
<field name="act_from" ref="account.act_paid"/>
|
||||
<field name="act_to" ref="account.act_open_test"/>
|
||||
<field name="condition">test_undo_paid()</field>
|
||||
<field name="signal">undo_paid</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
1
__unported__/account_banking_camt/__init__.py
Normal file
1
__unported__/account_banking_camt/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
import camt
|
||||
33
__unported__/account_banking_camt/__openerp__.py
Normal file
33
__unported__/account_banking_camt/__openerp__.py
Normal file
@@ -0,0 +1,33 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>)
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'CAMT Format Bank Statements Import',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Therp BV',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Module to import SEPA CAMT.053 Format bank statement files. Based
|
||||
on the Banking addons framework.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
285
__unported__/account_banking_camt/camt.py
Normal file
285
__unported__/account_banking_camt/camt.py
Normal file
@@ -0,0 +1,285 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2013 Therp BV (<http://therp.nl>)
|
||||
# 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 lxml import etree
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.addons.account_banking.parsers import models
|
||||
from openerp.addons.account_banking.parsers.convert import str2date
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
|
||||
def __init__(self, values, *args, **kwargs):
|
||||
super(transaction, self).__init__(*args, **kwargs)
|
||||
for attr in values:
|
||||
setattr(self, attr, values[attr])
|
||||
|
||||
def is_valid(self):
|
||||
return not self.error_message
|
||||
|
||||
|
||||
class parser(models.parser):
|
||||
code = 'CAMT'
|
||||
country_code = 'NL'
|
||||
name = 'Generic CAMT Format'
|
||||
doc = '''\
|
||||
CAMT Format parser
|
||||
'''
|
||||
|
||||
def tag(self, node):
|
||||
"""
|
||||
Return the tag of a node, stripped from its namespace
|
||||
"""
|
||||
return node.tag[len(self.ns):]
|
||||
|
||||
def assert_tag(self, node, expected):
|
||||
"""
|
||||
Get node's stripped tag and compare with expected
|
||||
"""
|
||||
assert self.tag(node) == expected, (
|
||||
"Expected tag '%s', got '%s' instead" %
|
||||
(self.tag(node), expected))
|
||||
|
||||
def xpath(self, node, expr):
|
||||
"""
|
||||
Wrap namespaces argument into call to Element.xpath():
|
||||
|
||||
self.xpath(node, './ns:Acct/ns:Id')
|
||||
"""
|
||||
return node.xpath(expr, namespaces={'ns': self.ns[1:-1]})
|
||||
|
||||
def find(self, node, expr):
|
||||
"""
|
||||
Like xpath(), but return first result if any or else False
|
||||
|
||||
Return None to test nodes for being truesy
|
||||
"""
|
||||
result = node.xpath(expr, namespaces={'ns': self.ns[1:-1]})
|
||||
if result:
|
||||
return result[0]
|
||||
return None
|
||||
|
||||
def get_balance_type_node(self, node, balance_type):
|
||||
"""
|
||||
:param node: BkToCstmrStmt/Stmt/Bal node
|
||||
:param balance type: one of 'OPBD', 'PRCD', 'ITBD', 'CLBD'
|
||||
"""
|
||||
code_expr = ('./ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="%s"]/../../..'
|
||||
% balance_type)
|
||||
return self.xpath(node, code_expr)
|
||||
|
||||
def parse_amount(self, node):
|
||||
"""
|
||||
Parse an element that contains both Amount and CreditDebitIndicator
|
||||
|
||||
:return: signed amount
|
||||
:returntype: float
|
||||
"""
|
||||
sign = -1 if node.find(self.ns + 'CdtDbtInd').text == 'DBIT' else 1
|
||||
return sign * float(node.find(self.ns + 'Amt').text)
|
||||
|
||||
def get_start_balance(self, node):
|
||||
"""
|
||||
Find the (only) balance node with code OpeningBalance, or
|
||||
the only one with code 'PreviousClosingBalance'
|
||||
or the first balance node with code InterimBalance in
|
||||
the case of preceeding pagination.
|
||||
|
||||
:param node: BkToCstmrStmt/Stmt/Bal node
|
||||
"""
|
||||
nodes = (
|
||||
self.get_balance_type_node(node, 'OPBD') or
|
||||
self.get_balance_type_node(node, 'PRCD') or
|
||||
self.get_balance_type_node(node, 'ITBD'))
|
||||
return self.parse_amount(nodes[0])
|
||||
|
||||
def get_end_balance(self, node):
|
||||
"""
|
||||
Find the (only) balance node with code ClosingBalance, or
|
||||
the second (and last) balance node with code InterimBalance in
|
||||
the case of continued pagination.
|
||||
|
||||
:param node: BkToCstmrStmt/Stmt/Bal node
|
||||
"""
|
||||
nodes = (
|
||||
self.get_balance_type_node(node, 'CLBD') or
|
||||
self.get_balance_type_node(node, 'ITBD'))
|
||||
return self.parse_amount(nodes[-1])
|
||||
|
||||
def parse_Stmt(self, cr, node):
|
||||
"""
|
||||
Parse a single Stmt node.
|
||||
|
||||
Be sure to craft a unique, but short enough statement identifier,
|
||||
as it is used as the basis of the generated move lines' names
|
||||
which overflow when using the full IBAN and CAMT statement id.
|
||||
"""
|
||||
statement = models.mem_bank_statement()
|
||||
statement.local_account = (
|
||||
self.xpath(node, './ns:Acct/ns:Id/ns:IBAN')[0].text
|
||||
if self.xpath(node, './ns:Acct/ns:Id/ns:IBAN')
|
||||
else self.xpath(node, './ns:Acct/ns:Id/ns:Othr/ns:Id')[0].text)
|
||||
|
||||
identifier = node.find(self.ns + 'Id').text
|
||||
if identifier.upper().startswith('CAMT053'):
|
||||
identifier = identifier[7:]
|
||||
statement.id = self.get_unique_statement_id(
|
||||
cr, "%s-%s" % (
|
||||
self.get_unique_account_identifier(
|
||||
cr, statement.local_account),
|
||||
identifier)
|
||||
)
|
||||
|
||||
statement.local_currency = self.xpath(node, './ns:Acct/ns:Ccy')[0].text
|
||||
statement.start_balance = self.get_start_balance(node)
|
||||
statement.end_balance = self.get_end_balance(node)
|
||||
number = 0
|
||||
for Ntry in self.xpath(node, './ns:Ntry'):
|
||||
transaction_detail = self.parse_Ntry(Ntry)
|
||||
if number == 0:
|
||||
# Take the statement date from the first transaction
|
||||
statement.date = str2date(
|
||||
transaction_detail['execution_date'], "%Y-%m-%d")
|
||||
number += 1
|
||||
transaction_detail['id'] = str(number).zfill(4)
|
||||
statement.transactions.append(
|
||||
transaction(transaction_detail))
|
||||
return statement
|
||||
|
||||
def get_transfer_type(self, node):
|
||||
"""
|
||||
Map entry descriptions to transfer types. To extend with
|
||||
proper mapping from BkTxCd/Domn/Cd/Fmly/Cd to transfer types
|
||||
if we can get our hands on real life samples.
|
||||
|
||||
For now, leave as a hook for bank specific overrides to map
|
||||
properietary codes from BkTxCd/Prtry/Cd.
|
||||
|
||||
:param node: Ntry node
|
||||
"""
|
||||
return bt.ORDER
|
||||
|
||||
def parse_Ntry(self, node):
|
||||
"""
|
||||
:param node: Ntry node
|
||||
"""
|
||||
entry_details = {
|
||||
'execution_date': self.xpath(node, './ns:BookgDt/ns:Dt')[0].text,
|
||||
'value_date': self.xpath(node, './ns:ValDt/ns:Dt')[0].text,
|
||||
'transfer_type': self.get_transfer_type(node),
|
||||
'transferred_amount': self.parse_amount(node)
|
||||
}
|
||||
TxDtls = self.xpath(node, './ns:NtryDtls/ns:TxDtls')
|
||||
if len(TxDtls) == 1:
|
||||
vals = self.parse_TxDtls(TxDtls[0], entry_details)
|
||||
else:
|
||||
vals = entry_details
|
||||
return vals
|
||||
|
||||
def get_party_values(self, TxDtls):
|
||||
"""
|
||||
Determine to get either the debtor or creditor party node
|
||||
and extract the available data from it
|
||||
"""
|
||||
vals = {}
|
||||
party_type = self.find(
|
||||
TxDtls, '../../ns:CdtDbtInd').text == 'CRDT' and 'Dbtr' or 'Cdtr'
|
||||
party_node = self.find(TxDtls, './ns:RltdPties/ns:%s' % party_type)
|
||||
account_node = self.find(
|
||||
TxDtls, './ns:RltdPties/ns:%sAcct/ns:Id' % party_type)
|
||||
bic_node = self.find(
|
||||
TxDtls,
|
||||
'./ns:RltdAgts/ns:%sAgt/ns:FinInstnId/ns:BIC' % party_type)
|
||||
if party_node is not None:
|
||||
name_node = self.find(party_node, './ns:Nm')
|
||||
vals['remote_owner'] = (
|
||||
name_node.text if name_node is not None else False)
|
||||
country_node = self.find(party_node, './ns:PstlAdr/ns:Ctry')
|
||||
vals['remote_owner_country'] = (
|
||||
country_node.text if country_node is not None else False)
|
||||
address_node = self.find(party_node, './ns:PstlAdr/ns:AdrLine')
|
||||
if address_node is not None:
|
||||
vals['remote_owner_address'] = [address_node.text]
|
||||
if account_node is not None:
|
||||
iban_node = self.find(account_node, './ns:IBAN')
|
||||
if iban_node is not None:
|
||||
vals['remote_account'] = iban_node.text
|
||||
if bic_node is not None:
|
||||
vals['remote_bank_bic'] = bic_node.text
|
||||
else:
|
||||
domestic_node = self.find(account_node, './ns:Othr/ns:Id')
|
||||
vals['remote_account'] = (
|
||||
domestic_node.text if domestic_node is not None else False)
|
||||
return vals
|
||||
|
||||
def parse_TxDtls(self, TxDtls, entry_values):
|
||||
"""
|
||||
Parse a single TxDtls node
|
||||
"""
|
||||
vals = dict(entry_values)
|
||||
unstructured = self.xpath(TxDtls, './ns:RmtInf/ns:Ustrd')
|
||||
if unstructured:
|
||||
vals['message'] = ' '.join([x.text for x in unstructured])
|
||||
structured = self.find(
|
||||
TxDtls, './ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref')
|
||||
if structured is None or not structured.text:
|
||||
structured = self.find(TxDtls, './ns:Refs/ns:EndToEndId')
|
||||
if structured is not None:
|
||||
vals['reference'] = structured.text
|
||||
else:
|
||||
if vals.get('message'):
|
||||
vals['reference'] = vals['message']
|
||||
vals.update(self.get_party_values(TxDtls))
|
||||
return vals
|
||||
|
||||
def check_version(self):
|
||||
"""
|
||||
Sanity check the document's namespace
|
||||
"""
|
||||
if not self.ns.startswith('{urn:iso:std:iso:20022:tech:xsd:camt.')\
|
||||
and not self.ns.startswith('{ISO:camt.'):
|
||||
raise except_orm(
|
||||
"Error",
|
||||
"This does not seem to be a CAMT format bank statement.")
|
||||
|
||||
if not self.ns.startswith('{urn:iso:std:iso:20022:tech:xsd:camt.053.')\
|
||||
and not self.ns.startswith('{ISO:camt.053'):
|
||||
raise except_orm(
|
||||
"Error",
|
||||
"Only CAMT.053 is supported at the moment.")
|
||||
return True
|
||||
|
||||
def parse(self, cr, data):
|
||||
"""
|
||||
Parse a CAMT053 XML file
|
||||
"""
|
||||
root = etree.fromstring(data)
|
||||
self.ns = root.tag[:root.tag.index("}") + 1]
|
||||
self.check_version()
|
||||
self.assert_tag(root[0][0], 'GrpHdr')
|
||||
statements = []
|
||||
for node in root[0][1:]:
|
||||
statement = self.parse_Stmt(cr, node)
|
||||
if len(statement.transactions):
|
||||
statements.append(statement)
|
||||
return statements
|
||||
29
__unported__/account_banking_fi_patu/__init__.py
Normal file
29
__unported__/account_banking_fi_patu/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2010 Sami Haahtinen (<http://ressukka.net>).
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract EduSense BV
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (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 patu
|
||||
43
__unported__/account_banking_fi_patu/__openerp__.py
Normal file
43
__unported__/account_banking_fi_patu/__openerp__.py
Normal file
@@ -0,0 +1,43 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2010 Sami Haahtinen (<http://ressukka.net>).
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract EduSense BV
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (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': 'Account Banking PATU module',
|
||||
'version': '0.62',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Sami Haahtinen',
|
||||
'website': 'http://ressukka.net',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Module to import Finnish PATU format transation files.
|
||||
|
||||
This modules contains no logic, just an import filter for account_banking.
|
||||
''',
|
||||
'active': False,
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_fi_patu
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:53+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_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:115
|
||||
#, python-format
|
||||
msgid "PATU statement sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:116
|
||||
#, python-format
|
||||
msgid "PATU statement format defines one or more statements in each file. This parser\n"
|
||||
"will parse all statements in a file and import them to OpenERP\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
37
__unported__/account_banking_fi_patu/i18n/nl.po
Normal file
37
__unported__/account_banking_fi_patu/i18n/nl.po
Normal file
@@ -0,0 +1,37 @@
|
||||
# Dutch translation for banking-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the banking-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: banking-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-12-03 11:08+0000\n"
|
||||
"Last-Translator: Erwin van der Ploeg (BAS Solutions) <Unknown>\n"
|
||||
"Language-Team: Dutch <nl@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-31 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:115
|
||||
#, python-format
|
||||
msgid "PATU statement sheet"
|
||||
msgstr "PATU bankafschrift"
|
||||
|
||||
#. module: account_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:116
|
||||
#, python-format
|
||||
msgid ""
|
||||
"PATU statement format defines one or more statements in each file. This "
|
||||
"parser\n"
|
||||
"will parse all statements in a file and import them to OpenERP\n"
|
||||
msgstr ""
|
||||
"PATU afschrift formaat definieert een of meerdere afschriften in ieder "
|
||||
"bestand. deze parser\n"
|
||||
"zal alle afschriften verwerken in het bestand en deze importeren in "
|
||||
"OpenERP.\n"
|
||||
33
__unported__/account_banking_fi_patu/i18n/pt_BR.po
Normal file
33
__unported__/account_banking_fi_patu/i18n/pt_BR.po
Normal file
@@ -0,0 +1,33 @@
|
||||
# Brazilian Portuguese translation for banking-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the banking-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: banking-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:32+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@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-31 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:115
|
||||
#, python-format
|
||||
msgid "PATU statement sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fi_patu
|
||||
#: code:addons/account_banking_fi_patu/patu.py:116
|
||||
#, python-format
|
||||
msgid ""
|
||||
"PATU statement format defines one or more statements in each file. This "
|
||||
"parser\n"
|
||||
"will parse all statements in a file and import them to OpenERP\n"
|
||||
msgstr ""
|
||||
250
__unported__/account_banking_fi_patu/parser.py
Normal file
250
__unported__/account_banking_fi_patu/parser.py
Normal file
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""Parser for PATU format files"""
|
||||
import re
|
||||
import datetime
|
||||
|
||||
|
||||
def fixchars(line):
|
||||
"""Fix the characters mangled in the input
|
||||
|
||||
:param line: Line to rewrite
|
||||
|
||||
:returns: string, fixed line
|
||||
"""
|
||||
# Fix the umlauts int the input
|
||||
line = line.replace("{", u"ä")
|
||||
line = line.replace("}", u"ö")
|
||||
# XXX: There are a whole bunch of these, adding them later
|
||||
return line
|
||||
|
||||
|
||||
class PatuParser(object):
|
||||
"""Parse PATU lines in to structs"""
|
||||
|
||||
def __init__(self):
|
||||
""" Initialize PATU parser """
|
||||
|
||||
recparse = dict()
|
||||
recparse["00"] = (
|
||||
"T(?P<recordid>00)(?P<record_len>\d{3})"
|
||||
"(?P<version>\d{3})(?P<accountnr>\d{14})"
|
||||
"(?P<statementnr>\d{3})(?P<startdate>\d{6})"
|
||||
"(?P<enddate>\d{6})"
|
||||
"(?P<creationdate>\d{6})(?P<creationtime>\d{4})"
|
||||
"(?P<customerid>.{17})(?P<balancedate>\d{6})"
|
||||
"(?P<startingbalance>.{19})"
|
||||
"(?P<itemcount>\d{6})(?P<currency>.{3})"
|
||||
"(?P<accountname>.{30})"
|
||||
"(?P<accountlimit>\d{18})(?P<accountowner>.{35})"
|
||||
"(?P<bankcontact1>.{40})(?P<bankcontact2>.{40})"
|
||||
"(?P<bankcontact3>.{30})(?P<ibanswift>.{30})"
|
||||
)
|
||||
recparse["10"] = (
|
||||
"T(?P<recordid>[18]0)(?P<record_len>\d{3})"
|
||||
"(?P<eventid>\d{6})"
|
||||
"(?P<archivalnr>.{18})(?P<recorddate>\d{6})"
|
||||
"(?P<valuedate>\d{6})"
|
||||
"(?P<paymentdate>\d{6})(?P<eventtype>\d)"
|
||||
"(?P<eventcode>.{3})(?P<eventdesc>.{35})"
|
||||
"(?P<amount>.{19})(?P<receiptcode>.)(?P<creationmethod>.)"
|
||||
"(?P<recipientname>.{35})(?P<recipientsource>.)"
|
||||
"(?P<recipientaccount>.{14})(?P<recipientaccountchanged>.)"
|
||||
"(?P<refnr>.{20})"
|
||||
"(?P<formnr>.{8})(?P<eventlevel>.)"
|
||||
)
|
||||
recparse["11"] = (
|
||||
"T(?P<recordid>[18]1)(?P<record_len>\d{3})"
|
||||
"(?P<infotype>.{2})"
|
||||
"(?:(?# Match specific info)"
|
||||
"(?<=00)(?P<message>.{35})+"
|
||||
"|"
|
||||
"(?<=01)(?P<transactioncount>\d{8})"
|
||||
"|"
|
||||
"(?<=02)(?P<customerid>.{10})\s(?P<invoicenr>.{15})\s"
|
||||
"(?P<invoicedate>\d{6})"
|
||||
"|"
|
||||
"(?<=03)(?P<cardnumber>.{19})\s(?P<storereference>.{14})"
|
||||
"|"
|
||||
"(?<=04)(?P<origarchiveid>.{18})"
|
||||
"|"
|
||||
"(?<=05)(?P<destinationamount>.{19})\s(?P<currency>.{3})\s"
|
||||
"(?P<exchangerate>.{11})(?P<rateref>.{6})"
|
||||
"|"
|
||||
"(?<=06)(?P<principalinfo1>.{35})(?P<principalinfo2>.{35})"
|
||||
"|"
|
||||
"(?<=07)(?P<bankinfo1>.{35})"
|
||||
"(?P<bankinfo2>.{35})?"
|
||||
"(?P<bankinfo3>.{35})?"
|
||||
"(?P<bankinfo4>.{35})?"
|
||||
"(?P<bankinfo5>.{35})?"
|
||||
"(?P<bankinfo6>.{35})?"
|
||||
"(?P<bankinfo7>.{35})?"
|
||||
"(?P<bankinfo8>.{35})?"
|
||||
"(?P<bankinfo9>.{35})?"
|
||||
"(?P<bankinfo10>.{35})?"
|
||||
"(?P<bankinfo11>.{35})?"
|
||||
"(?P<bankinfo12>.{35})?"
|
||||
"|"
|
||||
"(?<=08)(?P<paymentcode>\d{3})\s(?P<paymentdesc>.{31})"
|
||||
"|"
|
||||
"(?<=09)(?P<recipientname2>.{35})"
|
||||
"|"
|
||||
"(?<=11)(?P<reference>.{35})(?P<recipientiban>.{35})"
|
||||
"(?P<recipientbic>.{35})(?P<recipientnameiban>.{70})"
|
||||
"(?P<sendername>.{70})(?P<senderid>.{35})"
|
||||
"(?P<archivalid>.{70})"
|
||||
")"
|
||||
)
|
||||
recparse["40"] = (
|
||||
"T(?P<recordid>40)(?P<record_len>\d{3})"
|
||||
"(?P<recorddate>\d{6})(?P<balance>.{19})"
|
||||
"(?P<availablefunds>.{19})"
|
||||
)
|
||||
recparse["50"] = (
|
||||
"T(?P<recordid>50)(?P<record_len>\d{3})"
|
||||
"(?P<period>\d)(?P<perioddate>\d{6})"
|
||||
"(?P<depositcount>\d{8})(?P<depositsum>.{19})"
|
||||
"(?P<withdrawcount>\d{8})(?P<withdrawsum>.{19})"
|
||||
)
|
||||
recparse["60"] = (
|
||||
"T(?P<recordid>60)(?P<record_len>\d{3})"
|
||||
"(?P<bankid>.{3})(?P<specialid>01)"
|
||||
"(?P<interestperiodstart>\d{6})-"
|
||||
"(?P<interestperiodend>\d{6})"
|
||||
"(?P<avgbalanceinfo>.)(?P<avgbalance>.{19})"
|
||||
"(?P<interestinfo>.)(?P<interestrate>\d{7})"
|
||||
"(?P<limitbalanceinfo>.)(?P<avglimitbalance>.{19})"
|
||||
"(?P<limitinterestinfo>.)(?P<limitinterestrate>\d{7})"
|
||||
"(?P<limitusageinfo>.)(?P<limitusage>\d{7})"
|
||||
"(?P<permanentbalanceinfo>.)(?P<permanentbalance>.{19})"
|
||||
"(?P<refinterestinfo>.)(?P<refinterestname>.{35})"
|
||||
"(?P<refinterestrate>\d{7})"
|
||||
"(?P<refcreditinfo>.)(?P<refcreditname>.{35})"
|
||||
"(?P<refcreditrate>\d{7})"
|
||||
)
|
||||
recparse["70"] = (
|
||||
"T(?P<recordid>70)(?P<record_len>\d{3})"
|
||||
"(?P<bankid>\d{3})"
|
||||
"(?P<infoline1>.{80})"
|
||||
"(?P<infoline2>.{80})?"
|
||||
"(?P<infoline3>.{80})?"
|
||||
"(?P<infoline4>.{80})?"
|
||||
"(?P<infoline5>.{80})?"
|
||||
"(?P<infoline6>.{80})?"
|
||||
)
|
||||
for record in recparse:
|
||||
recparse[record] = re.compile(recparse[record])
|
||||
self.recparse = recparse
|
||||
|
||||
def parse_record(self, line):
|
||||
"""Docstring for parse_perus
|
||||
|
||||
:param line: description
|
||||
|
||||
:returns: description
|
||||
"""
|
||||
line = fixchars(line)
|
||||
for matcher in self.recparse:
|
||||
matchobj = self.recparse[matcher].match(line)
|
||||
if matchobj:
|
||||
break
|
||||
if not matchobj:
|
||||
print(" **** failed to match line '%s'" % (line))
|
||||
return
|
||||
# Strip strings
|
||||
matchdict = matchobj.groupdict()
|
||||
|
||||
# Remove members set to None
|
||||
for field in matchdict.keys():
|
||||
if not matchdict[field]:
|
||||
del matchdict[field]
|
||||
|
||||
matchkeys = set(matchdict.keys())
|
||||
needstrip = set([
|
||||
"bankcontact1", "bankcontact2", "bankcontact3",
|
||||
"customerid", "accountowner", "accountname", "refnr", "formnr",
|
||||
"recipientname", "eventdesc", "recipientaccount", "message",
|
||||
"principalinfo1", "bankinfo1", "bankinfo2", "bankinfo3",
|
||||
"bankinfo4", "bankinfo5", "bankinfo6", "bankinfo7", "bankinfo8",
|
||||
"bankinfo9", "bankinfo10", "bankinfo11", "bankinfo12",
|
||||
"principalinfo2", "paymentdesc", "infoline1", "infoline2",
|
||||
"infoline3", "infoline4", "infoline5", "infoline6",
|
||||
"recipientname2", "recipientnameiban", "sendername"])
|
||||
for field in matchkeys & needstrip:
|
||||
matchdict[field] = matchdict[field].strip()
|
||||
# Convert to int
|
||||
needsint = set([
|
||||
"itemcount", "eventid", "record_len",
|
||||
"depositcount", "withdrawcount"])
|
||||
for field in matchkeys & needsint:
|
||||
matchdict[field] = float(matchdict[field])
|
||||
# Convert to float
|
||||
needsfloat = set([
|
||||
"startingbalance", "accountlimit", "amount",
|
||||
"destinationamount", "balance", "availablefunds", "depositsum",
|
||||
"withdrawsum", "avgbalance", "avglimitbalance",
|
||||
"permanentbalance"])
|
||||
for field in matchkeys & needsfloat:
|
||||
matchdict[field] = float(matchdict[field])
|
||||
# convert sents to euros
|
||||
needseur = set([
|
||||
"startingbalance", "accountlimit", "amount",
|
||||
"destinationamount", "balance", "availablefunds", "depositsum",
|
||||
"withdrawsum", "avgbalance", "permanentbalance"])
|
||||
for field in matchkeys & needseur:
|
||||
matchdict[field] = matchdict[field] / 100
|
||||
# convert ibanswift to separate fields
|
||||
if "ibanswift" in matchdict:
|
||||
matchdict["iban"], matchdict["swift"] = (
|
||||
matchdict["ibanswift"].strip().split()
|
||||
)
|
||||
|
||||
# Convert date fields
|
||||
needdate = set([
|
||||
"startdate", "enddate", "creationdate", "balancedate",
|
||||
"valuedate", "paymentdate", "recorddate", "perioddate"])
|
||||
for field in matchkeys & needdate:
|
||||
# Base all dates on the year 2000, since it's unlikely that this
|
||||
# starndard will survive to see 2020 due to SEPA
|
||||
datestring = matchdict[field]
|
||||
if datestring == '000000':
|
||||
matchdict[field] = None
|
||||
continue
|
||||
|
||||
matchdict[field] = datetime.date(
|
||||
int("20" + datestring[0:2]),
|
||||
int(datestring[2:4]), int(datestring[4:6]))
|
||||
# convert time fields
|
||||
needtime = set(["creationtime"])
|
||||
for field in matchkeys & needtime:
|
||||
timestring = matchdict[field]
|
||||
matchdict[field] = datetime.time(
|
||||
int(timestring[0:2]),
|
||||
int(timestring[2:4]))
|
||||
|
||||
return matchdict
|
||||
|
||||
|
||||
def parse_file(filename):
|
||||
"""Parse file with PATU format inside
|
||||
|
||||
:param filename: description
|
||||
|
||||
:returns: description
|
||||
"""
|
||||
patufile = open(filename, "r")
|
||||
parser = PatuParser()
|
||||
for line in patufile:
|
||||
parser.parse_record(line)
|
||||
|
||||
|
||||
def main():
|
||||
"""The main function, currently just calls a dummy filename
|
||||
|
||||
:returns: description
|
||||
"""
|
||||
parse_file("myinput.nda")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
132
__unported__/account_banking_fi_patu/patu.py
Normal file
132
__unported__/account_banking_fi_patu/patu.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2010 Sami Haahtinen (<http://ressukka.net>).
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
This parser implements the PATU format support. PATU format is a generic format
|
||||
used by finnish banks.
|
||||
"""
|
||||
from openerp.addons.account_banking.parsers import models
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.account_banking_fi_patu.parser import PatuParser
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
|
||||
class Transaction(models.mem_bank_transaction):
|
||||
"""Implementation of transaction communication class for account_banking.
|
||||
"""
|
||||
mapping = {
|
||||
"remote_account": "recipientaccount",
|
||||
"remote_currency": "currency",
|
||||
"transferred_amount": "amount",
|
||||
"execution_date": "recorddate",
|
||||
"value_date": "paymentdate",
|
||||
"transfer_type": "eventtype",
|
||||
"reference": "refnr",
|
||||
"eventcode": "eventcode",
|
||||
"message": "message"
|
||||
}
|
||||
|
||||
def __init__(self, record, *args, **kwargs):
|
||||
"""Initialize own dict with read values."""
|
||||
super(Transaction, self).__init__(*args, **kwargs)
|
||||
for key in self.mapping:
|
||||
try:
|
||||
setattr(self, key, record[self.mapping[key]])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def is_valid(self):
|
||||
"""Override validity checks.
|
||||
There are certain situations for PATU which can be validated as
|
||||
invalid, but are normal.
|
||||
If eventcode is 730, the transaction was initiated by the bank and
|
||||
doesn't have a destination account.
|
||||
"""
|
||||
if self.eventcode in ["720", "710"]:
|
||||
# Withdrawal from and deposit to the account
|
||||
return (self.execution_date and self.transferred_amount and True) \
|
||||
or False
|
||||
if self.eventcode and self.eventcode == "730":
|
||||
# The transaction is bank initiated, no remote account is present
|
||||
return (self.execution_date and self.transferred_amount and True) \
|
||||
or False
|
||||
return super(Transaction, self).is_valid()
|
||||
|
||||
|
||||
class statement(models.mem_bank_statement):
|
||||
"""Implementation of bank_statement communication class of account_banking
|
||||
"""
|
||||
def __init__(self, record, *args, **kwargs):
|
||||
"""
|
||||
Set decent start values based on first transaction read
|
||||
"""
|
||||
super(statement, self).__init__(*args, **kwargs)
|
||||
self.id = record["statementnr"]
|
||||
self.local_account = self.convert_bank_account(record["accountnr"])
|
||||
self.date = record["creationdate"]
|
||||
self.start_balance = record["startingbalance"]
|
||||
|
||||
def convert_bank_account(self, accountnr):
|
||||
"""Convert bank account number in to a abbreviated format used in
|
||||
finland"""
|
||||
bank = accountnr[:6]
|
||||
account = accountnr[6:].lstrip("0")
|
||||
return "%s-%s" % (bank, account)
|
||||
|
||||
def import_transaction(self, record):
|
||||
"""Import a transaction to the statement"""
|
||||
if record["recordid"] == "40":
|
||||
self.end_balance = record["balance"]
|
||||
elif record["recordid"] == "10" or record["recordid"] == "80":
|
||||
# XXX: Sum up entries that have detailed records set for them. For
|
||||
# now, ignore the parent entry
|
||||
if record["receiptcode"] == "E":
|
||||
return
|
||||
self.transactions.append(Transaction(record))
|
||||
|
||||
|
||||
class Parser(models.parser):
|
||||
code = 'FIPATU'
|
||||
name = _('PATU statement sheet')
|
||||
doc = _('''\
|
||||
PATU statement format defines one or more statements in each file. This parser
|
||||
will parse all statements in a file and import them to OpenERP
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
patuparser = PatuParser()
|
||||
for line in data.splitlines():
|
||||
# Skip empty (last) lines
|
||||
if not line:
|
||||
continue
|
||||
record = patuparser.parse_record(line)
|
||||
if record["recordid"] == "00":
|
||||
# New statement
|
||||
stmnt = statement(record)
|
||||
result.append(stmnt)
|
||||
else:
|
||||
stmnt.import_transaction(record)
|
||||
result.append(stmnt)
|
||||
return result
|
||||
24
__unported__/account_banking_fr_lcr/__init__.py
Normal file
24
__unported__/account_banking_fr_lcr/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# French Letter of Change module for OpenERP
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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 account_banking_lcr
|
||||
from . import wizard
|
||||
62
__unported__/account_banking_fr_lcr/__openerp__.py
Normal file
62
__unported__/account_banking_fr_lcr/__openerp__.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# French Letter of Change module for OpenERP
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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': 'French Letter of Change',
|
||||
'summary': 'Create French LCR CFONB files',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'category': 'Banking addons',
|
||||
'depends': ['account_direct_debit'],
|
||||
'external_dependencies': {
|
||||
'python': ['unidecode'],
|
||||
},
|
||||
'data': [
|
||||
'account_banking_lcr_view.xml',
|
||||
'wizard/export_lcr_view.xml',
|
||||
'data/payment_type_lcr.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': ['lcr_demo.xml'],
|
||||
'description': '''
|
||||
French Letter of Change
|
||||
=======================
|
||||
|
||||
This module adds support for French Letters of Change (in French :
|
||||
Lettre de Change Relevé aka LCR).
|
||||
|
||||
This payment type is still in use in France and it is *not* replaced by SEPA
|
||||
one-off Direct Debits.
|
||||
|
||||
With this module, you can generate a CFONB file to send to your bank.
|
||||
|
||||
This module uses the framework provided by the banking addons,
|
||||
cf https://github.com/OCA/banking
|
||||
|
||||
Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com>
|
||||
for any help or question about this module.
|
||||
''',
|
||||
'active': False,
|
||||
'installable': False,
|
||||
}
|
||||
70
__unported__/account_banking_fr_lcr/account_banking_lcr.py
Normal file
70
__unported__/account_banking_fr_lcr/account_banking_lcr.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# French Letter of Change module for OpenERP
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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 openerp.osv import orm, fields
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
class banking_export_lcr(orm.Model):
|
||||
'''French LCR'''
|
||||
_name = 'banking.export.lcr'
|
||||
_description = __doc__
|
||||
_rec_name = 'filename'
|
||||
|
||||
def _generate_filename(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for lcr_file in self.browse(cr, uid, ids, context=context):
|
||||
ref = lcr_file.payment_order_ids[0].reference
|
||||
if ref:
|
||||
label = unidecode(ref.replace('/', '-'))
|
||||
else:
|
||||
label = 'error'
|
||||
res[lcr_file.id] = 'lcr_%s.txt' % label
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'payment_order_ids': fields.many2many(
|
||||
'payment.order',
|
||||
'account_payment_order_lcr_rel',
|
||||
'banking_export_lcr_id', 'payment_order_id',
|
||||
'Payment Orders',
|
||||
readonly=True),
|
||||
'nb_transactions': fields.integer(
|
||||
'Number of Transactions', readonly=True),
|
||||
'total_amount': fields.float(
|
||||
'Total Amount', digits_compute=dp.get_precision('Account'),
|
||||
readonly=True),
|
||||
'create_date': fields.datetime('Generation Date', readonly=True),
|
||||
'file': fields.binary('CFONB File', readonly=True),
|
||||
'filename': fields.function(
|
||||
_generate_filename, type='char', size=256,
|
||||
string='Filename', readonly=True, store=True),
|
||||
'state': fields.selection([
|
||||
('draft', 'Draft'),
|
||||
('sent', 'Sent'),
|
||||
], 'State', readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="banking_export_lcr_form" model="ir.ui.view">
|
||||
<field name="name">banking.export.lcr.form</field>
|
||||
<field name="model">banking.export.lcr</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="LCR File" version="7.0">
|
||||
<header>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<notebook>
|
||||
<page string="General Information">
|
||||
<group name="main">
|
||||
<field name="total_amount" />
|
||||
<field name="nb_transactions" />
|
||||
<field name="create_date" />
|
||||
<field name="file" filename="filename"/>
|
||||
<field name="filename" invisible="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Payment Orders">
|
||||
<field name="payment_order_ids" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="banking_export_lcr_tree" model="ir.ui.view">
|
||||
<field name="name">banking.export.lcr.tree</field>
|
||||
<field name="model">banking.export.lcr</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="LCR Files">
|
||||
<field name="filename"/>
|
||||
<field name="create_date"/>
|
||||
<field name="nb_transactions"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="banking_export_lcr_action" model="ir.actions.act_window">
|
||||
<field name="name">LCR Files</field>
|
||||
<field name="res_model">banking.export.lcr</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="banking_export_lcr_menu"
|
||||
parent="account_payment.menu_main_payment"
|
||||
action="banking_export_lcr_action"
|
||||
sequence="50"
|
||||
/>
|
||||
|
||||
<act_window id="act_banking_export_lcr_payment_order"
|
||||
name="Generated LCR Files"
|
||||
domain="[('payment_order_ids', '=', active_id)]"
|
||||
res_model="banking.export.lcr"
|
||||
src_model="payment.order"
|
||||
view_type="form"
|
||||
view_mode="tree,form"
|
||||
/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_mode_type_lcr" model="payment.mode.type">
|
||||
<field name="name">Lettre de Change Relevé</field>
|
||||
<field name="code">LCR</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_lcr_wizard"/>
|
||||
<field name="payment_order_type">debit</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,187 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_fr_lcr
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-03-20 23:15+0000\n"
|
||||
"PO-Revision-Date: 2014-03-20 23:15+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_banking_fr_lcr
|
||||
#: selection:banking.export.lcr.wizard,state:0
|
||||
msgid "Create"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,nb_transactions:0
|
||||
#: field:banking.export.lcr.wizard,nb_transactions:0
|
||||
msgid "Number of Transactions"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,filename:0
|
||||
#: field:banking.export.lcr.wizard,filename:0
|
||||
msgid "Filename"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,state:0
|
||||
#: field:banking.export.lcr.wizard,state:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
msgid "LCR File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr,state:0
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr,state:0
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:91
|
||||
#, python-format
|
||||
msgid "The field '%s' is empty or 0. It should have a non-null value."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr.wizard,state:0
|
||||
msgid "Finish"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:124
|
||||
#, python-format
|
||||
msgid "For the bank account '%s' of partner '%s', the bank account type is 'RIB and optional IBAN' and the IBAN field is empty, but, starting from 2014, we consider that the IBAN is required. Please write the IBAN on this bank account."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "LCR File Generation"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,total_amount:0
|
||||
#: field:banking.export.lcr.wizard,total_amount:0
|
||||
msgid "Total Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:296
|
||||
#, python-format
|
||||
msgid "The currency of payment line '%s' is '%s'. To be included in a French LCR, the currency must be EUR."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.model,name:account_banking_fr_lcr.model_banking_export_lcr_wizard
|
||||
msgid "Export French LCR File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.model,name:account_banking_fr_lcr.model_banking_export_lcr
|
||||
msgid "French LCR"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Validate"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Generate"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.actions.act_window,name:account_banking_fr_lcr.act_banking_export_lcr_payment_order
|
||||
msgid "Generated LCR Files"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr.wizard,file_id:0
|
||||
msgid "LCR CFONB File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:144
|
||||
#, python-format
|
||||
msgid "LCR are only for French bank accounts. The IBAN '%s' of partner '%s' is not a French IBAN."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:90
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:104
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:123
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:134
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:143
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:295
|
||||
#, python-format
|
||||
msgid "Error:"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
#: model:ir.actions.act_window,name:account_banking_fr_lcr.banking_export_lcr_action
|
||||
#: model:ir.ui.menu,name:account_banking_fr_lcr.banking_export_lcr_menu
|
||||
msgid "LCR Files"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,file:0
|
||||
msgid "CFONB File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
#: field:banking.export.lcr,payment_order_ids:0
|
||||
#: field:banking.export.lcr.wizard,payment_order_ids:0
|
||||
msgid "Payment Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
msgid "General Information"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:135
|
||||
#, python-format
|
||||
msgid "For the bank account '%s' of partner '%s', the Bank Account Type should be 'IBAN'."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr.wizard,file:0
|
||||
msgid "File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:105
|
||||
#, python-format
|
||||
msgid "Cannot convert the field '%s' to ASCII"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,create_date:0
|
||||
msgid "Generation Date"
|
||||
msgstr ""
|
||||
|
||||
204
__unported__/account_banking_fr_lcr/i18n/fr.po
Normal file
204
__unported__/account_banking_fr_lcr/i18n/fr.po
Normal file
@@ -0,0 +1,204 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_fr_lcr
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-03-20 23:15+0000\n"
|
||||
"PO-Revision-Date: 2014-03-27 08:45+0000\n"
|
||||
"Last-Translator: Alexis de Lattre <alexis@via.ecp.fr>\n"
|
||||
"Language-Team: \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-31 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr.wizard,state:0
|
||||
msgid "Create"
|
||||
msgstr "Créer"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,nb_transactions:0
|
||||
#: field:banking.export.lcr.wizard,nb_transactions:0
|
||||
msgid "Number of Transactions"
|
||||
msgstr "Nombre de transactions"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,filename:0
|
||||
#: field:banking.export.lcr.wizard,filename:0
|
||||
msgid "Filename"
|
||||
msgstr "Nom du fichier"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,state:0
|
||||
#: field:banking.export.lcr.wizard,state:0
|
||||
msgid "State"
|
||||
msgstr "État"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
msgid "LCR File"
|
||||
msgstr "Fichier LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr,state:0
|
||||
msgid "Draft"
|
||||
msgstr "Brouillon"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr,state:0
|
||||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:91
|
||||
#, python-format
|
||||
msgid "The field '%s' is empty or 0. It should have a non-null value."
|
||||
msgstr ""
|
||||
"Le champ '%s' est vide ou égal à 0. Il devrait avoir une valeur non nulle."
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: selection:banking.export.lcr.wizard,state:0
|
||||
msgid "Finish"
|
||||
msgstr "Finir"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:124
|
||||
#, python-format
|
||||
msgid ""
|
||||
"For the bank account '%s' of partner '%s', the bank account type is 'RIB and "
|
||||
"optional IBAN' and the IBAN field is empty, but, starting from 2014, we "
|
||||
"consider that the IBAN is required. Please write the IBAN on this bank "
|
||||
"account."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "LCR File Generation"
|
||||
msgstr "Génération du fichier LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,total_amount:0
|
||||
#: field:banking.export.lcr.wizard,total_amount:0
|
||||
msgid "Total Amount"
|
||||
msgstr "Montant total"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:296
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The currency of payment line '%s' is '%s'. To be included in a French LCR, "
|
||||
"the currency must be EUR."
|
||||
msgstr ""
|
||||
"La monnaie de la ligne de paiement '%s' est '%s'. Pour être intégrée dans "
|
||||
"une LCR, la monnaie doit être EUR."
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.model,name:account_banking_fr_lcr.model_banking_export_lcr_wizard
|
||||
msgid "Export French LCR File"
|
||||
msgstr "Export du fichier LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.model,name:account_banking_fr_lcr.model_banking_export_lcr
|
||||
msgid "French LCR"
|
||||
msgstr "LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Validate"
|
||||
msgstr "Valider"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Generate"
|
||||
msgstr "Générer"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: model:ir.actions.act_window,name:account_banking_fr_lcr.act_banking_export_lcr_payment_order
|
||||
msgid "Generated LCR Files"
|
||||
msgstr "Fichiers LCR générés"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr.wizard,file_id:0
|
||||
msgid "LCR CFONB File"
|
||||
msgstr "Fichier CFONB LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:144
|
||||
#, python-format
|
||||
msgid ""
|
||||
"LCR are only for French bank accounts. The IBAN '%s' of partner '%s' is not "
|
||||
"a French IBAN."
|
||||
msgstr ""
|
||||
"Les LCR ne fonctionnent qu'avec des comptes bancaires français. L'IBAN '%s' "
|
||||
"du partenaire '%s' n'est pas un IBAN français."
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:90
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:104
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:123
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:134
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:143
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:295
|
||||
#, python-format
|
||||
msgid "Error:"
|
||||
msgstr "Erreur :"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
#: model:ir.actions.act_window,name:account_banking_fr_lcr.banking_export_lcr_action
|
||||
#: model:ir.ui.menu,name:account_banking_fr_lcr.banking_export_lcr_menu
|
||||
msgid "LCR Files"
|
||||
msgstr "Fichiers LCR"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,file:0
|
||||
msgid "CFONB File"
|
||||
msgstr "Fichier CFONB"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
#: field:banking.export.lcr,payment_order_ids:0
|
||||
#: field:banking.export.lcr.wizard,payment_order_ids:0
|
||||
msgid "Payment Orders"
|
||||
msgstr "Ordre de paiement"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr:0
|
||||
msgid "General Information"
|
||||
msgstr "Informations générales"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:135
|
||||
#, python-format
|
||||
msgid ""
|
||||
"For the bank account '%s' of partner '%s', the Bank Account Type should be "
|
||||
"'IBAN'."
|
||||
msgstr ""
|
||||
"Pour le compte bancaire '%s' du partenaire '%s', le type de compte bancaire "
|
||||
"devrait être 'IBAN'."
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr.wizard,file:0
|
||||
msgid "File"
|
||||
msgstr "Fichier"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: view:banking.export.lcr.wizard:0
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: code:addons/account_banking_fr_lcr/wizard/export_lcr.py:105
|
||||
#, python-format
|
||||
msgid "Cannot convert the field '%s' to ASCII"
|
||||
msgstr "Impossible de convertir le champ '%s' en ASCII"
|
||||
|
||||
#. module: account_banking_fr_lcr
|
||||
#: field:banking.export.lcr,create_date:0
|
||||
msgid "Generation Date"
|
||||
msgstr "Date de génération"
|
||||
15
__unported__/account_banking_fr_lcr/lcr_demo.xml
Normal file
15
__unported__/account_banking_fr_lcr/lcr_demo.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_mode_lcr" model="payment.mode">
|
||||
<field name="name">LCR La Banque Postale</field>
|
||||
<field name="journal" ref="account.bank_journal"/>
|
||||
<field name="bank_id" ref="account_banking_payment_export.main_company_iban"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="type" ref="payment_mode_type_lcr"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_banking_export_lcr,Full access on banking.export.lcr to Account Payment grp,model_banking_export_lcr,account_payment.group_account_payment,1,1,1,1
|
||||
|
23
__unported__/account_banking_fr_lcr/wizard/__init__.py
Normal file
23
__unported__/account_banking_fr_lcr/wizard/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# French Letter of Change module for OpenERP
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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 export_lcr
|
||||
355
__unported__/account_banking_fr_lcr/wizard/export_lcr.py
Normal file
355
__unported__/account_banking_fr_lcr/wizard/export_lcr.py
Normal file
@@ -0,0 +1,355 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# French Letter of Change module for OpenERP
|
||||
# Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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 openerp.osv import orm, fields
|
||||
from openerp.tools.translate import _
|
||||
from openerp import netsvc
|
||||
from datetime import datetime
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from unidecode import unidecode
|
||||
import base64
|
||||
|
||||
LCR_DATE_FORMAT = '%d%m%y'
|
||||
|
||||
|
||||
class banking_export_lcr_wizard(orm.TransientModel):
|
||||
_name = 'banking.export.lcr.wizard'
|
||||
_description = 'Export French LCR File'
|
||||
|
||||
_columns = {
|
||||
'state': fields.selection([
|
||||
('create', 'Create'),
|
||||
('finish', 'Finish'),
|
||||
], 'State', readonly=True),
|
||||
'nb_transactions': fields.related(
|
||||
'file_id', 'nb_transactions', type='integer',
|
||||
string='Number of Transactions', readonly=True),
|
||||
'total_amount': fields.related(
|
||||
'file_id', 'total_amount', type='float', string='Total Amount',
|
||||
readonly=True),
|
||||
'file_id': fields.many2one(
|
||||
'banking.export.lcr', 'LCR CFONB File', readonly=True),
|
||||
'file': fields.related(
|
||||
'file_id', 'file', string="File", type='binary', readonly=True),
|
||||
'filename': fields.related(
|
||||
'file_id', 'filename', string="Filename", type='char', size=256,
|
||||
readonly=True),
|
||||
'payment_order_ids': fields.many2many(
|
||||
'payment.order', 'wiz_lcr_payorders_rel', 'wizard_id',
|
||||
'payment_order_id', 'Payment Orders', readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': 'create',
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
payment_order_ids = context.get('active_ids', [])
|
||||
vals.update({
|
||||
'payment_order_ids': [[6, 0, payment_order_ids]],
|
||||
})
|
||||
return super(banking_export_lcr_wizard, self).create(
|
||||
cr, uid, vals, context=context)
|
||||
|
||||
def _prepare_export_lcr(
|
||||
self, cr, uid, lcr_export, total_amount, transactions_count,
|
||||
cfonb_string, context=None):
|
||||
return {
|
||||
'total_amount': total_amount,
|
||||
'nb_transactions': transactions_count,
|
||||
'file': base64.encodestring(cfonb_string),
|
||||
'payment_order_ids': [(
|
||||
6, 0, [x.id for x in lcr_export.payment_order_ids]
|
||||
)],
|
||||
}
|
||||
|
||||
def _prepare_field(
|
||||
self, cr, uid, field_name, field_value, size, context=None):
|
||||
'''This function is designed to be inherited.'''
|
||||
if not field_value:
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("The field '%s' is empty or 0. It should have a non-null "
|
||||
"value.")
|
||||
% field_name)
|
||||
try:
|
||||
value = unidecode(field_value)
|
||||
unallowed_ascii_chars = [
|
||||
'"', '#', '$', '%', '&', ';', '<', '>', '=', '@',
|
||||
'[', ']', '^', '_', '`', '{', '}', '|', '~', '\\', '!',
|
||||
]
|
||||
for unallowed_ascii_char in unallowed_ascii_chars:
|
||||
value = value.replace(unallowed_ascii_char, '-')
|
||||
except:
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("Cannot convert the field '%s' to ASCII")
|
||||
% field_name)
|
||||
value = value.upper()
|
||||
# Cut if too long
|
||||
value = value[0:size]
|
||||
# enlarge if too small
|
||||
if len(value) < size:
|
||||
value = value.ljust(size, ' ')
|
||||
assert len(value) == size, 'The length of the field is wrong'
|
||||
return value
|
||||
|
||||
def _get_rib_from_iban(self, cr, uid, partner_bank, context=None):
|
||||
# I do NOT want to add a dependancy on l10n_fr_rib, because
|
||||
# we plan to remove the module in the near future
|
||||
# So I consider that IBAN MUST be given in the res.partner.bank
|
||||
# of type 'rib'
|
||||
if partner_bank.state == 'rib' and not partner_bank.acc_number:
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("For the bank account '%s' of partner '%s', the bank "
|
||||
"account type is 'RIB and optional IBAN' and the IBAN "
|
||||
"field is empty, but, starting from 2014, we consider "
|
||||
"that the IBAN is required. Please write the IBAN on "
|
||||
"this bank account.")
|
||||
% (self.pool['res.partner.bank'].name_get(
|
||||
cr, uid, [partner_bank.id], context=context)[0][1],
|
||||
partner_bank.partner_id.name))
|
||||
elif partner_bank.state != 'iban':
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("For the bank account '%s' of partner '%s', the Bank "
|
||||
"Account Type should be 'IBAN'.")
|
||||
% (self.pool['res.partner.bank'].name_get(
|
||||
cr, uid, [partner_bank.id], context=context)[0][1],
|
||||
partner_bank.partner_id.name))
|
||||
iban = partner_bank.acc_number.replace(' ', '')
|
||||
if iban[0:2] != 'FR':
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("LCR are only for French bank accounts. The IBAN '%s' "
|
||||
"of partner '%s' is not a French IBAN.")
|
||||
% (partner_bank.acc_number, partner_bank.partner_id.name))
|
||||
assert len(iban) == 27, 'French IBANs must have 27 caracters'
|
||||
return {
|
||||
'code_banque': iban[4:9],
|
||||
'code_guichet': iban[9:14],
|
||||
'numero_compte': iban[14:25],
|
||||
'cle_rib': iban[25:27],
|
||||
}
|
||||
|
||||
def _prepare_first_cfonb_line(
|
||||
self, cr, uid, lcr_export, context=None):
|
||||
'''Generate the header line of the CFONB file'''
|
||||
code_enregistrement = '03'
|
||||
code_operation = '60'
|
||||
numero_enregistrement = '00000001'
|
||||
numero_emetteur = '000000' # It is not needed for LCR
|
||||
# this number is only required for old national direct debits
|
||||
today_str = fields.date.context_today(self, cr, uid, context=context)
|
||||
today_dt = datetime.strptime(today_str, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date_remise = today_dt.strftime(LCR_DATE_FORMAT)
|
||||
raison_sociale_cedant = self._prepare_field(
|
||||
cr, uid, u'Raison sociale du cédant',
|
||||
lcr_export.payment_order_ids[0].company_id.name, 24,
|
||||
context=context)
|
||||
domiciliation_bancaire_cedant = self._prepare_field(
|
||||
cr, uid, u'Domiciliation bancaire du cédant',
|
||||
lcr_export.payment_order_ids[0].mode.bank_id.bank.name, 24,
|
||||
context=context)
|
||||
code_entree = '3'
|
||||
code_dailly = ' '
|
||||
code_monnaie = 'E'
|
||||
rib = self._get_rib_from_iban(
|
||||
cr, uid, lcr_export.payment_order_ids[0].mode.bank_id,
|
||||
context=context)
|
||||
ref_remise = self._prepare_field(
|
||||
cr, uid, u'Référence de la remise',
|
||||
lcr_export.payment_order_ids[0].reference, 11, context=context)
|
||||
cfonb_line = ''.join([
|
||||
code_enregistrement,
|
||||
code_operation,
|
||||
numero_enregistrement,
|
||||
numero_emetteur,
|
||||
' ' * 6,
|
||||
date_remise,
|
||||
raison_sociale_cedant,
|
||||
domiciliation_bancaire_cedant,
|
||||
code_entree,
|
||||
code_dailly,
|
||||
code_monnaie,
|
||||
rib['code_banque'],
|
||||
rib['code_guichet'],
|
||||
rib['numero_compte'],
|
||||
' ' * (16 + 6 + 10 + 15),
|
||||
# Date de valeur is left empty because it is only for
|
||||
# "remise à l'escompte" and we do
|
||||
# "Encaissement, crédit forfaitaire après l’échéance"
|
||||
ref_remise,
|
||||
])
|
||||
assert len(cfonb_line) == 160, 'LCR CFONB line must have 160 chars'
|
||||
cfonb_line += '\r\n'
|
||||
return cfonb_line
|
||||
|
||||
def _prepare_cfonb_line(
|
||||
self, cr, uid, line, requested_date, transactions_count,
|
||||
context=None):
|
||||
'''Generate each debit line of the CFONB file'''
|
||||
# I use French variable names because the specs are in French
|
||||
code_enregistrement = '06'
|
||||
code_operation = '60'
|
||||
numero_enregistrement = '%08d' % (transactions_count + 1)
|
||||
reference_tire = self._prepare_field(
|
||||
cr, uid, u'Référence tiré', line.communication, 10,
|
||||
context=context)
|
||||
rib = self._get_rib_from_iban(cr, uid, line.bank_id, context=context)
|
||||
|
||||
nom_tire = self._prepare_field(
|
||||
cr, uid, u'Nom tiré', line.partner_id.name, 24, context=context)
|
||||
nom_banque = self._prepare_field(
|
||||
cr, uid, u'Nom banque', line.bank_id.bank.name, 24,
|
||||
context=context)
|
||||
code_acceptation = '0'
|
||||
montant_centimes = int(line.amount_currency * 100)
|
||||
zero_montant_centimes = ('%012d' % montant_centimes)
|
||||
today_str = fields.date.context_today(self, cr, uid, context=context)
|
||||
today_dt = datetime.strptime(today_str, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date_creation = today_dt.strftime(LCR_DATE_FORMAT)
|
||||
requested_date_dt = datetime.strptime(
|
||||
requested_date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date_echeance = requested_date_dt.strftime(LCR_DATE_FORMAT)
|
||||
reference_tireur = reference_tire
|
||||
|
||||
cfonb_line = ''.join([
|
||||
code_enregistrement,
|
||||
code_operation,
|
||||
numero_enregistrement,
|
||||
' ' * (6 + 2),
|
||||
reference_tire,
|
||||
nom_tire,
|
||||
nom_banque,
|
||||
code_acceptation,
|
||||
' ' * 2,
|
||||
rib['code_banque'],
|
||||
rib['code_guichet'],
|
||||
rib['numero_compte'],
|
||||
zero_montant_centimes,
|
||||
' ' * 4,
|
||||
date_echeance,
|
||||
date_creation,
|
||||
' ' * (4 + 1 + 3 + 3 + 9),
|
||||
reference_tireur,
|
||||
])
|
||||
assert len(cfonb_line) == 160, 'LCR CFONB line must have 160 chars'
|
||||
cfonb_line += '\r\n'
|
||||
return cfonb_line
|
||||
|
||||
def _prepare_final_cfonb_line(
|
||||
self, cr, uid, total_amount, transactions_count, context=None):
|
||||
'''Generate the last line of the CFONB file'''
|
||||
code_enregistrement = '08'
|
||||
code_operation = '60'
|
||||
numero_enregistrement = '%08d' % (transactions_count + 2)
|
||||
montant_total_centimes = int(total_amount * 100)
|
||||
zero_montant_total_centimes = ('%012d' % montant_total_centimes)
|
||||
cfonb_line = ''.join([
|
||||
code_enregistrement,
|
||||
code_operation,
|
||||
numero_enregistrement,
|
||||
' ' * (6 + 12 + 24 + 24 + 1 + 2 + 5 + 5 + 11),
|
||||
zero_montant_total_centimes,
|
||||
' ' * (4 + 6 + 10 + 15 + 5 + 6),
|
||||
])
|
||||
assert len(cfonb_line) == 160, 'LCR CFONB line must have 160 chars'
|
||||
return cfonb_line
|
||||
|
||||
def create_lcr(self, cr, uid, ids, context=None):
|
||||
'''Creates the LCR CFONB file.'''
|
||||
lcr_export = self.browse(cr, uid, ids[0], context=context)
|
||||
today = fields.date.context_today(self, cr, uid, context=context)
|
||||
|
||||
cfonb_string = self._prepare_first_cfonb_line(
|
||||
cr, uid, lcr_export, context=context)
|
||||
transactions_count = 0
|
||||
total_amount = 0.0
|
||||
for payment_order in lcr_export.payment_order_ids:
|
||||
total_amount = total_amount + payment_order.total
|
||||
# Iterate each payment lines
|
||||
for line in payment_order.line_ids:
|
||||
if line.currency.name != 'EUR':
|
||||
raise orm.except_orm(
|
||||
_('Error:'),
|
||||
_("The currency of payment line '%s' is '%s'. "
|
||||
"To be included in a French LCR, the currency "
|
||||
"must be EUR.")
|
||||
% (line.name, line.currency.name))
|
||||
transactions_count += 1
|
||||
if payment_order.date_prefered == 'due':
|
||||
requested_date = line.ml_maturity_date or today
|
||||
elif payment_order.date_prefered == 'fixed':
|
||||
requested_date = payment_order.date_scheduled or today
|
||||
else:
|
||||
requested_date = today
|
||||
cfonb_string += self._prepare_cfonb_line(
|
||||
cr, uid, line, requested_date, transactions_count,
|
||||
context=context)
|
||||
|
||||
cfonb_string += self._prepare_final_cfonb_line(
|
||||
cr, uid, total_amount, transactions_count,
|
||||
context=context)
|
||||
|
||||
file_id = self.pool['banking.export.lcr'].create(
|
||||
cr, uid, self._prepare_export_lcr(
|
||||
cr, uid, lcr_export, total_amount, transactions_count,
|
||||
cfonb_string, context=context),
|
||||
context=context)
|
||||
|
||||
self.write(
|
||||
cr, uid, ids, {
|
||||
'file_id': file_id,
|
||||
'state': 'finish',
|
||||
}, context=context)
|
||||
|
||||
action = {
|
||||
'name': 'LCR File',
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': self._name,
|
||||
'res_id': ids[0],
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
return action
|
||||
|
||||
def cancel_lcr(self, cr, uid, ids, context=None):
|
||||
'''Cancel the CFONB file: just drop the file'''
|
||||
lcr_export = self.browse(cr, uid, ids[0], context=context)
|
||||
self.pool['banking.export.lcr'].unlink(
|
||||
cr, uid, lcr_export.file_id.id, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def save_lcr(self, cr, uid, ids, context=None):
|
||||
'''Mark the LCR file as 'sent' and the payment order as 'done'.'''
|
||||
lcr_export = self.browse(cr, uid, ids[0], context=context)
|
||||
self.pool['banking.export.lcr'].write(
|
||||
cr, uid, lcr_export.file_id.id, {'state': 'sent'},
|
||||
context=context)
|
||||
wf_service = netsvc.LocalService('workflow')
|
||||
for order in lcr_export.payment_order_ids:
|
||||
wf_service.trg_validate(uid, 'payment.order', order.id, 'done', cr)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2014 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="banking_export_lcr_wizard_form" model="ir.ui.view">
|
||||
<field name="name">banking.export.lcr.wizard.form</field>
|
||||
<field name="model">banking.export.lcr.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="LCR File Generation" version="7.0">
|
||||
<field name="state" invisible="1"/>
|
||||
<group states="finish">
|
||||
<field name="total_amount" />
|
||||
<field name="nb_transactions" />
|
||||
<field name="file" filename="filename" />
|
||||
<field name="filename" invisible="True"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Generate" name="create_lcr" type="object"
|
||||
class="oe_highlight" states="create"/>
|
||||
<button string="Cancel" special="cancel"
|
||||
class="oe_link" states="create"/>
|
||||
<button string="Validate" name="save_lcr" type="object"
|
||||
class="oe_highlight" states="finish"/>
|
||||
<button string="Cancel" name="cancel_lcr" type="object"
|
||||
class="oe_link" states="finish"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
3
__unported__/account_banking_iban_lookup/__init__.py
Normal file
3
__unported__/account_banking_iban_lookup/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import online
|
||||
from . import urlagent
|
||||
from . import model
|
||||
52
__unported__/account_banking_iban_lookup/__openerp__.py
Normal file
52
__unported__/account_banking_iban_lookup/__openerp__.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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': 'Banking Addons - Iban lookup (legacy)',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Banking addons community',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_banking',
|
||||
'account_iban_preserve_domestic',
|
||||
],
|
||||
'data': [
|
||||
'view/res_bank.xml',
|
||||
'view/res_partner_bank.xml',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python': ['BeautifulSoup'],
|
||||
},
|
||||
'description': '''
|
||||
This addons contains the legacy infrastructure for autocompletion of IBANs
|
||||
and BBANs.
|
||||
|
||||
The autocompletion was implemented for Dutch IBANs, but as it turns out
|
||||
the online database that it consults does not get updated. As a result,
|
||||
the autocompletion will come up with outdated IBANs and BICs.
|
||||
|
||||
This module is deprecated and will be dropped in OpenERP 8.0.
|
||||
''',
|
||||
'auto_install': False,
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
from . import res_bank
|
||||
from . import res_partner_bank
|
||||
63
__unported__/account_banking_iban_lookup/model/res_bank.py
Normal file
63
__unported__/account_banking_iban_lookup/model/res_bank.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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 openerp.osv import orm
|
||||
from openerp.addons.account_banking_iban_lookup import online
|
||||
|
||||
|
||||
class ResBank(orm.Model):
|
||||
_inherit = 'res.bank'
|
||||
|
||||
def online_bank_info(self, cr, uid, bic, context=None):
|
||||
"""
|
||||
Overwrite existing API hook from account_banking
|
||||
"""
|
||||
return online.bank_info(bic)
|
||||
|
||||
def onchange_bic(
|
||||
self, cr, uid, ids, bic, name, context=None):
|
||||
|
||||
if not bic:
|
||||
return {}
|
||||
|
||||
info, address = online.bank_info(bic)
|
||||
if not info:
|
||||
return {}
|
||||
|
||||
if address and address.country_id:
|
||||
country_ids = self.pool.get('res.country').search(
|
||||
cr, uid, [('code', '=', address.country_id)])
|
||||
country_id = country_ids[0] if country_ids else False
|
||||
else:
|
||||
country_id = False
|
||||
|
||||
return {
|
||||
'value': dict(
|
||||
# Only the first eight positions of BIC are used for bank
|
||||
# transfers, so ditch the rest.
|
||||
bic=info.bic[:8],
|
||||
street=address.street,
|
||||
street2=address.get('street2', False),
|
||||
zip=address.zip,
|
||||
city=address.city,
|
||||
country=country_id,
|
||||
name=name or info.name,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# All other contributions are (C) by their respective contributors
|
||||
#
|
||||
# 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 openerp import SUPERUSER_ID
|
||||
from openerp.osv import orm
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.account_banking_iban_lookup import online
|
||||
from openerp.addons.account_banking import sepa
|
||||
from openerp.addons.account_banking.wizard.banktools import get_or_create_bank
|
||||
|
||||
|
||||
def warning(title, message):
|
||||
'''Convenience routine'''
|
||||
return {'warning': {'title': title, 'message': message}}
|
||||
|
||||
|
||||
class res_partner_bank(orm.Model):
|
||||
'''
|
||||
Extended functionality:
|
||||
1. BBAN and IBAN are considered equal
|
||||
2. Online lookup when an API is available (providing NL in this module)
|
||||
3. Banks are created on the fly when using IBAN + online
|
||||
4. IBAN formatting
|
||||
5. BBAN's are generated from IBAN when possible
|
||||
'''
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def init(self, cr):
|
||||
'''
|
||||
Update existing iban accounts to comply to new regime
|
||||
'''
|
||||
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
bank_ids = partner_bank_obj.search(
|
||||
cr, SUPERUSER_ID, [('state', '=', 'iban')], limit=0)
|
||||
for bank in partner_bank_obj.read(cr, SUPERUSER_ID, bank_ids):
|
||||
write_vals = {}
|
||||
if bank['state'] == 'iban':
|
||||
iban_acc = sepa.IBAN(bank['acc_number'])
|
||||
if iban_acc.valid:
|
||||
write_vals['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
write_vals['acc_number'] = str(iban_acc)
|
||||
elif bank['acc_number'] != bank['acc_number'].upper():
|
||||
write_vals['acc_number'] = bank['acc_number'].upper()
|
||||
if write_vals:
|
||||
partner_bank_obj.write(
|
||||
cr, SUPERUSER_ID, bank['id'], write_vals)
|
||||
|
||||
@staticmethod
|
||||
def _correct_IBAN(acc_number):
|
||||
'''
|
||||
Routine to correct IBAN values and deduce localized values when valid.
|
||||
Note: No check on validity IBAN/Country
|
||||
'''
|
||||
iban = sepa.IBAN(acc_number)
|
||||
return (str(iban), iban.localized_BBAN)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
'''
|
||||
if vals.get('state') == 'iban':
|
||||
iban = (vals.get('acc_number')
|
||||
or vals.get('acc_number_domestic', False))
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(iban))
|
||||
return super(res_partner_bank, self).create(
|
||||
cr, uid, vals, context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
|
||||
Update the domestic account number when the IBAN is
|
||||
written, or clear the domestic number on regular account numbers.
|
||||
'''
|
||||
if ids and isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
for account in self.read(
|
||||
cr, uid, ids, ['state', 'acc_number']):
|
||||
if 'state' in vals or 'acc_number' in vals:
|
||||
account.update(vals)
|
||||
if account['state'] == 'iban':
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(account['acc_number']))
|
||||
else:
|
||||
vals['acc_number_domestic'] = False
|
||||
super(res_partner_bank, self).write(
|
||||
cr, uid, account['id'], vals, context)
|
||||
return True
|
||||
|
||||
def onchange_acc_number(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
if state == 'iban':
|
||||
return self.onchange_iban(
|
||||
cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None
|
||||
)
|
||||
else:
|
||||
return self.onchange_domestic(
|
||||
cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None
|
||||
)
|
||||
|
||||
def onchange_domestic(
|
||||
self, cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to find IBAN. When found:
|
||||
1. Reformat BBAN
|
||||
2. Autocomplete bank
|
||||
|
||||
TODO: prevent unnecessary assignment of country_ids and
|
||||
browsing of the country
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
values = {}
|
||||
country_obj = self.pool.get('res.country')
|
||||
country_ids = []
|
||||
country = False
|
||||
|
||||
# Pre fill country based on available data. This is just a default
|
||||
# which can be overridden by the user.
|
||||
# 1. Use provided country_id (manually filled)
|
||||
if country_id:
|
||||
country = country_obj.browse(cr, uid, country_id, context=context)
|
||||
country_ids = [country_id]
|
||||
# 2. Use country_id of found bank accounts
|
||||
# This can be usefull when there is no country set in the partners
|
||||
# addresses, but there was a country set in the address for the bank
|
||||
# account itself before this method was triggered.
|
||||
elif ids and len(ids) == 1:
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
partner_bank_id = partner_bank_obj.browse(
|
||||
cr, uid, ids[0], context=context)
|
||||
if partner_bank_id.country_id:
|
||||
country = partner_bank_id.country_id
|
||||
country_ids = [country.id]
|
||||
# 3. Use country_id of default address of partner
|
||||
# The country_id of a bank account is a one time default on creation.
|
||||
# It originates in the same address we are about to check, but
|
||||
# modifications on that address afterwards are not transfered to the
|
||||
# bank account, hence the additional check.
|
||||
elif partner_id:
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
country = partner_obj.browse(
|
||||
cr, uid, partner_id, context=context).country
|
||||
country_ids = country and [country.id] or []
|
||||
# 4. Without any of the above, take the country from the company of
|
||||
# the handling user
|
||||
if not country_ids:
|
||||
user = self.pool.get('res.users').browse(
|
||||
cr, uid, uid, context=context)
|
||||
# Try user companies partner (user no longer has address in 6.1)
|
||||
if (user.company_id and
|
||||
user.company_id.partner_id and
|
||||
user.company_id.partner_id.country):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
if (user.company_id and user.company_id.partner_id and
|
||||
user.company_id.partner_id.country):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
# Ok, tried everything, give up and leave it to the user
|
||||
return warning(_('Insufficient data'),
|
||||
_('Insufficient data to select online '
|
||||
'conversion database')
|
||||
)
|
||||
result = {'value': values}
|
||||
# Complete data with online database when available
|
||||
if country_ids:
|
||||
country = country_obj.browse(
|
||||
cr, uid, country_ids[0], context=context)
|
||||
values['country_id'] = country_ids[0]
|
||||
if country and country.code in sepa.IBAN.countries:
|
||||
info = online.account_info(country.code, acc_number)
|
||||
if info:
|
||||
iban_acc = sepa.IBAN(info.iban)
|
||||
if iban_acc.valid:
|
||||
values['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
values['acc_number'] = unicode(iban_acc)
|
||||
values['state'] = 'iban'
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid,
|
||||
info.bic or iban_acc.BIC_searchkey,
|
||||
name=info.bank)
|
||||
if country_id:
|
||||
values['country_id'] = country_id
|
||||
values['bank'] = bank_id or False
|
||||
if info.bic:
|
||||
values['bank_bic'] = info.bic
|
||||
else:
|
||||
info = None
|
||||
if info is None:
|
||||
result.update(warning(
|
||||
_('Invalid data'),
|
||||
_('The account number appears to be invalid for %s')
|
||||
% country.name
|
||||
))
|
||||
if info is False:
|
||||
if country.code in sepa.IBAN.countries:
|
||||
acc_number_fmt = sepa.BBAN(acc_number, country.code)
|
||||
if acc_number_fmt.valid:
|
||||
values['acc_number_domestic'] = str(acc_number_fmt)
|
||||
else:
|
||||
result.update(warning(
|
||||
_('Invalid format'),
|
||||
_('The account number has the wrong format for %s')
|
||||
% country.name
|
||||
))
|
||||
return result
|
||||
|
||||
def onchange_iban(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to verify IBAN. When valid:
|
||||
1. Extract BBAN as local account
|
||||
2. Auto complete bank
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
iban_acc = sepa.IBAN(acc_number)
|
||||
if iban_acc.valid:
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid, iban_acc.BIC_searchkey,
|
||||
code=iban_acc.BIC_searchkey
|
||||
)
|
||||
return {
|
||||
'value': dict(
|
||||
acc_number_domestic=iban_acc.localized_BBAN,
|
||||
acc_number=unicode(iban_acc),
|
||||
country=country_id or False,
|
||||
bank=bank_id or False,
|
||||
)
|
||||
}
|
||||
return warning(
|
||||
_('Invalid IBAN account number!'),
|
||||
_("The IBAN number doesn't seem to be correct"))
|
||||
|
||||
def online_account_info(
|
||||
self, cr, uid, country_code, acc_number, context=None):
|
||||
"""
|
||||
Overwrite API hook from account_banking
|
||||
"""
|
||||
return online.account_info(country_code, acc_number)
|
||||
298
__unported__/account_banking_iban_lookup/online.py
Normal file
298
__unported__/account_banking_iban_lookup/online.py
Normal file
@@ -0,0 +1,298 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
'''
|
||||
This module provides online bank databases for conversion between BBAN and
|
||||
IBAN numbers and for consulting.
|
||||
'''
|
||||
import re
|
||||
import urllib
|
||||
import urllib2
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
from openerp.addons.account_banking.sepa import postalcode
|
||||
from openerp.addons.account_banking_iban_lookup.urlagent import (
|
||||
URLAgent,
|
||||
SoupForm,
|
||||
)
|
||||
from openerp.addons.account_banking.sepa.iban import IBAN
|
||||
from openerp.addons.account_banking.struct import struct
|
||||
|
||||
__all__ = [
|
||||
'account_info',
|
||||
'bank_info',
|
||||
]
|
||||
|
||||
IBANlink_NL = 'http://www.ibannl.org/iban_check.php'
|
||||
IBANlink_BE = 'http://www.ibanbic.be/'
|
||||
|
||||
|
||||
def get_iban_bic_NL(bank_acc):
|
||||
'''
|
||||
Consult the Dutch online banking database to check both the account number
|
||||
and the bank to which it belongs. Will not work offline, is limited to
|
||||
banks operating in the Netherlands and will only convert Dutch local
|
||||
account numbers.
|
||||
'''
|
||||
# sanity check: Dutch 7 scheme uses ING as sink and online convertor
|
||||
# calculates accounts, so no need to consult it - calculate our own
|
||||
number = bank_acc.lstrip('0')
|
||||
if len(number) <= 7:
|
||||
iban = IBAN.create(BBAN='INGB' + number.rjust(10, '0'),
|
||||
countrycode='NL'
|
||||
)
|
||||
return struct(
|
||||
iban=iban.replace(' ', ''),
|
||||
account=iban.BBAN[4:],
|
||||
bic='INGBNL2A',
|
||||
code='INGBNL',
|
||||
bank='ING Bank N.V.',
|
||||
country_id='NL',
|
||||
)
|
||||
|
||||
data = urllib.urlencode(dict(number=number, method='POST'))
|
||||
request = urllib2.Request(IBANlink_NL, data)
|
||||
response = urllib2.urlopen(request)
|
||||
soup = BeautifulSoup(response)
|
||||
result = struct()
|
||||
attr = None
|
||||
for _pass, td in enumerate(soup.findAll('td')):
|
||||
if _pass % 2 == 1:
|
||||
result[attr] = unicode(td.find('font').contents[0])
|
||||
else:
|
||||
attr = td.find('strong').contents[0][:4].strip().lower()
|
||||
if result:
|
||||
result.account = bank_acc
|
||||
result.country_id = result.bic[4:6]
|
||||
# Nationalized bank code
|
||||
result.code = result.bic[:6]
|
||||
# All Dutch banks use generic channels
|
||||
# result.bic += 'XXX'
|
||||
return result
|
||||
return None
|
||||
|
||||
|
||||
def get_iban_bic_BE(bank_acc):
|
||||
'''
|
||||
Consult the Belgian online database to check both account number and the
|
||||
bank it belongs to. Will not work offline, is limited to banks operating
|
||||
in Belgium and will only convert Belgian local account numbers.
|
||||
'''
|
||||
def contents(soup, attr):
|
||||
return soup.find('input', {
|
||||
'id': 'textbox%s' % attr
|
||||
}).get('value').strip()
|
||||
|
||||
if not bank_acc.strip():
|
||||
return None
|
||||
|
||||
# Get empty form with hidden validators
|
||||
agent = URLAgent()
|
||||
request = agent.open(IBANlink_BE)
|
||||
|
||||
# Isolate form and fill it in
|
||||
soup = BeautifulSoup(request)
|
||||
form = SoupForm(soup.find('form', {'id': 'form1'}))
|
||||
form['textboxBBAN'] = bank_acc.strip()
|
||||
form['Convert'] = 'Convert Number'
|
||||
|
||||
# Submit the form
|
||||
response = agent.submit(form)
|
||||
|
||||
# Parse the results
|
||||
soup = BeautifulSoup(response)
|
||||
iban = contents(soup, 'IBAN')
|
||||
if iban.lower().startswith('not a'):
|
||||
return None
|
||||
result = struct(iban=iban.replace(' ', ''))
|
||||
result.bic = contents(soup, 'BIC').replace(' ', '')
|
||||
result.bank = contents(soup, 'BankName')
|
||||
|
||||
# Add substracts
|
||||
result.account = bank_acc
|
||||
result.country_id = result.bic[4:6]
|
||||
result.code = result.bic[:6]
|
||||
return result
|
||||
|
||||
|
||||
def BBAN_is_IBAN(bank_acc):
|
||||
'''
|
||||
Intelligent copy, valid for SEPA members who switched to SEPA from old
|
||||
standards before SEPA actually started.
|
||||
'''
|
||||
if isinstance(bank_acc, IBAN):
|
||||
iban_acc = bank_acc
|
||||
else:
|
||||
iban_acc = IBAN(bank_acc)
|
||||
return struct(
|
||||
iban=str(iban_acc),
|
||||
account=str(bank_acc),
|
||||
country_id=iban_acc.countrycode,
|
||||
code=iban_acc.BIC_searchkey,
|
||||
# Note: BIC can not be constructed here!
|
||||
bic=False,
|
||||
bank=False,
|
||||
)
|
||||
|
||||
|
||||
_account_info = {
|
||||
# TODO: Add more online data banks
|
||||
'BA': BBAN_is_IBAN,
|
||||
'BE': get_iban_bic_BE,
|
||||
'BG': BBAN_is_IBAN,
|
||||
'NL': get_iban_bic_NL,
|
||||
'LV': BBAN_is_IBAN,
|
||||
'LT': BBAN_is_IBAN,
|
||||
'LU': BBAN_is_IBAN,
|
||||
'MU': BBAN_is_IBAN,
|
||||
'SM': BBAN_is_IBAN,
|
||||
}
|
||||
|
||||
|
||||
def account_info(iso, bank_acc):
|
||||
'''
|
||||
Consult the online database for this country to obtain its
|
||||
corresponding IBAN/BIC number and other info available.
|
||||
Returns None when a service was found but something went wrong.
|
||||
Returns a dictionary (struct) of information when found, or
|
||||
False when not implemented.
|
||||
'''
|
||||
if iso in _account_info:
|
||||
return _account_info[iso](bank_acc)
|
||||
return False
|
||||
|
||||
|
||||
bic_re = re.compile("[^']+'([^']*)'.*")
|
||||
SWIFTlink = 'http://www.swift.com/bsl/freequery.do'
|
||||
|
||||
|
||||
def bank_info(bic):
|
||||
'''
|
||||
Consult the free online SWIFT service to obtain the name and address of a
|
||||
bank. This call may take several seconds to complete, due to the number of
|
||||
requests to make. In total three HTTP requests are made per function call.
|
||||
In theory one request could be stripped, but the SWIFT terms of use prevent
|
||||
automated usage, so user like behavior is required.
|
||||
|
||||
Update January 2012: Always return None, as the SWIFT page to retrieve the
|
||||
information does no longer exist.
|
||||
If demand exists, maybe bite the bullet and integrate with a paid web
|
||||
service such as http://www.iban-rechner.de.
|
||||
lp914922 additionally suggests to make online lookup optional.
|
||||
'''
|
||||
|
||||
return None, None
|
||||
|
||||
def harvest(soup):
|
||||
retval = struct()
|
||||
for trsoup in soup('tr'):
|
||||
for stage, tdsoup in enumerate(trsoup('td')):
|
||||
if stage == 0:
|
||||
attr = tdsoup.contents[0].strip().replace(' ', '_')
|
||||
elif stage == 2:
|
||||
if tdsoup.contents:
|
||||
retval[attr] = tdsoup.contents[0].strip()
|
||||
else:
|
||||
retval[attr] = ''
|
||||
return retval
|
||||
|
||||
# Get form
|
||||
agent = URLAgent()
|
||||
request = agent.open(SWIFTlink)
|
||||
soup = BeautifulSoup(request)
|
||||
|
||||
# Parse request form. As this form is intertwined with a table, use the
|
||||
# parent as root to search for form elements.
|
||||
form = SoupForm(soup.find('form', {'id': 'frmFreeSearch1'}), parent=True)
|
||||
|
||||
# Fill form fields
|
||||
form['selected_bic'] = bic
|
||||
|
||||
# Get intermediate response
|
||||
response = agent.submit(form)
|
||||
|
||||
# Parse response
|
||||
soup = BeautifulSoup(response)
|
||||
|
||||
# Isolate the full 11 BIC - there may be more, but we only use the first
|
||||
bic_button = soup.find('a', {'class': 'bigbuttonblack'})
|
||||
if not bic_button:
|
||||
return None, None
|
||||
|
||||
# Overwrite the location with 'any' ('XXX') to narrow the results to one
|
||||
# or less.
|
||||
# Assume this regexp will never fail...
|
||||
full_bic = bic_re.match(bic_button.get('href')).groups()[0][:8] + 'XXX'
|
||||
|
||||
# Get the detail form
|
||||
form = SoupForm(soup.find('form', {'id': 'frmDetail'}))
|
||||
|
||||
# Fill detail fields
|
||||
form['selected_bic11'] = full_bic
|
||||
|
||||
# Get final response
|
||||
response = agent.submit(form)
|
||||
soup = BeautifulSoup(response)
|
||||
|
||||
# Now parse the results
|
||||
tables = soup.find('div', {'id': 'Middle'}).findAll('table')
|
||||
if not tables:
|
||||
return None, None
|
||||
tablesoup = tables[2]('table')
|
||||
if not tablesoup:
|
||||
return None, None
|
||||
|
||||
codes = harvest(tablesoup[0])
|
||||
if not codes:
|
||||
return None, None
|
||||
|
||||
bankinfo = struct(
|
||||
# Most banks use the first four chars of the BIC as an identifier for
|
||||
# their 'virtual bank' accross the world, containing all national
|
||||
# banks world wide using the same name.
|
||||
# The concatenation with the two character country code is for most
|
||||
# national branches sufficient as a unique identifier.
|
||||
code=full_bic[:6],
|
||||
bic=full_bic,
|
||||
name=codes.Institution_name,
|
||||
)
|
||||
|
||||
address = harvest(tablesoup[1])
|
||||
# The address in the SWIFT database includes a postal code.
|
||||
# We need to split it into two fields...
|
||||
if not address.Zip_Code:
|
||||
if address.Location:
|
||||
iso, address.Zip_Code, address.Location = \
|
||||
postalcode.split(address.Location, full_bic[4:6])
|
||||
|
||||
bankaddress = struct(
|
||||
street=address.Address.title(),
|
||||
city=address.Location.strip().title(),
|
||||
zip=address.Zip_Code,
|
||||
country=address.Country.title(),
|
||||
country_id=full_bic[4:6],
|
||||
)
|
||||
if ' ' in bankaddress.street:
|
||||
bankaddress.street, bankaddress.street2 = [
|
||||
x.strip() for x in bankaddress.street.split(' ', 1)
|
||||
]
|
||||
else:
|
||||
bankaddress.street2 = ''
|
||||
|
||||
return bankinfo, bankaddress
|
||||
236
__unported__/account_banking_iban_lookup/urlagent.py
Normal file
236
__unported__/account_banking_iban_lookup/urlagent.py
Normal file
@@ -0,0 +1,236 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
'''
|
||||
This module presents a browser like class to browse the web, fill and submit
|
||||
forms and to parse the results back in. It is heavily based on BeautifulSoup.
|
||||
'''
|
||||
|
||||
import urllib
|
||||
|
||||
__all__ = ['urlsplit', 'urljoin', 'pathbase', 'urlbase', 'SoupForm',
|
||||
'URLAgent'
|
||||
]
|
||||
|
||||
|
||||
def urlsplit(url):
|
||||
'''
|
||||
Split an URL into scheme, host and path parts. Helper function.
|
||||
'''
|
||||
if ':' in url:
|
||||
parts = url.split(':')
|
||||
scheme = parts[0]
|
||||
url = ':'.join(parts[1:])
|
||||
else:
|
||||
scheme = ''
|
||||
host, path = urllib.splithost(url)
|
||||
return (scheme, host, path)
|
||||
|
||||
|
||||
def urljoin(scheme, host, path, args=None):
|
||||
'''
|
||||
Join scheme, host and path to a full URL.
|
||||
Optional: add urlencoded args.
|
||||
Helper function.
|
||||
'''
|
||||
url = '%s://%s/%s' % (scheme or 'http', host, path)
|
||||
if args:
|
||||
url += '?%s' % urllib.urlencode(args)
|
||||
return url
|
||||
|
||||
|
||||
def pathbase(path):
|
||||
'''
|
||||
Return the base for the path in order to satisfy relative paths.
|
||||
Helper function.
|
||||
'''
|
||||
if path and '/' in path:
|
||||
return path[:path.rfind('/') + 1]
|
||||
return path
|
||||
|
||||
|
||||
def urlbase(url):
|
||||
'''
|
||||
Return the base URL for url in order to satisfy relative paths.
|
||||
Helper function.
|
||||
'''
|
||||
scheme, host, path = urlsplit(url)
|
||||
return urljoin(scheme, host, pathbase(path))
|
||||
|
||||
|
||||
class SoupForm(object):
|
||||
'''
|
||||
A SoupForm is a representation of a HTML Form in BeautifulSoup terms.
|
||||
It has a helper method __setitem__ to set or replace form fields.
|
||||
It gets initiated from a soup object.
|
||||
'''
|
||||
def __init__(self, soup, parent=False):
|
||||
'''
|
||||
Parse the form attributes and fields from the soup. Make sure
|
||||
to get the action right. When parent is set, then the parent
|
||||
element is used as anchor for the search for form elements.
|
||||
'''
|
||||
self._extra_args = {}
|
||||
self.soup = soup
|
||||
|
||||
# Make sure to use base strings, not unicode
|
||||
for attr, value in soup.attrMap.iteritems():
|
||||
setattr(self, str(attr), str(value))
|
||||
|
||||
# Set right anchor point for harvest
|
||||
if parent:
|
||||
self.soup = soup.parent
|
||||
|
||||
# Harvest input elements.
|
||||
self._args = {}
|
||||
for item in self.soup.findAll('input'):
|
||||
# Make sure to initialize to '' to avoid None strings to appear
|
||||
# during submit
|
||||
self._args[str(item.get('name'))] = item.get('value') or ''
|
||||
|
||||
# Harvest url
|
||||
self.scheme, self.host, self.action = urlsplit(self.action)
|
||||
self.action, args = urllib.splitquery(self.action)
|
||||
if args:
|
||||
args = args.split('&')
|
||||
for arg in args:
|
||||
attr, value = urllib.splitvalue(arg)
|
||||
self._extra_args[str(attr)] = value or ''
|
||||
|
||||
def __setitem__(self, name, value, force=False):
|
||||
'''
|
||||
Set values for the form attributes when present
|
||||
'''
|
||||
if name in self._args or force:
|
||||
self._extra_args[name] = value
|
||||
else:
|
||||
raise AttributeError('No such attribute: %s' % name)
|
||||
|
||||
def __getitem__(self, name):
|
||||
'''
|
||||
Get a value. Set values overrule got values.
|
||||
'''
|
||||
if name in self._extra_args:
|
||||
return self._extra_args[name]
|
||||
if name in self._args:
|
||||
return self._args[name]
|
||||
raise AttributeError('No attribute with name "%s" found.' % name)
|
||||
|
||||
def set(self, **kwargs):
|
||||
'''
|
||||
Forcibly sets an attribute to the supplied value, even if it is not
|
||||
part of the parsed form.
|
||||
Can be useful in situations where forms are deliberatly chunked in
|
||||
order to make it difficult to automate form requests, e.g. the
|
||||
SWIFT BIC service, which uses JavaScript to add form attributes to an
|
||||
emtpy base form.
|
||||
'''
|
||||
for name, value in kwargs.iteritems():
|
||||
self.__setitem__(name, value, force=True)
|
||||
|
||||
def args(self):
|
||||
'''
|
||||
Return the field values as attributes, updated with the modified
|
||||
values.
|
||||
'''
|
||||
args = dict(self._args)
|
||||
args.update(self._extra_args)
|
||||
return args
|
||||
|
||||
|
||||
class URLAgent(object):
|
||||
'''
|
||||
Assistent object to ease HTTP(S) requests.
|
||||
Mimics a normal web browser.
|
||||
'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(URLAgent, self).__init__(*args, **kwargs)
|
||||
self._extra_headers = {}
|
||||
self.headers = {
|
||||
'User-Agent': (
|
||||
'Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.0.10) '
|
||||
'Gecko/2009042708 Fedora/3.0.10-1.fc9 Firefox/3.0.10'),
|
||||
'Accept': (
|
||||
'text/html,application/xhtml+xml,application/xml;'
|
||||
'q=0.9,*/*;q=0.8'),
|
||||
'Accept-Language': 'en-us;q=1.0',
|
||||
'Accept-Charset': 'UTF-8,*',
|
||||
'Cache-Control': 'max-age=0'
|
||||
}
|
||||
|
||||
def add_headers(self, **kwargs):
|
||||
self._extra_headers.update(**kwargs)
|
||||
|
||||
def open(self, URL):
|
||||
'''
|
||||
Open a URL and set some vars based on the used URL.
|
||||
Meant to be used on a single server.
|
||||
'''
|
||||
self.scheme, self.host, self.path = urlsplit(URL)
|
||||
|
||||
# Create agent
|
||||
self.agent = urllib.URLopener()
|
||||
|
||||
# Remove additional and unasked for User-Agent header
|
||||
# Some servers choke on multiple User-Agent headers
|
||||
self.agent.addheaders = []
|
||||
headers = self._extra_headers.copy()
|
||||
headers.update(self.headers)
|
||||
for key, value in headers.iteritems():
|
||||
self.agent.addheader(key, value)
|
||||
|
||||
# Open webpage
|
||||
request = self.agent.open(URL)
|
||||
|
||||
# Get and set cookies for next actions
|
||||
attributes = request.info()
|
||||
if 'set-cookie' in attributes:
|
||||
self.agent.addheader('Cookie', attributes['set-cookie'])
|
||||
|
||||
# Add referer
|
||||
self.agent.addheader('Referer', URL)
|
||||
|
||||
# Return request
|
||||
return request
|
||||
|
||||
def submit(self, form, action=None, method=None, **kwargs):
|
||||
'''
|
||||
Submit a SoupForm. Override missing attributes in action from our own
|
||||
initial URL.
|
||||
'''
|
||||
if action:
|
||||
scheme, host, path = urlsplit(action)
|
||||
else:
|
||||
scheme = form.scheme or self.scheme
|
||||
host = form.host or self.host
|
||||
action = form.action
|
||||
method = (method or form.method).lower()
|
||||
args = urllib.urlencode(kwargs or form.args())
|
||||
|
||||
if not action.startswith('/'):
|
||||
# Relative path
|
||||
action = pathbase(self.path) + action
|
||||
|
||||
function = getattr(self.agent, 'open_%s' % scheme)
|
||||
if method == 'post':
|
||||
return function('//%s%s' % (host, action), args)
|
||||
return function('//%s%s?%s' % (host, action, args))
|
||||
15
__unported__/account_banking_iban_lookup/view/res_bank.xml
Normal file
15
__unported__/account_banking_iban_lookup/view/res_bank.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_res_bank_account_banking_form_1" model="ir.ui.view">
|
||||
<field name="name">Add BIC lookup to bank form</field>
|
||||
<field name="model">res.bank</field>
|
||||
<field name="inherit_id" ref="base.view_res_bank_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bic" position="replace">
|
||||
<field name="bic" on_change="onchange_bic(bic, name)"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_partner_bank_account_banking_form_2" model="ir.ui.view">
|
||||
<field name="name">Add autocompletion methods to partner bank form</field>
|
||||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="base.view_partner_bank_form"/>
|
||||
<field name="priority" eval="24"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="acc_number" position="attributes">
|
||||
<attribute name="on_change">onchange_acc_number(acc_number, acc_number_domestic, state, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
<field name="acc_number_domestic" position="attributes">
|
||||
<attribute name="on_change">onchange_domestic(acc_number_domestic, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
||||
21
__unported__/account_banking_mt940/__init__.py
Normal file
21
__unported__/account_banking_mt940/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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 mt940
|
||||
53
__unported__/account_banking_mt940/__openerp__.py
Normal file
53
__unported__/account_banking_mt940/__openerp__.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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": "MT940",
|
||||
"version": "1.0",
|
||||
"author": "Therp BV",
|
||||
"complexity": "expert",
|
||||
"description": """
|
||||
This addon provides a generic parser for MT940 files. Given that MT940 is a
|
||||
non-open non-standard of pure evil in the way that every bank cooks up its own
|
||||
interpretation of it, this addon alone won't help you much. It is rather
|
||||
intended to be used by other addons to implement the dialect specific to a
|
||||
certain bank.
|
||||
|
||||
See account_banking_nl_ing_mt940 for an example on how to use it.
|
||||
""",
|
||||
"category": "Dependency",
|
||||
"depends": [
|
||||
'account_banking',
|
||||
],
|
||||
"data": [
|
||||
],
|
||||
"js": [
|
||||
],
|
||||
"css": [
|
||||
],
|
||||
"qweb": [
|
||||
],
|
||||
"auto_install": False,
|
||||
'installable': False,
|
||||
"application": False,
|
||||
"external_dependencies": {
|
||||
'python': [],
|
||||
},
|
||||
}
|
||||
225
__unported__/account_banking_mt940/mt940.py
Normal file
225
__unported__/account_banking_mt940/mt940.py
Normal file
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Parser for MT940 format files
|
||||
"""
|
||||
import re
|
||||
import datetime
|
||||
import logging
|
||||
try:
|
||||
from openerp.addons.account_banking.parsers.models import (
|
||||
mem_bank_statement,
|
||||
mem_bank_transaction,
|
||||
)
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT
|
||||
except ImportError:
|
||||
# this allows us to run this file standalone, see __main__ at the end
|
||||
|
||||
class mem_bank_statement:
|
||||
def __init__(self):
|
||||
self.transactions = []
|
||||
|
||||
class mem_bank_transaction:
|
||||
pass
|
||||
DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d"
|
||||
|
||||
|
||||
class MT940(object):
|
||||
'''Inherit this class in your account_banking.parsers.models.parser,
|
||||
define functions to handle the tags you need to handle and adjust static
|
||||
variables as needed.
|
||||
|
||||
Note that order matters: You need to do your_parser(MT940, parser), not the
|
||||
other way around!
|
||||
|
||||
At least, you should override handle_tag_61 and handle_tag_86. Don't forget
|
||||
to call super.
|
||||
handle_tag_* functions receive the remainder of the the line (that is,
|
||||
without ':XX:') and are supposed to write into self.current_transaction'''
|
||||
|
||||
header_lines = 3
|
||||
'''One file can contain multiple statements, each with its own poorly
|
||||
documented header. For now, the best thing to do seems to skip that'''
|
||||
|
||||
footer_regex = '^-}$'
|
||||
footer_regex = '^-XXX$'
|
||||
'The line that denotes end of message, we need to create a new statement'
|
||||
|
||||
tag_regex = '^:[0-9]{2}[A-Z]*:'
|
||||
'The beginning of a record, should be anchored to beginning of the line'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MT940, self).__init__(*args, **kwargs)
|
||||
'state variables'
|
||||
self.current_statement = None
|
||||
'type account_banking.parsers.models.mem_bank_statement'
|
||||
self.current_transaction = None
|
||||
'type account_banking.parsers.models.mem_bank_transaction'
|
||||
self.statements = []
|
||||
'parsed statements up to now'
|
||||
|
||||
def parse(self, cr, data):
|
||||
'implements account_banking.parsers.models.parser.parse()'
|
||||
iterator = data.replace('\r\n', '\n').split('\n').__iter__()
|
||||
line = None
|
||||
record_line = ''
|
||||
try:
|
||||
while True:
|
||||
if not self.current_statement:
|
||||
self.handle_header(cr, line, iterator)
|
||||
line = iterator.next()
|
||||
if not self.is_tag(cr, line) and not self.is_footer(cr, line):
|
||||
record_line = self.append_continuation_line(
|
||||
cr, record_line, line)
|
||||
continue
|
||||
if record_line:
|
||||
self.handle_record(cr, record_line)
|
||||
if self.is_footer(cr, line):
|
||||
self.handle_footer(cr, line, iterator)
|
||||
record_line = ''
|
||||
continue
|
||||
record_line = line
|
||||
except StopIteration:
|
||||
pass
|
||||
return self.statements
|
||||
|
||||
def append_continuation_line(self, cr, line, continuation_line):
|
||||
'''append a continuation line for a multiline record.
|
||||
Override and do data cleanups as necessary.'''
|
||||
return line + continuation_line
|
||||
|
||||
def create_statement(self, cr):
|
||||
'''create a mem_bank_statement - override if you need a custom
|
||||
implementation'''
|
||||
return mem_bank_statement()
|
||||
|
||||
def create_transaction(self, cr):
|
||||
'''create a mem_bank_transaction - override if you need a custom
|
||||
implementation'''
|
||||
return mem_bank_transaction()
|
||||
|
||||
def is_footer(self, cr, line):
|
||||
'''determine if a line is the footer of a statement'''
|
||||
return line and bool(re.match(self.footer_regex, line))
|
||||
|
||||
def is_tag(self, cr, line):
|
||||
'''determine if a line has a tag'''
|
||||
return line and bool(re.match(self.tag_regex, line))
|
||||
|
||||
def handle_header(self, cr, line, iterator):
|
||||
'''skip header lines, create current statement'''
|
||||
for i in range(self.header_lines):
|
||||
iterator.next()
|
||||
self.current_statement = self.create_statement(cr)
|
||||
|
||||
def handle_footer(self, cr, line, iterator):
|
||||
'''add current statement to list, reset state'''
|
||||
self.statements.append(self.current_statement)
|
||||
self.current_statement = None
|
||||
|
||||
def handle_record(self, cr, line):
|
||||
'''find a function to handle the record represented by line'''
|
||||
tag_match = re.match(self.tag_regex, line)
|
||||
tag = tag_match.group(0).strip(':')
|
||||
if not hasattr(self, 'handle_tag_%s' % tag):
|
||||
logging.error('Unknown tag %s', tag)
|
||||
logging.error(line)
|
||||
return
|
||||
handler = getattr(self, 'handle_tag_%s' % tag)
|
||||
handler(cr, line[tag_match.end():])
|
||||
|
||||
def handle_tag_20(self, cr, data):
|
||||
'''ignore reference number'''
|
||||
pass
|
||||
|
||||
def handle_tag_25(self, cr, data):
|
||||
'''get account owner information'''
|
||||
self.current_statement.local_account = data
|
||||
|
||||
def handle_tag_28C(self, cr, data):
|
||||
'''get sequence number _within_this_batch_ - this alone
|
||||
doesn't provide a unique id!'''
|
||||
self.current_statement.id = data
|
||||
|
||||
def handle_tag_60F(self, cr, data):
|
||||
'''get start balance and currency'''
|
||||
self.current_statement.local_currency = data[7:10]
|
||||
self.current_statement.date = str2date(data[1:7])
|
||||
self.current_statement.start_balance = \
|
||||
(1 if data[0] == 'C' else -1) * str2float(data[10:])
|
||||
self.current_statement.id = '%s/%s' % (
|
||||
self.current_statement.date.strftime('%Y'),
|
||||
self.current_statement.id)
|
||||
|
||||
def handle_tag_62F(self, cr, data):
|
||||
'''get ending balance'''
|
||||
self.current_statement.end_balance = \
|
||||
(1 if data[0] == 'C' else -1) * str2float(data[10:])
|
||||
|
||||
def handle_tag_64(self, cr, data):
|
||||
'''get current balance in currency'''
|
||||
pass
|
||||
|
||||
def handle_tag_65(self, cr, data):
|
||||
'''get future balance in currency'''
|
||||
pass
|
||||
|
||||
def handle_tag_61(self, cr, data):
|
||||
'''get transaction values'''
|
||||
transaction = self.create_transaction(cr)
|
||||
self.current_statement.transactions.append(transaction)
|
||||
self.current_transaction = transaction
|
||||
transaction.execution_date = str2date(data[:6])
|
||||
transaction.effective_date = str2date(data[:6])
|
||||
transaction.value_date = str2date(data[:6])
|
||||
'...and the rest already is highly bank dependent'
|
||||
|
||||
def handle_tag_86(self, cr, data):
|
||||
'''details for previous transaction, here most differences between
|
||||
banks occur'''
|
||||
pass
|
||||
|
||||
|
||||
def str2date(string, fmt='%y%m%d'):
|
||||
return datetime.datetime.strptime(string, fmt)
|
||||
|
||||
|
||||
def str2float(string):
|
||||
return float(string.replace(',', '.'))
|
||||
|
||||
|
||||
def main(filename):
|
||||
"""testing"""
|
||||
parser = MT940()
|
||||
parser.parse(None, open(filename, 'r').read())
|
||||
for statement in parser.statements:
|
||||
print '''statement found for %(local_account)s at %(date)s
|
||||
with %(local_currency)s%(start_balance)s to %(end_balance)s
|
||||
''' % statement.__dict__
|
||||
for transaction in statement.transactions:
|
||||
print '''
|
||||
transaction on %(execution_date)s''' % transaction.__dict__
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
main(*sys.argv[1:])
|
||||
2
__unported__/account_banking_nl_abnamro/__init__.py
Normal file
2
__unported__/account_banking_nl_abnamro/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import abnamro
|
||||
42
__unported__/account_banking_nl_abnamro/__openerp__.py
Normal file
42
__unported__/account_banking_nl_abnamro/__openerp__.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 - 2011 EduSense BV (<http://www.edusense.nl>)
|
||||
# and Therp BV (<http://therp.nl>)
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'abnamro (NL) Bank Statements Import',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': ['Therp BV', 'EduSense BV'],
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Import filter for abnamro (NL) bank transaction files (txt/tab format).
|
||||
|
||||
No formal specifications of the file layout are released by abnamro. You can
|
||||
help improve the performance of this import filter on
|
||||
https://launchpad.net/account-banking.
|
||||
|
||||
Imported bank transfers are organized in statements covering periods of one
|
||||
week, even if the imported files cover a different period.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
394
__unported__/account_banking_nl_abnamro/abnamro.py
Normal file
394
__unported__/account_banking_nl_abnamro/abnamro.py
Normal file
@@ -0,0 +1,394 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>)
|
||||
# 2011 - 2013 Therp BV (<http://therp.nl>)
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
'''
|
||||
This parser follows the Dutch Banking Tools specifications which are
|
||||
empirically recreated in this module.
|
||||
|
||||
Dutch Banking Tools uses the concept of 'Afschrift' or Bank Statement.
|
||||
Every transaction is bound to a Bank Statement. As such, this module generates
|
||||
Bank Statements along with Bank Transactions.
|
||||
'''
|
||||
from openerp.addons.account_banking.parsers import models
|
||||
from openerp.addons.account_banking.parsers.convert import str2date
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import orm
|
||||
|
||||
import re
|
||||
import csv
|
||||
|
||||
__all__ = ['parser']
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
|
||||
class transaction_message(object):
|
||||
'''
|
||||
A auxiliary class to validate and coerce read values
|
||||
'''
|
||||
attrnames = [
|
||||
'local_account', 'local_currency', 'date', 'u1', 'u2', 'date2',
|
||||
'transferred_amount', 'blob',
|
||||
]
|
||||
|
||||
def __init__(self, values, subno):
|
||||
'''
|
||||
Initialize own dict with attributes and coerce values to right type
|
||||
'''
|
||||
if len(self.attrnames) != len(values):
|
||||
raise ValueError(
|
||||
_('Invalid transaction line: expected %d columns, found '
|
||||
'%d') % (len(self.attrnames), len(values))
|
||||
)
|
||||
''' Strip all values except the blob '''
|
||||
for (key, val) in zip(self.attrnames, values):
|
||||
self.__dict__[key] = key == 'blob' and val or val.strip()
|
||||
# for lack of a standardized locale function to parse amounts
|
||||
self.local_account = self.local_account.zfill(10)
|
||||
self.transferred_amount = float(
|
||||
self.transferred_amount.replace(',', '.'))
|
||||
self.execution_date = str2date(self.date, '%Y%m%d')
|
||||
self.value_date = str2date(self.date, '%Y%m%d')
|
||||
# Set statement_id based on week number
|
||||
self.statement_id = self.execution_date.strftime('%Yw%W')
|
||||
self.id = str(subno).zfill(4)
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
'''
|
||||
Implementation of transaction communication class for account_banking.
|
||||
'''
|
||||
attrnames = ['local_account', 'local_currency', 'transferred_amount',
|
||||
'blob', 'execution_date', 'value_date', 'id',
|
||||
]
|
||||
|
||||
type_map = {
|
||||
# retrieved from online help in the Triodos banking application
|
||||
'BEA': bt.PAYMENT_TERMINAL, # Pin
|
||||
'GEA': bt.BANK_TERMINAL, # ATM
|
||||
'COSTS': bt.BANK_COSTS,
|
||||
'BANK': bt.ORDER,
|
||||
'GIRO': bt.ORDER,
|
||||
'INTL': bt.ORDER, # international order
|
||||
'UNKN': bt.ORDER, # everything else
|
||||
'SEPA': bt.ORDER,
|
||||
'PAYB': bt.PAYMENT_BATCH,
|
||||
'RETR': bt.STORNO,
|
||||
}
|
||||
|
||||
def __init__(self, line, *args, **kwargs):
|
||||
'''
|
||||
Initialize own dict with read values.
|
||||
'''
|
||||
super(transaction, self).__init__(*args, **kwargs)
|
||||
# Copy attributes from auxiliary class to self.
|
||||
for attr in self.attrnames:
|
||||
setattr(self, attr, getattr(line, attr))
|
||||
# Initialize other attributes
|
||||
self.transfer_type = 'UNKN'
|
||||
self.remote_account = ''
|
||||
self.remote_owner = ''
|
||||
self.reference = ''
|
||||
self.message = ''
|
||||
# Decompose structured messages
|
||||
self.parse_message()
|
||||
|
||||
def is_valid(self):
|
||||
if not self.error_message:
|
||||
if not self.transferred_amount:
|
||||
self.error_message = "No transferred amount"
|
||||
elif not self.execution_date:
|
||||
self.error_message = "No execution date"
|
||||
elif not self.remote_account and self.transfer_type not in [
|
||||
'BEA', 'GEA', 'COSTS', 'UNKN', 'PAYB', ]:
|
||||
self.error_message = _(
|
||||
'No remote account for transaction type %s'
|
||||
) % self.transfer_type
|
||||
if self.error_message:
|
||||
raise orm.except_orm(_('Error !'), _(self.error_message))
|
||||
return not self.error_message
|
||||
|
||||
def parse_message(self):
|
||||
'''
|
||||
Parse structured message parts into appropriate attributes
|
||||
'''
|
||||
def split_blob(line):
|
||||
# here we split up the blob, which the last field in a tab
|
||||
# separated statement line the blob is a *space separated* fixed
|
||||
# field format with field length 32. Empty fields are ignored
|
||||
col = 0
|
||||
size = 33
|
||||
res = []
|
||||
while(len(line) > col * size):
|
||||
separation = (col + 1) * size - 1
|
||||
if line[col * size: separation].strip():
|
||||
part = line[col * size: separation]
|
||||
# If the separation character is not a space, add it anyway
|
||||
# presumably for sepa feedback strings only
|
||||
if (len(line) > separation and line[separation] != ' '):
|
||||
part += line[separation]
|
||||
res.append(part)
|
||||
col += 1
|
||||
return res
|
||||
|
||||
def get_sepa_dict(field):
|
||||
"""
|
||||
Parses a subset of SEPA feedback strings as occur
|
||||
in this non-SEPA csv format.
|
||||
|
||||
The string consists of slash separated KEY/VALUE pairs,
|
||||
but the slash is allowed to and known to occur in VALUE as well!
|
||||
"""
|
||||
def _sepa_message(field, reason):
|
||||
return _(
|
||||
'unable to parse SEPA string: %s - %s' % (field, reason))
|
||||
|
||||
def _get_next_key(items, start):
|
||||
'''Find next key, starting from start, returns the key found,
|
||||
the start position in the array and the end position + 1'''
|
||||
known_keys = [
|
||||
'TRTP', 'IBAN', 'BIC', 'NAME', 'RTRN', 'EREF', 'SWOC',
|
||||
'REMI', 'ADDR', 'CPRP', 'CREF', 'CSID', 'ISDT', 'MARF',
|
||||
'NRTX', 'NRTXR', 'PREF', 'PURP', 'REFOB', 'RREF', 'RTYP',
|
||||
'SVCL', 'SWOD', 'BENM//ID', 'ORDP//ID', 'ORDP//RID',
|
||||
'ORIG//CSID', 'ORIG//MARF', 'ULTD//NAME', 'ULTD//ID',
|
||||
'ULTB//NAME', 'ULTB//ID'
|
||||
]
|
||||
items_len = len(items)
|
||||
start_index = start
|
||||
# Search until start after end of items
|
||||
while start_index < items_len:
|
||||
end_index = start_index + 1
|
||||
while end_index < items_len:
|
||||
key = '/'.join(items[start_index:end_index])
|
||||
if key in known_keys:
|
||||
return (key, start_index, end_index)
|
||||
end_index += 1
|
||||
start_index += 1
|
||||
return False
|
||||
|
||||
items = field[1:].split('/')
|
||||
assert len(items) > 1, _sepa_message(field, _('too few items'))
|
||||
sepa_dict = {}
|
||||
item_index = 0
|
||||
items_len = len(items)
|
||||
key_info = _get_next_key(items, item_index)
|
||||
assert key_info, _sepa_message(
|
||||
field, _('no key found for start %d') % item_index)
|
||||
assert key_info[1] == 0, _sepa_message(
|
||||
field, _('invalid data found before key %s') % key_info[0])
|
||||
while key_info:
|
||||
sepa_key = key_info[0]
|
||||
item_index = key_info[2]
|
||||
# Find where next key - if any - starts
|
||||
key_info = _get_next_key(items, item_index)
|
||||
value_end_index = (key_info and key_info[1]) or items_len
|
||||
sepa_value = (
|
||||
(
|
||||
(value_end_index > item_index)
|
||||
and '/'.join(items[item_index:value_end_index]))
|
||||
or '')
|
||||
sepa_dict[sepa_key] = sepa_value
|
||||
return sepa_dict
|
||||
|
||||
def parse_type(field):
|
||||
# here we process the first field, which identifies the statement
|
||||
# type and in case of certain types contains additional information
|
||||
transfer_type = 'UNKN'
|
||||
remote_account = False
|
||||
remote_owner = False
|
||||
if field.startswith('/TRTP/'):
|
||||
transfer_type = 'SEPA'
|
||||
elif field.startswith('GIRO '):
|
||||
transfer_type = 'GIRO'
|
||||
# field has markup 'GIRO ACCOUNT OWNER'
|
||||
# separated by clusters of space of varying size
|
||||
account_match = re.match('\s*([0-9]+)\s(.*)$', field[5:])
|
||||
if account_match:
|
||||
remote_account = account_match.group(1).zfill(10)
|
||||
remote_owner = account_match.group(2).strip() or ''
|
||||
else:
|
||||
raise orm.except_orm(
|
||||
_('Error !'),
|
||||
_('unable to parse GIRO string: %s') % field)
|
||||
elif field.startswith('BEA '):
|
||||
transfer_type = 'BEA'
|
||||
# columns 6 to 16 contain the terminal identifier
|
||||
# column 17 contains a space
|
||||
# columns 18 to 31 contain date and time in DD.MM.YY/HH.MM
|
||||
# format
|
||||
elif field.startswith('GEA '):
|
||||
transfer_type = 'GEA'
|
||||
# columns 6 to 16 contain the terminal identifier
|
||||
# column 17 contains a space
|
||||
# columns 18 to 31 contain date and time in DD.MM.YY/HH.MM
|
||||
# format
|
||||
elif field.startswith('MAANDBIJDRAGE ABNAMRO'):
|
||||
transfer_type = 'COSTS'
|
||||
elif re.match("^\s([0-9]+\.){3}[0-9]+\s", field):
|
||||
transfer_type = 'BANK'
|
||||
remote_account = field[1:13].strip().replace('.', '').zfill(10)
|
||||
# column 14 to 31 is either empty or contains the remote owner
|
||||
remote_owner = field[14:32].strip()
|
||||
elif re.match("^EL[0-9]{13}I", field):
|
||||
transfer_type = 'INTL'
|
||||
elif field.startswith("TOTAAL BETALINGEN"):
|
||||
transfer_type = 'PAYB'
|
||||
return (transfer_type, remote_account, remote_owner)
|
||||
|
||||
fields = split_blob(self.blob)
|
||||
(self.transfer_type, self.remote_account, self.remote_owner) = \
|
||||
parse_type(fields[0])
|
||||
|
||||
if self.transfer_type == 'SEPA':
|
||||
sepa_dict = get_sepa_dict(''.join(fields))
|
||||
sepa_type = sepa_dict.get('TRTP') or ''
|
||||
self.transfer_type = {
|
||||
'SEPA BATCH': 'PAYB',
|
||||
'SEPA BATCH SALARIS': 'PAYB',
|
||||
'SEPA TERUGBOEKING': 'RETR',
|
||||
}.get(sepa_type.upper(), 'SEPA')
|
||||
self.remote_account = sepa_dict.get('IBAN', False)
|
||||
self.remote_bank_bic = sepa_dict.get('BIC', False)
|
||||
self.remote_owner = sepa_dict.get('NAME', False)
|
||||
self.reference = sepa_dict.get('REMI', '')
|
||||
|
||||
# extract other information depending on type
|
||||
elif self.transfer_type == 'GIRO':
|
||||
if not self.remote_owner and len(fields) > 1:
|
||||
# OWNER is listed in the second field if not in the first
|
||||
self.remote_owner = fields[1].strip() or False
|
||||
fields = [fields[0]] + fields[2:]
|
||||
self.message = ' '.join(field.strip() for field in fields[1:])
|
||||
|
||||
elif self.transfer_type == 'BEA':
|
||||
# second column contains remote owner and bank pass identification
|
||||
self.remote_owner = (
|
||||
len(fields) > 1 and fields[1].split(',')[0].strip() or False)
|
||||
# column 2 and up can contain additional messsages
|
||||
# (such as transaction costs or currency conversion)
|
||||
self.message = ' '.join(field.strip() for field in fields)
|
||||
|
||||
elif self.transfer_type == 'BANK':
|
||||
# second column contains the remote owner or the first message line
|
||||
if not self.remote_owner:
|
||||
self.remote_owner = (
|
||||
len(fields) > 1 and fields[1].strip() or False)
|
||||
self.message = ' '.join(field.strip() for field in fields[2:])
|
||||
else:
|
||||
self.message = ' '.join(field.strip() for field in fields[1:])
|
||||
|
||||
elif self.transfer_type == 'INTL':
|
||||
# first column seems to consist of some kind of international
|
||||
# transaction id
|
||||
self.reference = fields[0].strip()
|
||||
# second column seems to contain remote currency and amount
|
||||
# to be processed in a later release of this module
|
||||
self.message = len(fields) > 1 and fields[1].strip() or False
|
||||
# third column contains iban, preceeded by a slash forward
|
||||
if len(fields) > 2:
|
||||
if fields[2].startswith('/'):
|
||||
self.remote_account = fields[2][1:].strip()
|
||||
else:
|
||||
self.remote_account = fields[2].strip()
|
||||
# fourth column contains remote owner
|
||||
self.remote_owner = (len(fields) > 3 and fields[3].strip() or
|
||||
False)
|
||||
self.message += ' ' + (
|
||||
' '.join(field.strip() for field in fields[4:]))
|
||||
|
||||
else:
|
||||
self.message = ' '.join(field.strip() for field in fields)
|
||||
|
||||
if not self.reference:
|
||||
# the reference is sometimes flagged by the prefix "BETALINGSKENM."
|
||||
# but can be any numeric line really
|
||||
for field in fields[1:]:
|
||||
m = re.match(
|
||||
"^\s*((BETALINGSKENM\.)|(ACCEPTGIRO))?\s*([0-9]+"
|
||||
"([ /][0-9]+)*)\s*$",
|
||||
field)
|
||||
if m:
|
||||
self.reference = m.group(4)
|
||||
break
|
||||
|
||||
|
||||
class statement(models.mem_bank_statement):
|
||||
'''
|
||||
Implementation of bank_statement communication class of account_banking
|
||||
'''
|
||||
def __init__(self, msg, *args, **kwargs):
|
||||
'''
|
||||
Set decent start values based on first transaction read
|
||||
'''
|
||||
super(statement, self).__init__(*args, **kwargs)
|
||||
self.id = msg.statement_id
|
||||
self.local_account = msg.local_account
|
||||
self.date = str2date(msg.date, '%Y%m%d')
|
||||
self.start_balance = self.end_balance = 0 # msg.start_balance
|
||||
self.import_transaction(msg)
|
||||
|
||||
def import_transaction(self, msg):
|
||||
'''
|
||||
Import a transaction and keep some house holding in the mean time.
|
||||
'''
|
||||
trans = transaction(msg)
|
||||
self.end_balance += trans.transferred_amount
|
||||
self.transactions.append(trans)
|
||||
|
||||
|
||||
class parser(models.parser):
|
||||
code = 'ABNAM'
|
||||
country_code = 'NL'
|
||||
name = _('Abnamro (NL)')
|
||||
doc = _('''\
|
||||
The Dutch Abnamro format is a tab separated text format. The last of these
|
||||
fields is itself a fixed length array containing transaction type, remote
|
||||
account and owner. The bank does not provide a formal specification of the
|
||||
format. Transactions are not explicitely tied to bank statements, although
|
||||
each file covers a period of two weeks.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
lines = data.split('\n')
|
||||
# Transaction lines are not numbered, so keep a tracer
|
||||
subno = 0
|
||||
statement_id = False
|
||||
for line in csv.reader(lines, delimiter='\t', quoting=csv.QUOTE_NONE):
|
||||
# Skip empty (last) lines
|
||||
if not line:
|
||||
continue
|
||||
subno += 1
|
||||
msg = transaction_message(line, subno)
|
||||
if not statement_id:
|
||||
statement_id = self.get_unique_statement_id(
|
||||
cr, msg.execution_date.strftime('%Yw%W'))
|
||||
msg.statement_id = statement_id
|
||||
if stmnt:
|
||||
stmnt.import_transaction(msg)
|
||||
else:
|
||||
stmnt = statement(msg)
|
||||
result.append(stmnt)
|
||||
return result
|
||||
@@ -0,0 +1,89 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_abnamro
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:53+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_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:122
|
||||
#, python-format
|
||||
msgid "No remote account for transaction type %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:348
|
||||
#, python-format
|
||||
msgid "Abnamro (NL)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:197
|
||||
#, python-format
|
||||
msgid "invalid data found before key %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:125
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:229
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:261
|
||||
#, python-format
|
||||
msgid "Sepa transaction type %s not handled yet"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:60
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:189
|
||||
#, python-format
|
||||
msgid "too few items"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:195
|
||||
#, python-format
|
||||
msgid "no key found for start %d"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:162
|
||||
#, python-format
|
||||
msgid "unable to parse SEPA string: %s - %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:230
|
||||
#, python-format
|
||||
msgid "unable to parse GIRO string: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:349
|
||||
#, python-format
|
||||
msgid "The Dutch Abnamro format is a tab separated text format. The last of these\n"
|
||||
"fields is itself a fixed length array containing transaction type, remote\n"
|
||||
"account and owner. The bank does not provide a formal specification of the\n"
|
||||
"format. Transactions are not explicitely tied to bank statements, although\n"
|
||||
"each file covers a period of two weeks.\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
94
__unported__/account_banking_nl_abnamro/i18n/en.po
Normal file
94
__unported__/account_banking_nl_abnamro/i18n/en.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_abnamro
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0.1\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 17:48+0000\n"
|
||||
"Last-Translator: Pedro Manuel Baeza <pedro.baeza@gmail.com>\n"
|
||||
"Language-Team: \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-31 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:122
|
||||
#, python-format
|
||||
msgid "No remote account for transaction type %s"
|
||||
msgstr "No remote account for transaction type %s"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:348
|
||||
#, python-format
|
||||
msgid "Abnamro (NL)"
|
||||
msgstr "Abnamro (NL)"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:197
|
||||
#, python-format
|
||||
msgid "invalid data found before key %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:125
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:229
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Error !"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:261
|
||||
#, python-format
|
||||
msgid "Sepa transaction type %s not handled yet"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:60
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Invalid transaction line: expected %d columns, found %d"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:189
|
||||
#, python-format
|
||||
msgid "too few items"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:195
|
||||
#, python-format
|
||||
msgid "no key found for start %d"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:162
|
||||
#, python-format
|
||||
msgid "unable to parse SEPA string: %s - %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:230
|
||||
#, python-format
|
||||
msgid "unable to parse GIRO string: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:349
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Abnamro format is a tab separated text format. The last of these\n"
|
||||
"fields is itself a fixed length array containing transaction type, remote\n"
|
||||
"account and owner. The bank does not provide a formal specification of the\n"
|
||||
"format. Transactions are not explicitely tied to bank statements, although\n"
|
||||
"each file covers a period of two weeks.\n"
|
||||
msgstr ""
|
||||
"The Dutch Abnamro format is a tab separated text format. The last of these\n"
|
||||
"fields is itself a fixed length array containing transaction type, remote\n"
|
||||
"account and owner. The bank does not provide a formal specification of the\n"
|
||||
"format. Transactions are not explicitely tied to bank statements, although\n"
|
||||
"each file covers a period of two weeks.\n"
|
||||
98
__unported__/account_banking_nl_abnamro/i18n/nl.po
Normal file
98
__unported__/account_banking_nl_abnamro/i18n/nl.po
Normal file
@@ -0,0 +1,98 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_abnamro
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0.1\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:53+0000\n"
|
||||
"PO-Revision-Date: 2013-12-03 11:09+0000\n"
|
||||
"Last-Translator: Erwin van der Ploeg (BAS Solutions) <Unknown>\n"
|
||||
"Language-Team: \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-31 06:02+0000\n"
|
||||
"X-Generator: Launchpad (build 17031)\n"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:122
|
||||
#, python-format
|
||||
msgid "No remote account for transaction type %s"
|
||||
msgstr "Geen tegenrekening bij transactietype %s"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:348
|
||||
#, python-format
|
||||
msgid "Abnamro (NL)"
|
||||
msgstr "Abnamro (NL)"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:197
|
||||
#, python-format
|
||||
msgid "invalid data found before key %s"
|
||||
msgstr "Ongeldige gegevesn gevonden voor key %s"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:125
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:229
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Fout !"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:261
|
||||
#, python-format
|
||||
msgid "Sepa transaction type %s not handled yet"
|
||||
msgstr "Sepa transactie type %s kan nog niet worden verwerkt"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:60
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Ongeldige transactieregel: %d kolommen verwacht, %d aangetroffen"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:189
|
||||
#, python-format
|
||||
msgid "too few items"
|
||||
msgstr "te weinig items"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:195
|
||||
#, python-format
|
||||
msgid "no key found for start %d"
|
||||
msgstr "Geen key gevonden voor start %d"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:162
|
||||
#, python-format
|
||||
msgid "unable to parse SEPA string: %s - %s"
|
||||
msgstr "Niet mogelijk om SEPA string: %s - %s te verwerken"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:230
|
||||
#, python-format
|
||||
msgid "unable to parse GIRO string: %s"
|
||||
msgstr "Niet mogelijk om GIRO string: %s te verwerken"
|
||||
|
||||
#. module: account_banking_nl_abnamro
|
||||
#: code:addons/account_banking_nl_abnamro/abnamro.py:349
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Abnamro format is a tab separated text format. The last of these\n"
|
||||
"fields is itself a fixed length array containing transaction type, remote\n"
|
||||
"account and owner. The bank does not provide a formal specification of the\n"
|
||||
"format. Transactions are not explicitely tied to bank statements, although\n"
|
||||
"each file covers a period of two weeks.\n"
|
||||
msgstr ""
|
||||
"Het Nederlandse ABNAMRO-formaat is een tab-gescheiden tekstformaat. De "
|
||||
"laatste\n"
|
||||
"van deze velden is een tabel van vaste lengte met een transactiesoort, "
|
||||
"tegenrekening\n"
|
||||
"en eigenaar. De bank geeft geen formele specificatie van het formaat. "
|
||||
"Transacties\n"
|
||||
"zijn niet expliciet verbonden met een bankafschrift, alhoewel elk bestand "
|
||||
"een periode\n"
|
||||
"van twee weken beslaat.\n"
|
||||
29
__unported__/account_banking_nl_clieop/__init__.py
Normal file
29
__unported__/account_banking_nl_clieop/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract EduSense BV
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (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 wizard
|
||||
from . import account_banking_nl_clieop
|
||||
44
__unported__/account_banking_nl_clieop/__openerp__.py
Normal file
44
__unported__/account_banking_nl_clieop/__openerp__.py
Normal file
@@ -0,0 +1,44 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Account Banking NL ClieOp',
|
||||
'version': '0.92',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'EduSense BV',
|
||||
'website': 'http://www.edusense.nl',
|
||||
'category': 'Account Banking',
|
||||
'depends': [
|
||||
'account_banking_payment',
|
||||
'account_iban_preserve_domestic',
|
||||
],
|
||||
'data': [
|
||||
'account_banking_nl_clieop.xml',
|
||||
'wizard/export_clieop_view.xml',
|
||||
'data/banking_export_clieop.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'description': '''
|
||||
Module to export payment orders in ClieOp format.
|
||||
|
||||
ClieOp format is used by Dutch banks to batch national bank transfers.
|
||||
This module uses the account_banking logic.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user