mirror of
https://github.com/OCA/bank-statement-import.git
synced 2025-01-20 12:37:43 +02:00
[FIX] Add back __unported__ to prevent deletions after PR.
This commit is contained in:
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>
|
||||
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")
|
||||
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')
|
||||
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)
|
||||
92
__unported__/account_banking/res_partner_bank.py
Normal file
92
__unported__/account_banking/res_partner_bank.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- 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):
|
||||
"""
|
||||
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)]
|
||||
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)
|
||||
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
|
||||
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
|
||||
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>
|
||||
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
|
||||
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"
|
||||
28
__unported__/account_banking_nl_girotel/__init__.py
Normal file
28
__unported__/account_banking_nl_girotel/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- 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 girotel
|
||||
36
__unported__/account_banking_nl_girotel/__openerp__.py
Normal file
36
__unported__/account_banking_nl_girotel/__openerp__.py
Normal file
@@ -0,0 +1,36 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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 - Girotel',
|
||||
'version': '0.62',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'EduSense BV',
|
||||
'website': 'http://www.edusense.nl',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking'],
|
||||
'data': [
|
||||
],
|
||||
'description': '''
|
||||
Module to import Dutch Girotel format transation files.
|
||||
|
||||
This modules contains no logic, just an import filter for account_banking.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
399
__unported__/account_banking_nl_girotel/girotel.py
Normal file
399
__unported__/account_banking_nl_girotel/girotel.py
Normal file
@@ -0,0 +1,399 @@
|
||||
# -*- 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 parser follows the Dutch Girotel specifications which are
|
||||
empirically recreated in this module.
|
||||
There is very little information for validating the format or the content
|
||||
within.
|
||||
|
||||
Dutch Girotel uses no concept of 'Afschrift' or Bank Statement.
|
||||
To overcome a lot of problems, this module generates reproducible Bank
|
||||
Staments per months period.
|
||||
|
||||
Transaction ID's are missing, but generated on the fly based on transaction
|
||||
date and sequence position therein.
|
||||
|
||||
Assumptions:
|
||||
1. transactions are sorted in ascending order of date.
|
||||
2. new transactions are appended after previously known transactions of
|
||||
the same date
|
||||
3. banks maintain order in transaction lists within a single date
|
||||
4. the data comes from the SWIFT-network (limited ASCII)
|
||||
|
||||
Assumption 4 seems not always true, leading to wrong character conversions.
|
||||
As a counter measure, all imported data is converted to SWIFT-format before
|
||||
usage.
|
||||
'''
|
||||
from account_banking.parsers import models
|
||||
from account_banking.parsers.convert import str2date
|
||||
from tools.translate import _
|
||||
import re
|
||||
import csv
|
||||
|
||||
_SWIFT = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
"/-?:().,'+ ")
|
||||
|
||||
|
||||
def to_swift(astr, schemes=None):
|
||||
"""
|
||||
Reduce a string to SWIFT fmt
|
||||
"""
|
||||
schemes = schemes or ['utf-8', 'latin-1', 'ascii']
|
||||
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
|
||||
|
||||
swift_string = [
|
||||
x in _SWIFT and x or ' '
|
||||
for x in unicodedata.normalize('NFKD', astr).encode('ascii', 'ignore')
|
||||
]
|
||||
return ''.join(swift_string)
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
__all__ = ['parser']
|
||||
|
||||
|
||||
class transaction_message(object):
|
||||
'''
|
||||
A auxiliary class to validate and coerce read values
|
||||
'''
|
||||
attrnames = [
|
||||
'local_account', 'date', 'transfer_type', 'u1',
|
||||
'remote_account', 'remote_owner', 'u2', 'transferred_amount',
|
||||
'direction', 'u3', 'message', 'remote_currency',
|
||||
]
|
||||
# Attributes with possible non-ASCII string content
|
||||
strattrs = [
|
||||
'remote_owner', 'message'
|
||||
]
|
||||
|
||||
ids = {}
|
||||
|
||||
def __setattribute__(self, attr, value):
|
||||
'''
|
||||
Convert values for string content to SWIFT-allowable content
|
||||
'''
|
||||
if attr != 'strattrs' and attr in self.strattrs:
|
||||
value = to_swift(value)
|
||||
super(transaction_message, self).__setattribute__(attr, value)
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
'''
|
||||
Convert values from string content to SWIFT-allowable content
|
||||
'''
|
||||
retval = super(transaction_message, self).__getattribute__(attr)
|
||||
return attr != (
|
||||
'strattrs'
|
||||
and attr in self.strattrs
|
||||
and to_swift(retval)
|
||||
or retval
|
||||
)
|
||||
|
||||
def genid(self):
|
||||
'''
|
||||
Generate a new id when not assigned before
|
||||
'''
|
||||
if (not hasattr(self, 'id')) or not self.id:
|
||||
if self.date in self.ids:
|
||||
self.ids[self.date] += 1
|
||||
else:
|
||||
self.ids[self.date] = 1
|
||||
self.id = self.date.strftime('%%Y%%m%%d%04d' % self.ids[self.date])
|
||||
|
||||
def __init__(self, values):
|
||||
'''
|
||||
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))
|
||||
)
|
||||
self.__dict__.update(dict(zip(self.attrnames, values)))
|
||||
self.date = str2date(self.date, '%Y%m%d')
|
||||
if self.direction == 'A':
|
||||
self.transferred_amount = -float(self.transferred_amount)
|
||||
# payment batch done via clieop
|
||||
if (self.transfer_type == 'VZ'
|
||||
and (not self.remote_account or self.remote_account == '0')
|
||||
and (not self.message or re.match('^\s*$', self.message))
|
||||
and self.remote_owner.startswith('TOTAAL ')):
|
||||
self.transfer_type = 'PB'
|
||||
self.message = self.remote_owner
|
||||
self.remove_owner = False
|
||||
# payment batch done via sepa
|
||||
if self.transfer_type == 'VZ'\
|
||||
and not self.remote_account\
|
||||
and not self.remote_owner\
|
||||
and re.match(
|
||||
'^Verzamel Eurobetaling .* TOTAAL \d+ POSTEN\s*$',
|
||||
self.message):
|
||||
self.transfer_type = 'PB'
|
||||
else:
|
||||
self.transferred_amount = float(self.transferred_amount)
|
||||
self.local_account = self.local_account.zfill(10)
|
||||
if self.transfer_type != 'DV':
|
||||
self.remote_account = self.remote_account.zfill(10)
|
||||
else:
|
||||
self.remote_account = False
|
||||
self.execution_date = self.value_date = self.date
|
||||
self.remote_owner = self.remote_owner.rstrip()
|
||||
self.message = self.message.rstrip()
|
||||
self.genid()
|
||||
|
||||
@property
|
||||
def statement_id(self):
|
||||
'''Return calculated statement id'''
|
||||
return self.id[:6]
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
'''
|
||||
Implementation of transaction communication class for account_banking.
|
||||
'''
|
||||
attrnames = ['statement_id', 'remote_account', 'remote_owner',
|
||||
'remote_currency', 'transferred_amount', 'execution_date',
|
||||
'value_date', 'transfer_type', 'message',
|
||||
]
|
||||
|
||||
type_map = {
|
||||
'BA': bt.PAYMENT_TERMINAL,
|
||||
'BT': bt.ORDER,
|
||||
'DV': bt.BANK_COSTS,
|
||||
'GM': bt.BANK_TERMINAL,
|
||||
'GT': bt.ORDER,
|
||||
'IC': bt.DIRECT_DEBIT,
|
||||
'OV': bt.ORDER,
|
||||
'VZ': bt.ORDER,
|
||||
'PB': bt.PAYMENT_BATCH,
|
||||
}
|
||||
|
||||
def __init__(self, line, *args, **kwargs):
|
||||
'''
|
||||
Initialize own dict with read values.
|
||||
'''
|
||||
super(transaction, self).__init__(*args, **kwargs)
|
||||
for attr in self.attrnames:
|
||||
setattr(self, attr, getattr(line, attr))
|
||||
self.id = line.id.replace(line.statement_id, '')
|
||||
self.reference = self.message[:32].rstrip()
|
||||
self.parse_message()
|
||||
|
||||
def is_valid(self):
|
||||
'''
|
||||
There are a few situations that can be signaled as 'invalid' but are
|
||||
valid nontheless:
|
||||
1. Invoices from the bank itself are communicated through statements.
|
||||
These too have no remote_account and no remote_owner. They have a
|
||||
transfer_type set to 'DV'.
|
||||
2. Transfers sent through the 'International Transfers' system get
|
||||
their feedback rerouted through a statement, which is not designed to
|
||||
hold the extra fields needed. These transfers have their transfer_type
|
||||
set to 'BT'.
|
||||
3. Cash payments with debit cards are not seen as a transfer between
|
||||
accounts, but as a cash withdrawal. These withdrawals have their
|
||||
transfer_type set to 'BA'.
|
||||
4. Cash withdrawals from banks are too not seen as a transfer between
|
||||
two accounts - the cash exits the banking system. These withdrawals
|
||||
have their transfer_type set to 'GM'.
|
||||
5. Aggregated payment batches. These transactions have transfer type
|
||||
'VZ' natively but are changed to 'PB' while parsing. These transactions
|
||||
have no remote account.
|
||||
'''
|
||||
return bool(self.transferred_amount and self.execution_date and (
|
||||
self.remote_account or
|
||||
self.transfer_type in [
|
||||
'DV', 'PB', 'BT', 'BA', 'GM',
|
||||
]))
|
||||
|
||||
def refold_message(self, message):
|
||||
'''
|
||||
Refold a previously chopped and fixed length message back into one
|
||||
line
|
||||
'''
|
||||
msg, message = message.rstrip(), None
|
||||
parts = [msg[i:i+32].rstrip() for i in range(0, len(msg), 32)]
|
||||
return '\n'.join(parts)
|
||||
|
||||
def parse_message(self):
|
||||
'''
|
||||
Parse the message as sent by the bank. Most messages are composed
|
||||
of chunks of 32 characters, but there are exceptions.
|
||||
'''
|
||||
if self.transfer_type == 'VZ':
|
||||
# Credit bank costs (interest) gets a special treatment.
|
||||
if self.remote_owner.startswith('RC AFREK. REK. '):
|
||||
self.transfer_type = 'DV'
|
||||
|
||||
if self.transfer_type == 'DV':
|
||||
# Bank costs.
|
||||
# Title of action is in remote_owner, message contains additional
|
||||
# info
|
||||
self.reference = self.remote_owner.rstrip()
|
||||
parts = [self.message[i:i+32].rstrip()
|
||||
for i in range(0, len(self.message), 32)
|
||||
]
|
||||
if len(parts) > 3:
|
||||
self.reference = parts[-1]
|
||||
self.message = '\n'.join(parts[:-1])
|
||||
else:
|
||||
self.message = '\n'.join(parts)
|
||||
self.remote_owner = ''
|
||||
|
||||
elif self.transfer_type == 'BA':
|
||||
# Payment through bank terminal
|
||||
# Id of terminal and some owner info is part of message
|
||||
if self.execution_date < str2date('20091130', '%Y%m%d'):
|
||||
parts = self.remote_owner.split('>')
|
||||
else:
|
||||
parts = self.remote_owner.split('>\\')
|
||||
self.remote_owner = ' '.join(parts[0].split()[1:])
|
||||
if len(parts) > 1 and len(parts[1]) > 2:
|
||||
self.remote_owner_city = parts[1]
|
||||
self.message = self.refold_message(self.message)
|
||||
self.reference = '%s %s' % (self.remote_owner,
|
||||
' '.join(self.message.split()[2:4])
|
||||
)
|
||||
|
||||
elif self.transfer_type == 'IC':
|
||||
# Direct debit - remote_owner containts reference, while
|
||||
# remote_owner is part of the message, most often as
|
||||
# first part of the message.
|
||||
# Sometimes this misfires, as with the tax office collecting road
|
||||
# taxes, but then a once-only manual correction is sufficient.
|
||||
parts = [self.message[i:i+32].rstrip()
|
||||
for i in range(0, len(self.message), 32)
|
||||
]
|
||||
self.reference = self.remote_owner
|
||||
|
||||
if not parts:
|
||||
return
|
||||
|
||||
if self.reference.startswith('KN: '):
|
||||
self.reference = self.reference[4:]
|
||||
if parts[0] == self.reference:
|
||||
parts = parts[1:]
|
||||
# The tax administration office seems to be the notorious exception
|
||||
# to the rule
|
||||
if parts[-1] == 'BELASTINGDIENST':
|
||||
self.remote_owner = parts[-1].capitalize()
|
||||
parts = parts[:-1]
|
||||
else:
|
||||
self.remote_owner = parts[0]
|
||||
parts = parts[1:]
|
||||
# Leave the message, to assist in manual correction of misfires
|
||||
self.message = '\n'.join(parts)
|
||||
|
||||
elif self.transfer_type == 'GM':
|
||||
# Cash withdrawal from a bank terminal
|
||||
# Structured remote_owner message containing bank info and location
|
||||
if self.remote_owner.startswith('OPL. CHIPKNIP'):
|
||||
# Transferring cash to debit card
|
||||
self.remote_account = self.local_account
|
||||
self.message = '%s: %s' % (self.remote_owner, self.message)
|
||||
else:
|
||||
if self.execution_date < str2date('20091130', '%Y%m%d'):
|
||||
parts = self.remote_owner.split('>')
|
||||
else:
|
||||
parts = self.remote_owner.split('>\\')
|
||||
if len(parts) > 1:
|
||||
self.reference = ' '.join([x.rstrip() for x in parts])
|
||||
else:
|
||||
self.reference = 'ING BANK NV %s' % parts[0].split(' ')[0]
|
||||
self.remote_owner = ''
|
||||
|
||||
elif self.transfer_type == 'GT':
|
||||
# Normal transaction, but remote_owner can contain city, depending
|
||||
# on length of total. As there is no clear pattern, leave it as
|
||||
# is.
|
||||
self.message = self.refold_message(self.message)
|
||||
|
||||
else:
|
||||
# Final default: reconstruct message from chopped fixed length
|
||||
# message parts.
|
||||
self.message = self.refold_message(self.message)
|
||||
|
||||
|
||||
class statement(models.mem_bank_statement):
|
||||
'''
|
||||
Implementation of bank_statement communication class of account_banking
|
||||
'''
|
||||
def __init__(self, msg, start_balance=0.0, *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 = msg.date
|
||||
self.start_balance = self.end_balance = 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 = 'NLGT'
|
||||
name = _('Dutch Girotel - Kommagescheiden')
|
||||
country_code = 'NL'
|
||||
doc = _('''\
|
||||
The Dutch Girotel - Kommagescheiden format is basicly a MS Excel CSV format.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
dialect = csv.excel()
|
||||
dialect.quotechar = '"'
|
||||
dialect.delimiter = ','
|
||||
lines = data.split('\n')
|
||||
start_balance = 0.0
|
||||
for line in csv.reader(lines, dialect=dialect):
|
||||
# Skip empty (last) lines
|
||||
if not line:
|
||||
continue
|
||||
msg = transaction_message(line)
|
||||
if stmnt and stmnt.id != msg.statement_id:
|
||||
start_balance = stmnt.end_balance
|
||||
result.append(stmnt)
|
||||
stmnt = None
|
||||
if not stmnt:
|
||||
stmnt = statement(msg, start_balance=start_balance)
|
||||
else:
|
||||
stmnt.import_transaction(msg)
|
||||
result.append(stmnt)
|
||||
return result
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,36 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_girotel
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:54+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:54+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_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:325
|
||||
#, python-format
|
||||
msgid "Dutch Girotel - Kommagescheiden"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:327
|
||||
#, python-format
|
||||
msgid "The Dutch Girotel - Kommagescheiden format is basicly a MS Excel CSV format.\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:103
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
|
||||
37
__unported__/account_banking_nl_girotel/i18n/en.po
Normal file
37
__unported__/account_banking_nl_girotel/i18n/en.po
Normal file
@@ -0,0 +1,37 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_multibank
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.7\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:54+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 17:50+0000\n"
|
||||
"Last-Translator: <>\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_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:325
|
||||
#, python-format
|
||||
msgid "Dutch Girotel - Kommagescheiden"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:327
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Girotel - Kommagescheiden format is basicly a MS Excel CSV "
|
||||
"format.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:103
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
39
__unported__/account_banking_nl_girotel/i18n/nl.po
Normal file
39
__unported__/account_banking_nl_girotel/i18n/nl.po
Normal file
@@ -0,0 +1,39 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_girotel
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.12\n"
|
||||
"Report-Msgid-Bugs-To: info@edusense.nl\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:54+0000\n"
|
||||
"PO-Revision-Date: 2013-12-02 14:45+0000\n"
|
||||
"Last-Translator: Jan Jurkus (GCE CAD-Service) <ict@gcecad-service.nl>\n"
|
||||
"Language-Team: Dutch\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_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:325
|
||||
#, python-format
|
||||
msgid "Dutch Girotel - Kommagescheiden"
|
||||
msgstr "Nederlands Girotel - Kommagescheiden"
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:327
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Girotel - Kommagescheiden format is basicly a MS Excel CSV "
|
||||
"format.\n"
|
||||
msgstr ""
|
||||
"Het Nederlandse Girotel - kommagescheiden formaat is in opzet een MS Excel "
|
||||
"CSV-formaat.\n"
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:103
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Ongeldige transactieregel: %d kolommen verwacht, %d aangetroffen"
|
||||
38
__unported__/account_banking_nl_girotel/i18n/pt_BR.po
Normal file
38
__unported__/account_banking_nl_girotel/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 15:54+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:33+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_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:325
|
||||
#, python-format
|
||||
msgid "Dutch Girotel - Kommagescheiden"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:327
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Girotel - Kommagescheiden format is basicly a MS Excel CSV "
|
||||
"format.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_girotel
|
||||
#: code:addons/account_banking_nl_girotel/girotel.py:103
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
2
__unported__/account_banking_nl_ing/__init__.py
Normal file
2
__unported__/account_banking_nl_ing/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import ing
|
||||
51
__unported__/account_banking_nl_ing/__openerp__.py
Normal file
51
__unported__/account_banking_nl_ing/__openerp__.py
Normal file
@@ -0,0 +1,51 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 Therp BV (<http://therp.nl>)
|
||||
# (C) 2011 Smile BV (<http://smile.fr>)
|
||||
#
|
||||
# Based on account-banking
|
||||
# (C) 2009 - 2011 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': 'ING (NL) Bank Statements Import',
|
||||
'version': '0.1.140',
|
||||
'license': 'AGPL-3',
|
||||
'author': ['Smile', 'Therp BV', 'EduSense BV'],
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Module to import Dutch ING bank format transaction files. The format covered
|
||||
is the CSV format with either 'dd-mm-yyyy' or 'yyyymmdd' date syntax.
|
||||
|
||||
As the ING bank does not provide detailed specification concerning possible
|
||||
values and their meaning for the fields in the CSV file format, the statements
|
||||
are parsed according to an educated guess based on incomplete information.
|
||||
You can contact the banking-addons developers through their launchpad page and
|
||||
help improve the performance of this import filter on
|
||||
https://launchpad.net/banking-addons.
|
||||
|
||||
Note that imported bank transfers are organized in statements covering periods
|
||||
of one week, even if the imported files cover a different period.
|
||||
|
||||
This modules contains no logic, just an import filter for account_banking.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_ing
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:55+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:55+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_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:257
|
||||
#, python-format
|
||||
msgid "ING Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:258
|
||||
#, python-format
|
||||
msgid "The Dutch ING format is basicly a MS Excel CSV format. It is specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:62
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
|
||||
41
__unported__/account_banking_nl_ing/i18n/nl.po
Normal file
41
__unported__/account_banking_nl_ing/i18n/nl.po
Normal file
@@ -0,0 +1,41 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_ing
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0.3\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:55+0000\n"
|
||||
"PO-Revision-Date: 2013-12-03 11:10+0000\n"
|
||||
"Last-Translator: Jan Jurkus (GCE CAD-Service) <ict@gcecad-service.nl>\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_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:257
|
||||
#, python-format
|
||||
msgid "ING Bank"
|
||||
msgstr "ING Bank"
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:258
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch ING format is basicly a MS Excel CSV format. It is specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
msgstr ""
|
||||
"Het Nederlandse ING formaat is in opzet een MS Excel CSV-formaat. Het is\n"
|
||||
"duidelijk afwijkend van het Nederlandse multibank-formaat. Transacties zijn\n"
|
||||
"niet gebonden aan bankafschriften.\n"
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:62
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Ongeldige transactieregel: %d kolommen verwacht, %d aangetroffen"
|
||||
39
__unported__/account_banking_nl_ing/i18n/pt_BR.po
Normal file
39
__unported__/account_banking_nl_ing/i18n/pt_BR.po
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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:55+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:31+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_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:257
|
||||
#, python-format
|
||||
msgid "ING Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:258
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch ING format is basicly a MS Excel CSV format. It is specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_ing
|
||||
#: code:addons/account_banking_nl_ing/ing.py:62
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
288
__unported__/account_banking_nl_ing/ing.py
Normal file
288
__unported__/account_banking_nl_ing/ing.py
Normal file
@@ -0,0 +1,288 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 Smile (<http://smile.fr>).
|
||||
# Copyright (C) 2011 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# Based on the multibank module by EduSense BV
|
||||
# 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.addons.account_banking.parsers import models
|
||||
from openerp.addons.account_banking.parsers.convert import str2date
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import re
|
||||
import csv
|
||||
|
||||
__all__ = ['parser']
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
"""
|
||||
First line states the legend
|
||||
"Datum","Naam / Omschrijving","Rekening","Tegenrekening","Code","Af Bij",\
|
||||
"Bedrag (EUR)","MutatieSoort","Mededelingen
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class transaction_message(object):
|
||||
'''
|
||||
A auxiliary class to validate and coerce read values
|
||||
'''
|
||||
attrnames = [
|
||||
'date', 'remote_owner', 'local_account', 'remote_account',
|
||||
'transfer_type', 'debcred', 'transferred_amount',
|
||||
'transfer_type_verbose', 'message'
|
||||
]
|
||||
|
||||
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)))
|
||||
self.__dict__.update(dict(zip(self.attrnames, values)))
|
||||
# for lack of a standardized locale function to parse amounts
|
||||
self.transferred_amount = float(
|
||||
re.sub(',', '.', self.transferred_amount))
|
||||
if self.debcred == 'Af':
|
||||
self.transferred_amount = -self.transferred_amount
|
||||
try:
|
||||
self.execution_date = self.value_date = str2date(self.date,
|
||||
'%Y%m%d')
|
||||
except ValueError:
|
||||
self.execution_date = self.value_date = str2date(self.date,
|
||||
'%d-%m-%Y')
|
||||
self.statement_id = '' # self.value_date.strftime('%Yw%W')
|
||||
self.id = str(subno).zfill(4)
|
||||
self.reference = ''
|
||||
# Normalize basic account numbers
|
||||
self.remote_account = self.remote_account.replace('.', '').zfill(10)
|
||||
self.local_account = self.local_account.replace('.', '').zfill(10)
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
'''
|
||||
Implementation of transaction communication class for account_banking.
|
||||
'''
|
||||
attrnames = ['local_account', 'remote_account',
|
||||
'remote_owner', 'transferred_amount',
|
||||
'execution_date', 'value_date', 'transfer_type',
|
||||
'id', 'reference', 'statement_id', 'message',
|
||||
]
|
||||
|
||||
"""
|
||||
Presumably the same transaction types occur in the MT940 format of ING.
|
||||
From www.ing.nl/Images/MT940_Technische_handleiding_tcm7-69020.pdf
|
||||
|
||||
"""
|
||||
type_map = {
|
||||
|
||||
'AC': bt.ORDER, # Acceptgiro
|
||||
'BA': bt.PAYMENT_TERMINAL, # Betaalautomaattransactie
|
||||
'CH': bt.ORDER, # Cheque
|
||||
'DV': bt.ORDER, # Diversen
|
||||
'FL': bt.BANK_TERMINAL, # Filiaalboeking, concernboeking
|
||||
'GF': bt.ORDER, # Telefonisch bankieren
|
||||
'GM': bt.BANK_TERMINAL, # Geldautomaat
|
||||
'GT': bt.ORDER, # Internetbankieren
|
||||
'IC': bt.DIRECT_DEBIT, # Incasso
|
||||
'OV': bt.ORDER, # Overschrijving
|
||||
'PK': bt.BANK_TERMINAL, # Opname kantoor
|
||||
'PO': bt.ORDER, # Periodieke overschrijving
|
||||
'ST': bt.BANK_TERMINAL, # Storting (eigen rekening of derde)
|
||||
'VZ': bt.ORDER, # Verzamelbetaling
|
||||
'NO': bt.STORNO, # Storno
|
||||
}
|
||||
|
||||
# global expression for matching storno references
|
||||
ref_expr = re.compile('REF[\*:]([0-9A-Z-z_-]+)')
|
||||
# match references for Acceptgiro's through Internet banking
|
||||
kn_expr = re.compile('KN: ([^ ]+)')
|
||||
|
||||
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))
|
||||
# self.message = ''
|
||||
# Decompose structured messages
|
||||
self.parse_message()
|
||||
# Adaptations to direct debit orders ands stornos
|
||||
if self.transfer_type == 'DV' and self.transferred_amount < 0:
|
||||
res = self.ref_expr.search(self.remote_owner)
|
||||
if res:
|
||||
self.transfer_type = 'NO'
|
||||
self.reference = res.group(1)
|
||||
self.remote_owner = False
|
||||
else:
|
||||
res = self.ref_expr.search(self.message)
|
||||
if res:
|
||||
self.transfer_type = 'NO'
|
||||
self.reference = res.group(1)
|
||||
if self.transfer_type == 'IC':
|
||||
if self.transferred_amount > 0:
|
||||
self.reference = self.remote_owner
|
||||
else:
|
||||
self.transfer_type = 'NO'
|
||||
self.message = self.remote_owner + self.message
|
||||
res = self.ref_expr.search(self.message)
|
||||
if res:
|
||||
self.reference = res.group(1)
|
||||
self.storno_retry = True
|
||||
self.remote_owner = False
|
||||
if self.transfer_type == 'GT':
|
||||
res = self.kn_expr.search(self.message)
|
||||
if res:
|
||||
self.reference = res.group(1)
|
||||
if self.transfer_type == 'AC':
|
||||
self.parse_acceptgiro()
|
||||
if self.message and not self.reference:
|
||||
self.reference = self.message
|
||||
|
||||
def parse_acceptgiro(self):
|
||||
"""
|
||||
Entries of type 'Acceptgiro' can contain the reference
|
||||
in the 'name' column, as well as full address information
|
||||
in the 'message' column'
|
||||
"""
|
||||
before = False
|
||||
if self.remote_owner.startswith('KN: '):
|
||||
self.reference = self.remote_owner[4:]
|
||||
self.remote_owner = ''
|
||||
if 'KN: ' in self.message:
|
||||
index = self.message.index('KN: ')
|
||||
before = self.message[:index]
|
||||
self.message = self.message[index:]
|
||||
expression = (
|
||||
"^\s*(KN:\s*(?P<kn>[^\s]+))?(\s*)"
|
||||
"(?P<navr>NAVR:\s*[^\s]+)?(\s*)(?P<after>.*?)$")
|
||||
msg_match = re.match(expression, self.message)
|
||||
after = msg_match.group('after')
|
||||
kn = msg_match.group('kn')
|
||||
navr = msg_match.group('navr')
|
||||
if kn:
|
||||
self.reference = kn[4:]
|
||||
self.message = 'Acceptgiro %s' % (navr or '')
|
||||
if after:
|
||||
parts = [after[i:i+33] for i in range(0, len(after), 33)]
|
||||
if parts and not self.remote_owner:
|
||||
self.remote_owner = parts.pop(0).strip()
|
||||
if parts:
|
||||
self.remote_owner_address = [parts.pop(0).strip()]
|
||||
if parts:
|
||||
zip_city = parts.pop(0).strip()
|
||||
zip_match = re.match(
|
||||
"^(?P<zipcode>[^ ]{6})\s+(?P<city>.*?)$", zip_city)
|
||||
if zip_match:
|
||||
self.remote_owner_postalcode = zip_match.group('zipcode')
|
||||
self.remote_owner_city = zip_match.group('city')
|
||||
if before and not self.remote_owner_city:
|
||||
self.remote_owner_city = before.strip()
|
||||
|
||||
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 [
|
||||
'BA', 'FL', 'GM', 'IC', 'PK', 'ST']:
|
||||
self.error_message = (
|
||||
"No remote account for transaction type %s" %
|
||||
self.transfer_type)
|
||||
return not self.error_message
|
||||
|
||||
def parse_message(self):
|
||||
'''
|
||||
Parse structured message parts into appropriate attributes.
|
||||
No processing done here for Triodos, maybe later.
|
||||
'''
|
||||
|
||||
|
||||
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
|
||||
try:
|
||||
self.date = str2date(msg.date, '%Y%m%d')
|
||||
except ValueError:
|
||||
self.date = str2date(msg.date, '%d-%m-%Y')
|
||||
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 = 'ING'
|
||||
country_code = 'NL'
|
||||
name = _('ING Bank')
|
||||
doc = _('''\
|
||||
The Dutch ING format is basicly a MS Excel CSV format. It is specifically
|
||||
distinct from the Dutch multibank format. Transactions are not tied to Bank
|
||||
Statements.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
dialect = csv.excel()
|
||||
dialect.quotechar = '"'
|
||||
dialect.delimiter = ','
|
||||
lines = data.split('\n')
|
||||
# Transaction lines are not numbered, so keep a tracer
|
||||
subno = 0
|
||||
statement_id = False
|
||||
for line in csv.reader(lines, dialect=dialect):
|
||||
# Skip empty (last) lines and header line
|
||||
if not line or line[0] == 'Datum':
|
||||
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
|
||||
28
__unported__/account_banking_nl_multibank/__init__.py
Normal file
28
__unported__/account_banking_nl_multibank/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- 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 multibank
|
||||
36
__unported__/account_banking_nl_multibank/__openerp__.py
Normal file
36
__unported__/account_banking_nl_multibank/__openerp__.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Account Banking - NL Multibank import',
|
||||
'version': '0.62',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'EduSense BV',
|
||||
'website': 'http://www.edusense.nl',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Module to import Dutch Multibank format transation files.
|
||||
|
||||
This modules contains no logic, just an import filter for account_banking.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_multibank
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:56+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:56+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_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:292
|
||||
#, python-format
|
||||
msgid "The Dutch Banking Tools format is basicly a MS Excel CSV format.\n"
|
||||
"There are two sub formats: MS Excel format and MS-Excel 2004 format.\n"
|
||||
"Both formats are covered with this parser. All transactions are tied\n"
|
||||
"to Bank Statements.\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:291
|
||||
#, python-format
|
||||
msgid "Dutch Banking Tools"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:77
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
|
||||
39
__unported__/account_banking_nl_multibank/i18n/en.po
Normal file
39
__unported__/account_banking_nl_multibank/i18n/en.po
Normal file
@@ -0,0 +1,39 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_multibank
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.7\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:56+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 17:50+0000\n"
|
||||
"Last-Translator: <>\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_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:292
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Banking Tools format is basicly a MS Excel CSV format.\n"
|
||||
"There are two sub formats: MS Excel format and MS-Excel 2004 format.\n"
|
||||
"Both formats are covered with this parser. All transactions are tied\n"
|
||||
"to Bank Statements.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:291
|
||||
#, python-format
|
||||
msgid "Dutch Banking Tools"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:77
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
43
__unported__/account_banking_nl_multibank/i18n/nl.po
Normal file
43
__unported__/account_banking_nl_multibank/i18n/nl.po
Normal file
@@ -0,0 +1,43 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_multibank
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.7\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2013-10-25 15:56+0000\n"
|
||||
"PO-Revision-Date: 2013-12-03 11:10+0000\n"
|
||||
"Last-Translator: Jan Jurkus (GCE CAD-Service) <ict@gcecad-service.nl>\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_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:292
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Banking Tools format is basicly a MS Excel CSV format.\n"
|
||||
"There are two sub formats: MS Excel format and MS-Excel 2004 format.\n"
|
||||
"Both formats are covered with this parser. All transactions are tied\n"
|
||||
"to Bank Statements.\n"
|
||||
msgstr ""
|
||||
"Het Nederlandse Multibank-formaat is in opzet een MS Excel CSV-formaat.\n"
|
||||
"Er zijn twee subformaten: MS Excel formaat en MS Excel 2004 formaat.\n"
|
||||
"Beide formaten worden ondersteund met deze inlezer. Alle transacties zijn\n"
|
||||
"gekoppeld aan bankafschriften\n"
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:291
|
||||
#, python-format
|
||||
msgid "Dutch Banking Tools"
|
||||
msgstr "Nederlands MultiBank-formaat"
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:77
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Ongeldige transactieregel: %d kolommen verwacht, %d aangetroffen"
|
||||
40
__unported__/account_banking_nl_multibank/i18n/pt_BR.po
Normal file
40
__unported__/account_banking_nl_multibank/i18n/pt_BR.po
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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:56+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:30+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_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:292
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Banking Tools format is basicly a MS Excel CSV format.\n"
|
||||
"There are two sub formats: MS Excel format and MS-Excel 2004 format.\n"
|
||||
"Both formats are covered with this parser. All transactions are tied\n"
|
||||
"to Bank Statements.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:291
|
||||
#, python-format
|
||||
msgid "Dutch Banking Tools"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_multibank
|
||||
#: code:addons/account_banking_nl_multibank/multibank.py:77
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
333
__unported__/account_banking_nl_multibank/multibank.py
Normal file
333
__unported__/account_banking_nl_multibank/multibank.py
Normal file
@@ -0,0 +1,333 @@
|
||||
# -*- 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 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 account_banking.parsers import models
|
||||
from account_banking.parsers.convert import str2date
|
||||
from account_banking.sepa import postalcode
|
||||
from tools.translate import _
|
||||
import csv
|
||||
|
||||
__all__ = ['parser']
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
|
||||
|
||||
class transaction_message(object):
|
||||
'''
|
||||
A auxiliary class to validate and coerce read values
|
||||
'''
|
||||
attrnames = [
|
||||
'date', 'local_account', 'remote_account', 'remote_owner', 'u1', 'u2',
|
||||
'u3', 'local_currency', 'start_balance', 'remote_currency',
|
||||
'transferred_amount', 'execution_date', 'value_date', 'nr1',
|
||||
'transfer_type', 'nr2', 'reference', 'message', 'statement_id'
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def clean_account(accountno):
|
||||
'''
|
||||
There seems to be some SEPA movement in data: account numbers
|
||||
get prefixed by zeroes as in BBAN. Convert those to 'old' local
|
||||
account numbers
|
||||
|
||||
Edit: All account number now follow the BBAN scheme. As SNS Bank,
|
||||
from which this module was re-engineered, follows the Dutch
|
||||
Banking Tools regulations, it is considered to be used by all banks
|
||||
in the Netherlands which comply to it. If not, please notify us.
|
||||
'''
|
||||
if len(accountno) == 10: # Invalid: longest number is 9
|
||||
accountno = accountno[1:]
|
||||
# 9-scheme or 7-scheme?
|
||||
stripped = accountno.lstrip('0')
|
||||
if len(stripped) <= 7:
|
||||
accountno = stripped
|
||||
return accountno
|
||||
|
||||
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))
|
||||
)
|
||||
self.__dict__.update(dict(zip(self.attrnames, values)))
|
||||
self.start_balance = float(self.start_balance)
|
||||
self.transferred_amount = float(self.transferred_amount)
|
||||
self.execution_date = str2date(self.execution_date, '%d-%m-%Y')
|
||||
self.value_date = str2date(self.value_date, '%d-%m-%Y')
|
||||
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', 'remote_account',
|
||||
'remote_owner', 'remote_currency', 'transferred_amount',
|
||||
'execution_date', 'value_date', 'transfer_type',
|
||||
'reference', 'message', 'statement_id', 'id',
|
||||
]
|
||||
|
||||
type_map = {
|
||||
'ACC': bt.ORDER,
|
||||
'BEA': bt.PAYMENT_TERMINAL,
|
||||
'BTL': bt.ORDER,
|
||||
'DIV': bt.ORDER,
|
||||
'IDB': bt.PAYMENT_TERMINAL,
|
||||
'INC': bt.DIRECT_DEBIT,
|
||||
'IOB': bt.ORDER,
|
||||
'KNT': bt.BANK_COSTS,
|
||||
'KST': bt.BANK_COSTS,
|
||||
'OPN': bt.BANK_TERMINAL,
|
||||
'OVS': bt.ORDER,
|
||||
'PRV': bt.BANK_COSTS,
|
||||
'TEL': bt.ORDER,
|
||||
}
|
||||
|
||||
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))
|
||||
# Decompose structured messages
|
||||
self.parse_message()
|
||||
# Set reference when bank costs
|
||||
if self.type == bt.BANK_COSTS:
|
||||
self.reference = self.message[:32].rstrip()
|
||||
|
||||
def is_valid(self):
|
||||
'''
|
||||
There are a few situations that can be signaled as 'invalid' but are
|
||||
valid nontheless:
|
||||
|
||||
1. Transfers from one account to another under the same account holder
|
||||
get not always a remote_account and remote_owner. They have their
|
||||
transfer_type set to 'PRV'.
|
||||
|
||||
2. Invoices from the bank itself are communicated through statements.
|
||||
These too have no remote_account and no remote_owner. They have a
|
||||
transfer_type set to 'KST', 'KNT' or 'DIV'.
|
||||
|
||||
3. Transfers sent through the 'International Transfers' system get
|
||||
their feedback rerouted through a statement, which is not designed to
|
||||
hold the extra fields needed. These transfers have their transfer_type
|
||||
set to 'BTL'.
|
||||
|
||||
4. Cash payments with debit cards are not seen as a transfer between
|
||||
accounts, but as a cash withdrawal. These withdrawals have their
|
||||
transfer_type set to 'BEA'.
|
||||
|
||||
5. Cash withdrawals from banks are too not seen as a transfer between
|
||||
two accounts - the cash exits the banking system. These withdrawals
|
||||
have their transfer_type set to 'OPN'.
|
||||
'''
|
||||
return ((
|
||||
self.transferred_amount and self.execution_date
|
||||
and self.value_date)
|
||||
and (self.remote_account or self.transfer_type in [
|
||||
'KST', 'PRV', 'BTL', 'BEA', 'OPN', 'KNT', 'DIV'
|
||||
] and not self.error_message))
|
||||
|
||||
def parse_message(self):
|
||||
'''
|
||||
Parse structured message parts into appropriate attributes
|
||||
'''
|
||||
if self.transfer_type == 'ACC':
|
||||
# Accept Giro - structured message payment
|
||||
# First part of message is redundant information - strip it
|
||||
msg = self.message[self.message.index('navraagnr.'):]
|
||||
self.message = ' '.join(msg.split())
|
||||
|
||||
elif self.transfer_type == 'BEA':
|
||||
# Payment through payment terminal
|
||||
# Remote owner is part of message, while remote_owner is set
|
||||
# to the intermediate party, which we don't need.
|
||||
self.remote_owner = self.message[:23].rstrip()
|
||||
self.remote_owner_city = self.message[23:31].rstrip()
|
||||
self.message = self.message[31:]
|
||||
|
||||
elif self.transfer_type == 'BTL':
|
||||
# International transfers.
|
||||
# Remote party is encoded in message, including bank costs
|
||||
parts = self.message.split(' ')
|
||||
last = False
|
||||
for part in parts:
|
||||
if part.startswith('bedrag. '):
|
||||
# The ordered transferred amount
|
||||
currency, amount = part.split('. ')[1].split()
|
||||
if self.remote_currency != currency.upper():
|
||||
self.error_message = (
|
||||
'Remote currency in message differs from '
|
||||
'transaction.'
|
||||
)
|
||||
else:
|
||||
self.local_amount = float(amount)
|
||||
elif part.startswith('koers. '):
|
||||
# The currency rate used
|
||||
self.exchange_rate = float(part.split('. ')[1])
|
||||
elif part.startswith('transfer prov. '):
|
||||
# The provision taken by the bank
|
||||
# Note that the amount must be negated to get the right
|
||||
# direction
|
||||
currency, costs = part.split('. ')[1].split()
|
||||
self.provision_costs = -float(costs)
|
||||
self.provision_costs_currency = currency.upper()
|
||||
self.provision_costs_description = 'Transfer costs'
|
||||
elif part.startswith('aan. '):
|
||||
# The remote owner
|
||||
self.remote_owner = part.replace('aan. ', '').rstrip()
|
||||
last = True
|
||||
elif last:
|
||||
# Last parts are address lines
|
||||
address = part.rstrip()
|
||||
iso, pc, city = postalcode.split(address)
|
||||
if pc and city:
|
||||
self.remote_owner_postalcode = pc
|
||||
self.remote_owner_city = city.strip()
|
||||
self.remote_owner_country_code = iso
|
||||
else:
|
||||
self.remote_owner_address.append(address)
|
||||
|
||||
elif self.transfer_type == 'DIV':
|
||||
# A diverse transfer. Message can be anything, but has some
|
||||
# structure
|
||||
ptr = self.message.find(self.reference)
|
||||
if ptr > 0:
|
||||
address = self.message[:ptr].rstrip().split(' ')
|
||||
length = len(address)
|
||||
if length >= 1:
|
||||
self.remote_owner = address[0]
|
||||
if length >= 2:
|
||||
self.remote_owner_address.append(address[1])
|
||||
if length >= 3:
|
||||
self.remote_owner_city = address[2]
|
||||
self.message = self.message[ptr:].rstrip()
|
||||
if self.message.find('transactiedatum') >= 0:
|
||||
rest = self.message.split('transactiedatum')
|
||||
if rest[1].startswith('* '):
|
||||
self.execution_date = str2date(rest[1][2:], '%d-%m-%Y')
|
||||
else:
|
||||
self.execution_date = str2date(rest[1][2:], '%d %m %Y')
|
||||
self.message = rest[0].rstrip()
|
||||
|
||||
elif self.transfer_type == 'IDB':
|
||||
# Payment by iDeal transaction
|
||||
# Remote owner can be part of message, while remote_owner can be
|
||||
# set to the intermediate party, which we don't need.
|
||||
parts = self.message.split(' ')
|
||||
# Second part: structured id, date & time
|
||||
subparts = parts[1].split()
|
||||
datestr = '-'.join(subparts[1:4])
|
||||
timestr = ':'.join(subparts[4:])
|
||||
parts[1] = ' '.join([subparts[0], datestr, timestr])
|
||||
# Only replace reference when redundant
|
||||
if self.reference == parts[0]:
|
||||
if parts[2]:
|
||||
self.reference = ' '.join([parts[2], datestr, timestr])
|
||||
else:
|
||||
self.reference += ' '.join([datestr, timestr])
|
||||
# Optional fourth path contains remote owners name
|
||||
if len(parts) > 3 and parts[-1].find(self.remote_owner) < 0:
|
||||
self.remote_owner = parts[-1].rstrip()
|
||||
parts = parts[:-1]
|
||||
self.message = ' '.join(parts)
|
||||
|
||||
|
||||
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, '%d-%m-%Y')
|
||||
self.start_balance = self.end_balance = 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 = 'NLBT'
|
||||
country_code = 'NL'
|
||||
name = _('Dutch Banking Tools')
|
||||
doc = _('''\
|
||||
The Dutch Banking Tools format is basicly a MS Excel CSV format.
|
||||
There are two sub formats: MS Excel format and MS-Excel 2004 format.
|
||||
Both formats are covered with this parser. All transactions are tied
|
||||
to Bank Statements.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
dialect = csv.excel()
|
||||
dialect.quotechar = '"'
|
||||
dialect.delimiter = ';'
|
||||
lines = data.split('\n')
|
||||
# Probe first record to find out which format we are parsing.
|
||||
if lines and lines[0].count(',') > lines[0].count(';'):
|
||||
dialect.delimiter = ','
|
||||
if lines and lines[0].count("'") > lines[0].count('"'):
|
||||
dialect.quotechar = "'"
|
||||
# Transaction lines are not numbered, so keep a tracer
|
||||
subno = 0
|
||||
for line in csv.reader(lines, dialect=dialect):
|
||||
# Skip empty (last) lines
|
||||
if not line:
|
||||
continue
|
||||
subno += 1
|
||||
msg = transaction_message(line, subno)
|
||||
if stmnt and stmnt.id != msg.statement_id:
|
||||
result.append(stmnt)
|
||||
stmnt = None
|
||||
subno = 0
|
||||
if not stmnt:
|
||||
stmnt = statement(msg)
|
||||
else:
|
||||
stmnt.import_transaction(msg)
|
||||
result.append(stmnt)
|
||||
return result
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
30
__unported__/account_banking_nl_triodos/__init__.py
Normal file
30
__unported__/account_banking_nl_triodos/__init__.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 - 2011 EduSense BV (<http://www.edusense.nl>)
|
||||
# and Therp BV (<http://therp.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
|
||||
# or Therp 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 triodos
|
||||
45
__unported__/account_banking_nl_triodos/__openerp__.py
Normal file
45
__unported__/account_banking_nl_triodos/__openerp__.py
Normal file
@@ -0,0 +1,45 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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': 'Triodos (NL) Bank Statements Import',
|
||||
'version': '0.92',
|
||||
'license': 'AGPL-3',
|
||||
'author': ['Therp BV', 'EduSense BV'],
|
||||
'website': 'https://launchpad.net/account-banking',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking'],
|
||||
'description': '''
|
||||
Module to import Dutch Triodos bank format transation files (CSV format).
|
||||
|
||||
As the Triodos bank does not provide detailed specification concerning possible
|
||||
values and their meaning for the fields in the CSV file format, the statements
|
||||
are parsed according to an educated guess based on incomplete information.
|
||||
You can contact the account-banking developers through their launchpad page and
|
||||
help improve the performance of this import filter on
|
||||
https://launchpad.net/account-banking.
|
||||
|
||||
Note that imported bank transfers are organized in statements covering periods
|
||||
of one week, even if the imported files cover a different period.
|
||||
|
||||
This modules contains no logic, just an import filter for account_banking.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_triodos
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:57+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:57+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_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:183
|
||||
#, python-format
|
||||
msgid "Triodos Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:184
|
||||
#, python-format
|
||||
msgid "The Dutch Triodos format is basicly a MS Excel CSV format. It is specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:59
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
|
||||
43
__unported__/account_banking_nl_triodos/i18n/en.po
Normal file
43
__unported__/account_banking_nl_triodos/i18n/en.po
Normal file
@@ -0,0 +1,43 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_triodos
|
||||
#
|
||||
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:57+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 17:51+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_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:183
|
||||
#, python-format
|
||||
msgid "Triodos Bank"
|
||||
msgstr "Triodos Bank"
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:184
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Triodos format is basicly a MS Excel CSV format. It is "
|
||||
"specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
msgstr ""
|
||||
"The Dutch Triodos format is basicly a MS Excel CSV format. It is "
|
||||
"specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:59
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Invalid transaction line: expected %d columns, found %d"
|
||||
43
__unported__/account_banking_nl_triodos/i18n/nl.po
Normal file
43
__unported__/account_banking_nl_triodos/i18n/nl.po
Normal file
@@ -0,0 +1,43 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_nl_triodos
|
||||
#
|
||||
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:57+0000\n"
|
||||
"PO-Revision-Date: 2013-12-03 11:15+0000\n"
|
||||
"Last-Translator: Jan Jurkus (GCE CAD-Service) <ict@gcecad-service.nl>\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_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:183
|
||||
#, python-format
|
||||
msgid "Triodos Bank"
|
||||
msgstr "Triodosbank"
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:184
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Triodos format is basicly a MS Excel CSV format. It is "
|
||||
"specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
msgstr ""
|
||||
"Het Nederlandse Triodos-formaat is in opzet een MS Excel CSV-formaat. Het "
|
||||
"is\n"
|
||||
"duidelijk afwijkend van het Nederlandse multibank-formaat. Transacties zijn\n"
|
||||
"niet gebonden aan bankafschriften.\n"
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:59
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr "Ongeldige transactieregel: %d kolommen verwacht, %d aangetroffen"
|
||||
40
__unported__/account_banking_nl_triodos/i18n/pt_BR.po
Normal file
40
__unported__/account_banking_nl_triodos/i18n/pt_BR.po
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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:57+0000\n"
|
||||
"PO-Revision-Date: 2013-12-25 12:29+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_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:183
|
||||
#, python-format
|
||||
msgid "Triodos Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:184
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The Dutch Triodos format is basicly a MS Excel CSV format. It is "
|
||||
"specifically\n"
|
||||
"distinct from the Dutch multibank format. Transactions are not tied to Bank\n"
|
||||
"Statements.\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_nl_triodos
|
||||
#: code:addons/account_banking_nl_triodos/triodos.py:59
|
||||
#, python-format
|
||||
msgid "Invalid transaction line: expected %d columns, found %d"
|
||||
msgstr ""
|
||||
229
__unported__/account_banking_nl_triodos/triodos.py
Normal file
229
__unported__/account_banking_nl_triodos/triodos.py
Normal file
@@ -0,0 +1,229 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>),
|
||||
# 2011 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 account_banking.parsers import models
|
||||
from account_banking.parsers.convert import str2date
|
||||
from tools.translate import _
|
||||
|
||||
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 = [
|
||||
'date', 'local_account', 'transferred_amount', 'debcred',
|
||||
'remote_owner', 'remote_account', 'transfer_type', 'reference',
|
||||
]
|
||||
|
||||
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)))
|
||||
self.__dict__.update(dict(zip(self.attrnames, values)))
|
||||
# for lack of a standardized locale function to parse amounts
|
||||
self.transferred_amount = float(
|
||||
re.sub(',', '.', re.sub('\.', '', self.transferred_amount)))
|
||||
if self.debcred == 'Debet':
|
||||
self.transferred_amount = -self.transferred_amount
|
||||
self.execution_date = str2date(self.date, '%d-%m-%Y')
|
||||
self.value_date = str2date(self.date, '%d-%m-%Y')
|
||||
self.statement_id = ''
|
||||
self.id = str(subno).zfill(4)
|
||||
# Normalize basic account numbers
|
||||
self.remote_account = self.remote_account.replace('.', '').zfill(10)
|
||||
self.local_account = self.local_account.replace('.', '').zfill(10)
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
'''
|
||||
Implementation of transaction communication class for account_banking.
|
||||
'''
|
||||
attrnames = [
|
||||
'local_account',
|
||||
'remote_account',
|
||||
'remote_owner',
|
||||
'transferred_amount',
|
||||
'execution_date',
|
||||
'value_date',
|
||||
'transfer_type',
|
||||
'reference',
|
||||
'id',
|
||||
]
|
||||
|
||||
type_map = {
|
||||
# retrieved from online help in the Triodos banking application
|
||||
'AC': bt.ORDER, # Acceptgiro gecodeerd
|
||||
'AN': bt.ORDER, # Acceptgiro ongecodeerd
|
||||
'AT': bt.ORDER, # Acceptgiro via internet
|
||||
'BA': bt.PAYMENT_TERMINAL, # Betaalautomaat
|
||||
'CHIP': bt.BANK_TERMINAL, # Chipknip
|
||||
# 'CO': # Correctie
|
||||
'DB': bt.ORDER, # Diskettebetaling
|
||||
# 'DV': # Dividend
|
||||
'EI': bt.DIRECT_DEBIT, # Europese Incasso
|
||||
'EICO': bt.DIRECT_DEBIT, # Europese Incasso Correctie
|
||||
'EIST': bt.ORDER, # Europese Incasso Storno
|
||||
'ET': bt.ORDER, # Europese Transactie
|
||||
'ETST': bt.ORDER, # Europese Transactie Storno
|
||||
'GA': bt.BANK_TERMINAL, # Geldautomaat
|
||||
'IB': bt.ORDER, # Interne Boeking
|
||||
'IC': bt.DIRECT_DEBIT, # Incasso
|
||||
'ID': bt.ORDER, # iDeal-betaling
|
||||
'IT': bt.ORDER, # Internet transactie
|
||||
'KN': bt.BANK_COSTS, # Kosten
|
||||
'KO': bt.BANK_TERMINAL, # Kasopname
|
||||
# 'KS': # Kwaliteitsstoring
|
||||
'OV': bt.ORDER, # Overboeking. NB: can also be bt.BANK_COSTS
|
||||
# when no remote_account specified!
|
||||
'PO': bt.ORDER, # Periodieke Overboeking
|
||||
'PR': bt.BANK_COSTS, # Provisie
|
||||
# 'RE': # Rente
|
||||
# 'RS': # Renteschenking
|
||||
'ST': bt.ORDER, # Storno
|
||||
'TG': bt.ORDER, # Telegiro
|
||||
# 'VL': # Vaste Lening
|
||||
'VO': bt.DIRECT_DEBIT, # Vordering overheid
|
||||
'VV': bt.ORDER, # Vreemde valuta
|
||||
}
|
||||
|
||||
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))
|
||||
self.message = ''
|
||||
# Decompose structured messages
|
||||
self.parse_message()
|
||||
if (self.transfer_type == 'OV'
|
||||
and not self.remote_account
|
||||
and not self.remote_owner):
|
||||
self.transfer_type = 'KN'
|
||||
|
||||
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 [
|
||||
'KN', 'TG', 'GA', 'BA', 'CHIP']:
|
||||
self.error_message = (
|
||||
"No remote account for transaction type %s" %
|
||||
self.transfer_type)
|
||||
return not self.error_message
|
||||
|
||||
def parse_message(self):
|
||||
'''
|
||||
Parse structured message parts into appropriate attributes.
|
||||
'''
|
||||
# IBAN accounts are prefixed by BIC
|
||||
if self.remote_account:
|
||||
parts = self.remote_account.split(' ')
|
||||
if len(parts) == 2:
|
||||
self.remote_bank_bic = parts[0]
|
||||
self.remote_account = parts[1]
|
||||
|
||||
|
||||
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, '%d-%m-%Y')
|
||||
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 = 'TRIOD'
|
||||
country_code = 'NL'
|
||||
name = _('Triodos Bank')
|
||||
doc = _('''\
|
||||
The Dutch Triodos format is basicly a MS Excel CSV format. It is specifically
|
||||
distinct from the Dutch multibank format. Transactions are not tied to Bank
|
||||
Statements.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
stmnt = None
|
||||
dialect = csv.excel()
|
||||
dialect.quotechar = '"'
|
||||
dialect.delimiter = ','
|
||||
lines = data.split('\n')
|
||||
# Transaction lines are not numbered, so keep a tracer
|
||||
subno = 0
|
||||
# fixed statement id based on import timestamp
|
||||
statement_id = False
|
||||
for line in csv.reader(lines, dialect=dialect):
|
||||
# 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
|
||||
26
__unported__/account_banking_uk_hsbc/__init__.py
Normal file
26
__unported__/account_banking_uk_hsbc/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 account_banking_uk_hsbc
|
||||
import wizard
|
||||
import hsbc_mt940
|
||||
import hsbc_clientid
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
52
__unported__/account_banking_uk_hsbc/__openerp__.py
Normal file
52
__unported__/account_banking_uk_hsbc/__openerp__.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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': 'HSBC Account Banking',
|
||||
'version': '0.5',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'credativ Ltd',
|
||||
'website': 'http://www.credativ.co.uk',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking_payment'],
|
||||
'data': [
|
||||
'account_banking_uk_hsbc.xml',
|
||||
'hsbc_clientid_view.xml',
|
||||
'data/banking_export_hsbc.xml',
|
||||
'wizard/export_hsbc_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'description': '''
|
||||
Module to import HSBC format transation files (S.W.I.F.T MT940) and to export
|
||||
payments for HSBC.net (PAYMUL).
|
||||
|
||||
Currently it is targetting UK market, due to country variances of the MT940 and
|
||||
PAYMUL.
|
||||
|
||||
It is possible to extend this module to work with HSBC.net in other countries
|
||||
and potentially other banks.
|
||||
|
||||
This module adds above import/export filter to the account_banking module.
|
||||
All business logic is in account_banking module.
|
||||
|
||||
Initial release of this module was co-sponsored by Canonical.
|
||||
''',
|
||||
'installable': False,
|
||||
}
|
||||
141
__unported__/account_banking_uk_hsbc/account_banking_uk_hsbc.py
Normal file
141
__unported__/account_banking_uk_hsbc/account_banking_uk_hsbc.py
Normal file
@@ -0,0 +1,141 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 datetime import date
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as OE_DATEFORMAT
|
||||
|
||||
|
||||
class hsbc_export(orm.Model):
|
||||
"""HSBC Export"""
|
||||
_name = 'banking.export.hsbc'
|
||||
_description = __doc__
|
||||
_rec_name = 'execution_date'
|
||||
|
||||
_columns = {
|
||||
'payment_order_ids': fields.many2many(
|
||||
'payment.order',
|
||||
'account_payment_order_hsbc_rel',
|
||||
'banking_export_hsbc_id', 'account_order_id',
|
||||
'Payment Orders',
|
||||
readonly=True),
|
||||
'identification':
|
||||
fields.char('Identification', size=15, readonly=True, select=True),
|
||||
'execution_date':
|
||||
fields.date('Execution Date', readonly=True),
|
||||
'no_transactions':
|
||||
fields.integer('Number of Transactions', readonly=True),
|
||||
'total_amount':
|
||||
fields.float('Total Amount', readonly=True),
|
||||
'date_generated':
|
||||
fields.datetime('Generation Date', readonly=True, select=True),
|
||||
'file':
|
||||
fields.binary('HSBC File', readonly=True),
|
||||
'state':
|
||||
fields.selection([
|
||||
('draft', 'Draft'),
|
||||
('sent', 'Sent'),
|
||||
('done', 'Reconciled'),
|
||||
], 'State', readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'date_generated': lambda *a: date.today().strftime(OE_DATEFORMAT),
|
||||
'state': 'draft',
|
||||
}
|
||||
|
||||
|
||||
class payment_line(orm.Model):
|
||||
"""The standard payment order is using a mixture of details from the
|
||||
partner record and the res.partner.bank record. For, instance, the account
|
||||
holder name is coming from the res.partner.bank record, but the company
|
||||
name and address are coming from the partner address record. This is
|
||||
problematic because the HSBC payment format is validating for alphanumeric
|
||||
characters in the company name and address. So, "Great Company Ltd." and
|
||||
"Great Company s.a." will cause an error because they have full-stops in
|
||||
the name.
|
||||
|
||||
A better approach is to use the name and address details from the
|
||||
res.partner.bank record always. This way, the address details can be
|
||||
sanitized for the payments, whilst being able to print the proper name and
|
||||
address throughout the rest of the system e.g. on invoices.
|
||||
"""
|
||||
|
||||
_inherit = 'payment.line'
|
||||
|
||||
def info_owner(self, cr, uid, ids, name=None, args=None, context=None):
|
||||
|
||||
if not ids:
|
||||
return {}
|
||||
|
||||
result = {}
|
||||
info = ''
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
owner = line.order_id.mode.bank_id
|
||||
|
||||
name = owner.owner_name or owner.partner_id.name
|
||||
st = owner.street and owner.street or ''
|
||||
st1 = '' # no street2 in res.partner.bank
|
||||
zip = owner.zip and owner.zip or ''
|
||||
city = owner.city and owner.city or ''
|
||||
zip_city = zip + ' ' + city
|
||||
cntry = owner.country_id and owner.country_id.name or ''
|
||||
info = name + "\n".join((st + " ", st1, zip_city, cntry))
|
||||
result[line.id] = info
|
||||
return result
|
||||
|
||||
def info_partner(self, cr, uid, ids, name=None, args=None, context=None):
|
||||
if not ids:
|
||||
return {}
|
||||
result = {}
|
||||
info = ''
|
||||
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
partner = line.bank_id
|
||||
|
||||
name = partner.owner_name or partner.partner_id.name
|
||||
st = partner.street and partner.street or ''
|
||||
st1 = '' # no street2 in res.partner.bank
|
||||
zip = partner.zip and partner.zip or ''
|
||||
city = partner.city and partner.city or ''
|
||||
zip_city = zip + ' ' + city
|
||||
cntry = partner.country_id and partner.country_id.name or ''
|
||||
info = name + "\n".join((st + " ", st1, zip_city, cntry))
|
||||
result[line.id] = info
|
||||
|
||||
return result
|
||||
|
||||
# Define the info_partner and info_owner so we can override the methods
|
||||
_columns = {
|
||||
'info_owner': fields.function(
|
||||
info_owner,
|
||||
string="Owner Account",
|
||||
type="text",
|
||||
help='Address of the Main Partner',
|
||||
),
|
||||
'info_partner': fields.function(
|
||||
info_partner,
|
||||
string="Destination Account",
|
||||
type="text",
|
||||
help='Address of the Ordering Customer.'
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) EduSense BV <http://www.edusense.nl>
|
||||
All rights reserved.
|
||||
|
||||
Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>)
|
||||
|
||||
The licence is in the file __openerp__.py
|
||||
|
||||
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Make new view on HSBC exports -->
|
||||
<record id="view_banking_export_hsbc_form" model="ir.ui.view">
|
||||
<field name="name">account.banking.export.hsbc.form</field>
|
||||
<field name="model">banking.export.hsbc</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="HSBC Export">
|
||||
<notebook>
|
||||
<page string="General Information">
|
||||
<separator string="HSBC Information" colspan="4" />
|
||||
<field name="total_amount" />
|
||||
<field name="no_transactions" />
|
||||
<separator string="Processing Information" colspan="4" />
|
||||
<field name="execution_date" />
|
||||
<field name="date_generated" />
|
||||
<newline />
|
||||
<field name="file" colspan="4" />
|
||||
</page>
|
||||
<page string="Payment Orders">
|
||||
<field name="payment_order_ids" colspan="4" nolabel="1">
|
||||
<tree colors="blue:state in ('draft');gray:state in ('cancel','done');black:state in ('open')" string="Payment order">
|
||||
<field name="reference"/>
|
||||
<field name="date_created"/>
|
||||
<field name="date_done"/>
|
||||
<field name="total"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_banking_export_hsbc_tree" model="ir.ui.view">
|
||||
<field name="name">account.banking.export.hsbc.tree</field>
|
||||
<field name="model">banking.export.hsbc</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="HSBC Export">
|
||||
<field name="execution_date" search="2"/>
|
||||
<field name="date_generated" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_account_banking_hsbcs">
|
||||
<field name="name">Generated HSBC files</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">banking.export.hsbc</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- Add a menu item for it -->
|
||||
<menuitem name="Generated HSBC files"
|
||||
id="menu_action_account_banking_exported_hsbc_files"
|
||||
parent="account_banking.menu_finance_banking_actions"
|
||||
action="action_account_banking_hsbcs"
|
||||
sequence="12"
|
||||
/>
|
||||
|
||||
<!-- Create right menu entry to see generated files -->
|
||||
<act_window name="Generated HSBC files"
|
||||
domain="[('payment_order_ids', '=', active_id)]"
|
||||
res_model="banking.export.hsbc"
|
||||
src_model="payment.order"
|
||||
view_type="form"
|
||||
view_mode="tree,form"
|
||||
id="act_banking_export_hsbc_payment_order"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="payment.mode.type" id="export_acm_or_ezone">
|
||||
<field name="name">ACH or EZONE</field>
|
||||
<field name="code">not used</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_uk_hsbc.model_banking_export_hsbc_wizard"/>
|
||||
</record>
|
||||
<record model="payment.mode.type" id="export_faster_payment">
|
||||
<field name="name">Faster Payment</field>
|
||||
<field name="code">not used</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base.bank_normal'),])]" />
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_uk_hsbc.model_banking_export_hsbc_wizard"/>
|
||||
</record>
|
||||
<record model="payment.mode.type" id="export_priority_payment">
|
||||
<field name="name">Priority Payment</field>
|
||||
<field name="code">not used</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_uk_hsbc.model_banking_export_hsbc_wizard"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
49
__unported__/account_banking_uk_hsbc/hsbc_clientid.py
Normal file
49
__unported__/account_banking_uk_hsbc/hsbc_clientid.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
|
||||
class hsbc_clientid(orm.Model):
|
||||
"""
|
||||
Record to hold the HSBCNet Client ID for the company.
|
||||
"""
|
||||
_name = 'banking.hsbc.clientid'
|
||||
_description = 'HSBC Client ID'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True),
|
||||
'clientid': fields.char('Client ID', size=20, required=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'company_id': (
|
||||
lambda self, cr, uid, c:
|
||||
self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id),
|
||||
}
|
||||
|
||||
|
||||
class payment_order(orm.Model):
|
||||
_inherit = 'payment.order'
|
||||
_columns = {
|
||||
'hsbc_clientid_id': fields.many2one(
|
||||
'banking.hsbc.clientid',
|
||||
'HSBC Client ID',
|
||||
required=True,
|
||||
),
|
||||
}
|
||||
|
||||
def _default_hsbc_clientid(self, cr, uid, context=None):
|
||||
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
|
||||
company_id = user.company_id.id
|
||||
|
||||
clientid_ids = self.pool['banking.hsbc.clientid'].search(
|
||||
cr, uid, [('company_id', '=', company_id)]
|
||||
)
|
||||
if len(clientid_ids) == 0:
|
||||
return False
|
||||
else:
|
||||
return clientid_ids[0]
|
||||
|
||||
_defaults = {
|
||||
'hsbc_clientid_id': _default_hsbc_clientid,
|
||||
}
|
||||
76
__unported__/account_banking_uk_hsbc/hsbc_clientid_view.xml
Normal file
76
__unported__/account_banking_uk_hsbc/hsbc_clientid_view.xml
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Add the HSBC Client ID to the Payment Order -->
|
||||
<record id="view_payment_order_form" model="ir.ui.view">
|
||||
<field name="name">payment.order.form</field>
|
||||
<field name="model">payment.order</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="account_payment.view_payment_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_scheduled" position="after">
|
||||
<field name="hsbc_clientid_id" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Form view for HSBC Client ID -->
|
||||
<record id="banking_hsbc_clientid_form" model="ir.ui.view">
|
||||
<field name="name">banking.hsbc.clientid.form</field>
|
||||
<field name="model">banking.hsbc.clientid</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="HSBC Client ID">
|
||||
<group colspan="4">
|
||||
<field name="name" />
|
||||
<field name="company_id" />
|
||||
<field name="clientid" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Tree view for HSBC Client ID -->
|
||||
<record id="banking_hsbc_clientid_tree" model="ir.ui.view">
|
||||
<field name="name">banking.hsbc.clientid.tree</field>
|
||||
<field name="model">banking.hsbc.clientid</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="HSBC Client IDs">
|
||||
<field name="name" />
|
||||
<field name="company_id" />
|
||||
<field name="clientid" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Search view for HSBC Client ID -->
|
||||
<record id="banking_hsbc_clientid_filter" model="ir.ui.view">
|
||||
<field name="name">banking.hsbc.clientid.filter</field>
|
||||
<field name="model">banking.hsbc.clientid</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="HSBC Client IDs">
|
||||
<field name="name"/>
|
||||
<field name="company_id" />
|
||||
<field name="clientid" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for HSBC Client ID -->
|
||||
<record id="banking_hsbc_clientid_action" model="ir.actions.act_window">
|
||||
<field name="name">HSBC Client ID</field>
|
||||
<field name="res_model">banking.hsbc.clientid</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="banking_hsbc_clientid_filter"/>
|
||||
</record>
|
||||
|
||||
<!-- Menu for HSBC Client ID -->
|
||||
<menuitem action="banking_hsbc_clientid_action" id="banking_hsbc_clientid_menu" parent="account.menu_configuration_misc"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
202
__unported__/account_banking_uk_hsbc/hsbc_mt940.py
Normal file
202
__unported__/account_banking_uk_hsbc/hsbc_mt940.py
Normal file
@@ -0,0 +1,202 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 of HSBC data in Swift MT940 format
|
||||
#
|
||||
|
||||
from account_banking.parsers import models
|
||||
from mt940_parser import HSBCParser
|
||||
import re
|
||||
import logging
|
||||
|
||||
bt = models.mem_bank_transaction
|
||||
logger = logging.getLogger('hsbc_mt940')
|
||||
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import orm
|
||||
|
||||
|
||||
def record2float(record, value):
|
||||
if record['creditmarker'][-1] == 'C':
|
||||
return float(record[value])
|
||||
return -float(record[value])
|
||||
|
||||
|
||||
class transaction(models.mem_bank_transaction):
|
||||
|
||||
mapping = {
|
||||
'execution_date': 'valuedate',
|
||||
'value_date': 'valuedate',
|
||||
'local_currency': 'currency',
|
||||
'transfer_type': 'bookingcode',
|
||||
'reference': 'custrefno',
|
||||
'message': 'furtherinfo'
|
||||
}
|
||||
|
||||
type_map = {
|
||||
'NTRF': bt.ORDER,
|
||||
'NMSC': bt.ORDER,
|
||||
'NPAY': bt.PAYMENT_BATCH,
|
||||
'NCHK': bt.CHECK,
|
||||
}
|
||||
|
||||
def __init__(self, record, *args, **kwargs):
|
||||
'''
|
||||
Transaction creation
|
||||
'''
|
||||
super(transaction, self).__init__(*args, **kwargs)
|
||||
for key, value in self.mapping.iteritems():
|
||||
if value in record:
|
||||
setattr(self, key, record[value])
|
||||
|
||||
self.transferred_amount = record2float(record, 'amount')
|
||||
|
||||
# Set the transfer type based on the bookingcode
|
||||
if record.get('bookingcode', 'ignore') in self.type_map:
|
||||
self.transfer_type = self.type_map[record['bookingcode']]
|
||||
else:
|
||||
# Default to the generic order, so it will be eligible for matching
|
||||
self.transfer_type = bt.ORDER
|
||||
|
||||
if not self.is_valid():
|
||||
logger.info("Invalid: %s", record)
|
||||
|
||||
def is_valid(self):
|
||||
'''
|
||||
We don't have remote_account so override base
|
||||
'''
|
||||
return (self.execution_date
|
||||
and self.transferred_amount and True) or False
|
||||
|
||||
|
||||
class statement(models.mem_bank_statement):
|
||||
'''
|
||||
Bank statement imported data
|
||||
'''
|
||||
|
||||
def import_record(self, record):
|
||||
def _transmission_number():
|
||||
self.id = record['transref']
|
||||
|
||||
def _account_number():
|
||||
# The wizard doesn't check for sort code
|
||||
self.local_account = (
|
||||
record['sortcode'] + ' ' + record['accnum'].zfill(8)
|
||||
)
|
||||
|
||||
def _statement_number():
|
||||
self.id = '-'.join(
|
||||
[self.id, self.local_account, record['statementnr']]
|
||||
)
|
||||
|
||||
def _opening_balance():
|
||||
self.start_balance = record2float(record, 'startingbalance')
|
||||
self.local_currency = record['currencycode']
|
||||
|
||||
def _closing_balance():
|
||||
self.end_balance = record2float(record, 'endingbalance')
|
||||
self.date = record['bookingdate']
|
||||
|
||||
def _transaction_new():
|
||||
self.transactions.append(transaction(record))
|
||||
|
||||
def _transaction_info():
|
||||
self.transaction_info(record)
|
||||
|
||||
def _not_used():
|
||||
logger.info("Didn't use record: %s", record)
|
||||
|
||||
rectypes = {
|
||||
'20': _transmission_number,
|
||||
'25': _account_number,
|
||||
'28': _statement_number,
|
||||
'28C': _statement_number,
|
||||
'60F': _opening_balance,
|
||||
'62F': _closing_balance,
|
||||
'61': _transaction_new,
|
||||
'86': _transaction_info,
|
||||
}
|
||||
|
||||
rectypes.get(record['recordid'], _not_used)()
|
||||
|
||||
def transaction_info(self, record):
|
||||
'''
|
||||
Add extra information to transaction
|
||||
'''
|
||||
# Additional information for previous transaction
|
||||
if len(self.transactions) < 1:
|
||||
logger.info(
|
||||
"Received additional information for non existent transaction:"
|
||||
)
|
||||
logger.info(record)
|
||||
else:
|
||||
transaction = self.transactions[-1]
|
||||
transaction.id = ','.join((
|
||||
record[k]
|
||||
for k in (
|
||||
'infoline{0}'.format(i)
|
||||
for i in range(2, 5)
|
||||
)
|
||||
if k in record
|
||||
))
|
||||
|
||||
|
||||
def raise_error(message, line):
|
||||
raise orm.except_orm(
|
||||
_('Import error'),
|
||||
_('Error in import:') + '\n\n'.join((message, line))
|
||||
)
|
||||
|
||||
|
||||
class parser_hsbc_mt940(models.parser):
|
||||
code = 'HSBC-MT940'
|
||||
name = _('HSBC Swift MT940 statement export')
|
||||
country_code = 'GB'
|
||||
doc = _('''\
|
||||
This format is available through
|
||||
the HSBC web interface.
|
||||
''')
|
||||
|
||||
def parse(self, cr, data):
|
||||
result = []
|
||||
parser = HSBCParser()
|
||||
# Split into statements
|
||||
statements = [st for st in re.split('[\r\n]*(?=:20:)', data)]
|
||||
# Split by records
|
||||
statement_list = [
|
||||
re.split('[\r\n ]*(?=:\d\d[\w]?:)', st)
|
||||
for st in statements
|
||||
]
|
||||
|
||||
for statement_lines in statement_list:
|
||||
stmnt = statement()
|
||||
records = [
|
||||
parser.parse_record(record)
|
||||
for record in statement_lines
|
||||
]
|
||||
[stmnt.import_record(r) for r in records if r is not None]
|
||||
|
||||
if stmnt.is_valid():
|
||||
result.append(stmnt)
|
||||
else:
|
||||
logger.info("Invalid Statement:")
|
||||
logger.info(records[0])
|
||||
|
||||
return result
|
||||
@@ -0,0 +1,287 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_banking_uk_hsbc
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-10-25 15:59+0000\n"
|
||||
"PO-Revision-Date: 2013-10-25 15:59+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_uk_hsbc
|
||||
#: help:banking.export.hsbc.wizard,execution_date_create:0
|
||||
msgid "This is the date the file should be processed by the bank. Don't choose a date beyond the nearest date in your payments. The latest allowed date is 30 days from now.\n"
|
||||
"Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc:0
|
||||
msgid "HSBC Information"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:234
|
||||
#, python-format
|
||||
msgid "There is insufficient information.
|
||||
\n"
|
||||
"Both destination address and account number must be provided"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.hsbc.clientid:0
|
||||
msgid "HSBC Client IDs"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/hsbc_mt940.py:143
|
||||
#, python-format
|
||||
msgid "HSBC Swift MT940 statement export"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,state:0
|
||||
#: field:banking.export.hsbc.wizard,state:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:355
|
||||
#: view:banking.export.hsbc:0
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
#: model:ir.model,name:account_banking_uk_hsbc.model_banking_export_hsbc
|
||||
#: model:ir.model,name:account_banking_uk_hsbc.model_banking_export_hsbc_wizard
|
||||
#, python-format
|
||||
msgid "HSBC Export"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: selection:banking.export.hsbc,state:0
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc:0
|
||||
msgid "Processing Information"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/hsbc_mt940.py:145
|
||||
#, python-format
|
||||
msgid " This format is available through\n"
|
||||
" the HSBC web interface.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc:0
|
||||
#: field:banking.export.hsbc,payment_order_ids:0
|
||||
#: field:banking.export.hsbc.wizard,payment_order_ids:0
|
||||
msgid "Payment Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: selection:banking.export.hsbc,state:0
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
#: selection:banking.export.hsbc.wizard,state:0
|
||||
msgid "Finish"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc.wizard,test:0
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.hsbc.clientid,company_id:0
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: model:ir.model,name:account_banking_uk_hsbc.model_payment_order
|
||||
msgid "Payment Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.hsbc.clientid,clientid:0
|
||||
msgid "Client ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
msgid "Reference for further communication"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: model:ir.model,name:account_banking_uk_hsbc.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
msgid "Processing Details"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: selection:banking.export.hsbc.wizard,state:0
|
||||
msgid "Create"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/hsbc_mt940.py:138
|
||||
#, python-format
|
||||
msgid "Import error"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,no_transactions:0
|
||||
#: field:banking.export.hsbc.wizard,no_transactions:0
|
||||
msgid "Number of Transactions"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.hsbc.clientid,name:0
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,execution_date:0
|
||||
#: field:banking.export.hsbc.wizard,execution_date_create:0
|
||||
#: field:banking.export.hsbc.wizard,execution_date_finish:0
|
||||
msgid "Execution Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:266
|
||||
#, python-format
|
||||
msgid "Transaction invalid: "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,total_amount:0
|
||||
#: field:banking.export.hsbc.wizard,total_amount:0
|
||||
msgid "Total Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: help:banking.export.hsbc.wizard,reference:0
|
||||
msgid "The bank will use this reference in feedback communication to refer to this run. 35 characters are available."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:315
|
||||
#, python-format
|
||||
msgid "Batch invalid: "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:167
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:185
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:210
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:233
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:265
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:286
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:292
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:314
|
||||
#, python-format
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc.wizard,file_id:0
|
||||
msgid "hsbc File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
msgid "Additional message for all transactions"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.hsbc.clientid:0
|
||||
#: model:ir.actions.act_window,name:account_banking_uk_hsbc.banking_hsbc_clientid_action
|
||||
#: model:ir.model,name:account_banking_uk_hsbc.model_banking_hsbc_clientid
|
||||
#: model:ir.ui.menu,name:account_banking_uk_hsbc.banking_hsbc_clientid_menu
|
||||
#: field:payment.order,hsbc_clientid_id:0
|
||||
msgid "HSBC Client ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: selection:banking.export.hsbc,state:0
|
||||
msgid "Reconciled"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc.wizard,reference:0
|
||||
msgid "Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc:0
|
||||
msgid "Payment order"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:294
|
||||
#, python-format
|
||||
msgid "Your company's bank account has to have a valid UK account number (not IBAN)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,date_generated:0
|
||||
msgid "Generation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc:0
|
||||
msgid "General Information"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
msgid "Export"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc.wizard,file:0
|
||||
msgid "File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: code:addons/account_banking_uk_hsbc/wizard/export_hsbc.py:287
|
||||
#, python-format
|
||||
msgid "Source account invalid: "
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: view:banking.export.hsbc.wizard:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,identification:0
|
||||
msgid "Identification"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: field:banking.export.hsbc,file:0
|
||||
msgid "HSBC File"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_banking_uk_hsbc
|
||||
#: model:ir.actions.act_window,name:account_banking_uk_hsbc.act_banking_export_hsbc_payment_order
|
||||
#: model:ir.actions.act_window,name:account_banking_uk_hsbc.action_account_banking_hsbcs
|
||||
#: model:ir.ui.menu,name:account_banking_uk_hsbc.menu_action_account_banking_exported_hsbc_files
|
||||
msgid "Generated HSBC files"
|
||||
msgstr ""
|
||||
|
||||
166
__unported__/account_banking_uk_hsbc/mt940_parser.py
Normal file
166
__unported__/account_banking_uk_hsbc/mt940_parser.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Parser for HSBC UK MT940 format files
|
||||
Based on fi_patu's parser
|
||||
"""
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class HSBCParser(object):
|
||||
|
||||
def __init__(self):
|
||||
recparse = dict()
|
||||
patterns = {'ebcdic': "\w/\?:\(\).,'+{} -"}
|
||||
|
||||
# MT940 header
|
||||
recparse["20"] = ":(?P<recordid>20):(?P<transref>.{1,16})"
|
||||
recparse["25"] = (":(?P<recordid>25):(?P<sortcode>\d{6})"
|
||||
"(?P<accnum>\d{1,29})")
|
||||
recparse["28"] = ":(?P<recordid>28C?):(?P<statementnr>.{1,8})"
|
||||
|
||||
# Opening balance 60F
|
||||
recparse["60F"] = (":(?P<recordid>60F):(?P<creditmarker>[CD])"
|
||||
"(?P<prevstmtdate>\d{6})(?P<currencycode>.{3})"
|
||||
"(?P<startingbalance>[\d,]{1,15})")
|
||||
|
||||
# Transaction
|
||||
recparse["61"] = """\
|
||||
:(?P<recordid>61):\
|
||||
(?P<valuedate>\d{6})(?P<bookingdate>\d{4})?\
|
||||
(?P<creditmarker>R?[CD])\
|
||||
(?P<currency>[A-Z])?\
|
||||
(?P<amount>[\d,]{1,15})\
|
||||
(?P<bookingcode>[A-Z][A-Z0-9]{3})\
|
||||
(?P<custrefno>[%(ebcdic)s]{1,16})\
|
||||
(?://)\
|
||||
(?P<bankref>[%(ebcdic)s]{1,16})?\
|
||||
(?:\n(?P<furtherinfo>[%(ebcdic)s]))?\
|
||||
""" % (patterns)
|
||||
|
||||
# Further info
|
||||
recparse["86"] = (":(?P<recordid>86):"
|
||||
"(?P<infoline1>.{1,80})?"
|
||||
"(?:\n(?P<infoline2>.{1,80}))?"
|
||||
"(?:\n(?P<infoline3>.{1,80}))?"
|
||||
"(?:\n(?P<infoline4>.{1,80}))?"
|
||||
"(?:\n(?P<infoline5>.{1,80}))?")
|
||||
|
||||
# Forward available balance (64) / Closing balance (62F)
|
||||
# / Interim balance (62M)
|
||||
recparse["64"] = (":(?P<recordid>64|62[FM]):"
|
||||
"(?P<creditmarker>[CD])"
|
||||
"(?P<bookingdate>\d{6})(?P<currencycode>.{3})"
|
||||
"(?P<endingbalance>[\d,]{1,15})")
|
||||
|
||||
for record in recparse:
|
||||
recparse[record] = re.compile(recparse[record])
|
||||
self.recparse = recparse
|
||||
|
||||
def parse_record(self, line):
|
||||
"""
|
||||
Parse record using regexps and apply post processing
|
||||
"""
|
||||
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
|
||||
matchdict = dict([(k, v) for k, v in matchdict.iteritems() if v])
|
||||
|
||||
matchkeys = set(matchdict.keys())
|
||||
needstrip = set([
|
||||
"transref", "accnum", "statementnr", "custrefno",
|
||||
"bankref", "furtherinfo", "infoline1", "infoline2", "infoline3",
|
||||
"infoline4", "infoline5", "startingbalance", "endingbalance"
|
||||
])
|
||||
for field in matchkeys & needstrip:
|
||||
matchdict[field] = matchdict[field].strip()
|
||||
|
||||
# Convert to float. Comma is decimal separator
|
||||
needsfloat = set(["startingbalance", "endingbalance", "amount"])
|
||||
for field in matchkeys & needsfloat:
|
||||
matchdict[field] = float(matchdict[field].replace(',', '.'))
|
||||
|
||||
# Convert date fields
|
||||
needdate = set(["prevstmtdate", "valuedate", "bookingdate"])
|
||||
for field in matchkeys & needdate:
|
||||
datestring = matchdict[field]
|
||||
|
||||
post_check = False
|
||||
if (len(datestring) == 4
|
||||
and field == "bookingdate"
|
||||
and "valuedate" in matchdict):
|
||||
# Get year from valuedate
|
||||
datestring = matchdict['valuedate'].strftime('%y') + datestring
|
||||
post_check = True
|
||||
try:
|
||||
matchdict[field] = datetime.strptime(datestring, '%y%m%d')
|
||||
if post_check and matchdict[field] > matchdict["valuedate"]:
|
||||
matchdict[field] = matchdict[field].replace(
|
||||
year=matchdict[field].year-1
|
||||
)
|
||||
except ValueError:
|
||||
matchdict[field] = None
|
||||
|
||||
return matchdict
|
||||
|
||||
def parse(self, cr, data):
|
||||
records = []
|
||||
# Some records are multiline
|
||||
for line in data:
|
||||
if len(line) <= 1:
|
||||
continue
|
||||
if line[0] == ':' and len(line) > 1:
|
||||
records.append(line)
|
||||
else:
|
||||
records[-1] = '\n'.join([records[-1], line])
|
||||
|
||||
output = []
|
||||
for rec in records:
|
||||
output.append(self.parse_record(rec))
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def parse_file(filename):
|
||||
with open(filename, "r") as hsbcfile:
|
||||
HSBCParser().parse(hsbcfile.readlines())
|
||||
|
||||
|
||||
def main():
|
||||
"""The main function, currently just calls a dummy filename
|
||||
|
||||
:returns: description
|
||||
"""
|
||||
parse_file("testfile")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,3 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_banking_hsbc_clientid","banking.hsbc.clientid","model_banking_hsbc_clientid","account_payment.group_account_payment",1,1,1,1
|
||||
"access_banking_export_hsbc","banking.export.hsbc","model_banking_export_hsbc","account_payment.group_account_payment",1,1,1,1
|
||||
|
23
__unported__/account_banking_uk_hsbc/wizard/__init__.py
Normal file
23
__unported__/account_banking_uk_hsbc/wizard/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 export_hsbc
|
||||
428
__unported__/account_banking_uk_hsbc/wizard/export_hsbc.py
Normal file
428
__unported__/account_banking_uk_hsbc/wizard/export_hsbc.py
Normal file
@@ -0,0 +1,428 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import base64
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
import paymul
|
||||
import string
|
||||
import random
|
||||
import logging
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.tools import ustr
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
def strpdate(arg, format='%Y-%m-%d'):
|
||||
"""shortcut"""
|
||||
return datetime.strptime(arg, format).date()
|
||||
|
||||
|
||||
def strfdate(arg, format='%Y-%m-%d'):
|
||||
"""shortcut"""
|
||||
return arg.strftime(format)
|
||||
|
||||
|
||||
class banking_export_hsbc_wizard(orm.TransientModel):
|
||||
_name = 'banking.export.hsbc.wizard'
|
||||
_description = 'HSBC Export'
|
||||
_columns = {
|
||||
'state': fields.selection(
|
||||
[
|
||||
('create', 'Create'),
|
||||
('finish', 'Finish')
|
||||
],
|
||||
'State',
|
||||
readonly=True,
|
||||
),
|
||||
'test': fields.boolean(),
|
||||
'reference': fields.char(
|
||||
'Reference', size=35,
|
||||
help=('The bank will use this reference in feedback communication '
|
||||
'to refer to this run. 35 characters are available.'
|
||||
),
|
||||
),
|
||||
'execution_date_create': fields.date(
|
||||
'Execution Date',
|
||||
help=('This is the date the file should be processed by the bank. '
|
||||
'Don\'t choose a date beyond the nearest date in your '
|
||||
'payments. The latest allowed date is 30 days from now.\n'
|
||||
'Please keep in mind that banks only execute on working '
|
||||
'days and typically use a delay of two days between '
|
||||
'execution date and effective transfer date.'
|
||||
),
|
||||
),
|
||||
'file_id': fields.many2one(
|
||||
'banking.export.hsbc',
|
||||
'hsbc File',
|
||||
readonly=True
|
||||
),
|
||||
'file': fields.related(
|
||||
'file_id', 'file', type='binary',
|
||||
readonly=True,
|
||||
string='File',
|
||||
),
|
||||
'execution_date_finish': fields.related(
|
||||
'file_id', 'execution_date', type='date',
|
||||
readonly=True,
|
||||
string='Execution Date',
|
||||
),
|
||||
'total_amount': fields.related(
|
||||
'file_id', 'total_amount',
|
||||
type='float',
|
||||
string='Total Amount',
|
||||
readonly=True,
|
||||
),
|
||||
'no_transactions': fields.integer(
|
||||
'Number of Transactions',
|
||||
readonly=True,
|
||||
),
|
||||
'payment_order_ids': fields.many2many(
|
||||
'payment.order', 'rel_wiz_payorders', 'wizard_id',
|
||||
'payment_order_id', 'Payment Orders',
|
||||
readonly=True,
|
||||
),
|
||||
}
|
||||
|
||||
logger = logging.getLogger('export_hsbc')
|
||||
|
||||
def create(self, cursor, uid, wizard_data, context=None):
|
||||
'''
|
||||
Retrieve a sane set of default values based on the payment orders
|
||||
from the context.
|
||||
'''
|
||||
|
||||
if 'execution_date_create' not in wizard_data:
|
||||
po_ids = context.get('active_ids', [])
|
||||
po_model = self.pool.get('payment.order')
|
||||
pos = po_model.browse(cursor, uid, po_ids)
|
||||
|
||||
execution_date = date.today()
|
||||
|
||||
for po in pos:
|
||||
if po.date_prefered == 'fixed' and po.date_planned:
|
||||
execution_date = strpdate(po.date_planned)
|
||||
elif po.date_prefered == 'due':
|
||||
for line in po.line_ids:
|
||||
if line.move_line_id.date_maturity:
|
||||
date_maturity = strpdate(
|
||||
line.move_line_id.date_maturity
|
||||
)
|
||||
if date_maturity < execution_date:
|
||||
execution_date = date_maturity
|
||||
|
||||
execution_date = max(execution_date, date.today())
|
||||
|
||||
# The default reference contains a /, which is invalid for PAYMUL
|
||||
reference = pos[0].reference.replace('/', ' ')
|
||||
|
||||
wizard_data.update({
|
||||
'execution_date_create': strfdate(execution_date),
|
||||
'reference': reference,
|
||||
'payment_order_ids': [(6, 0, po_ids)],
|
||||
'state': 'create',
|
||||
})
|
||||
|
||||
return super(banking_export_hsbc_wizard, self).create(
|
||||
cursor, uid, wizard_data, context)
|
||||
|
||||
def _create_account(self, oe_account, origin_country=None,
|
||||
is_origin_account=False):
|
||||
# let the receiving bank select the currency from the batch
|
||||
currency = None
|
||||
holder = oe_account.owner_name or oe_account.partner_id.name
|
||||
self.logger.info('Create account %s' % (holder))
|
||||
self.logger.info('-- %s' % (oe_account.country_id.code))
|
||||
self.logger.info('-- %s' % (oe_account.acc_number))
|
||||
|
||||
if oe_account.state == 'iban':
|
||||
self.logger.info('IBAN: %s' % (oe_account.acc_number))
|
||||
paymul_account = paymul.IBANAccount(
|
||||
iban=oe_account.acc_number,
|
||||
bic=oe_account.bank.bic,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_EACH_OWN,
|
||||
}
|
||||
elif oe_account.country_id.code == 'GB':
|
||||
self.logger.info('GB: %s %s' % (oe_account.country_id.code,
|
||||
oe_account.acc_number))
|
||||
split = oe_account.acc_number.split(" ", 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
else:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
"Invalid GB acccount number '%s'" % oe_account.acc_number)
|
||||
paymul_account = paymul.UKAccount(
|
||||
number=accountno,
|
||||
sortcode=sortcode,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
elif oe_account.country_id.code in ('US', 'CA'):
|
||||
self.logger.info('US/CA: %s %s' % (oe_account.country_id.code,
|
||||
oe_account.acc_number))
|
||||
split = oe_account.acc_number.split(' ', 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
else:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("Invalid %s account number '%s'") %
|
||||
(oe_account.country_id.code, oe_account.acc_number))
|
||||
paymul_account = paymul.NorthAmericanAccount(
|
||||
number=accountno,
|
||||
sortcode=sortcode,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
swiftcode=oe_account.bank.bic,
|
||||
country=oe_account.country_id.code,
|
||||
origin_country=origin_country,
|
||||
is_origin_account=is_origin_account
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
else:
|
||||
self.logger.info('SWIFT Account: %s' % oe_account.country_id.code)
|
||||
split = oe_account.acc_number.split(' ', 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
else:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("Invalid %s account number '%s'") %
|
||||
(oe_account.country_id.code, oe_account.acc_number))
|
||||
paymul_account = paymul.SWIFTAccount(
|
||||
number=accountno,
|
||||
sortcode=sortcode,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
swiftcode=oe_account.bank.bic,
|
||||
country=oe_account.country_id.code,
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
|
||||
return paymul_account, transaction_kwargs
|
||||
|
||||
def _create_transaction(self, line):
|
||||
# Check on missing partner of bank account (this can happen!)
|
||||
if not line.bank_id or not line.bank_id.partner_id:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('There is insufficient information.\r\n'
|
||||
'Both destination address and account '
|
||||
'number must be provided')
|
||||
)
|
||||
|
||||
self.logger.info('====')
|
||||
dest_account, transaction_kwargs = self._create_account(
|
||||
line.bank_id, line.order_id.mode.bank_id.country_id.code
|
||||
)
|
||||
|
||||
means = {
|
||||
'ACH or EZONE': paymul.MEANS_ACH_OR_EZONE,
|
||||
'Faster Payment': paymul.MEANS_FASTER_PAYMENT,
|
||||
'Priority Payment': paymul.MEANS_PRIORITY_PAYMENT
|
||||
}.get(line.order_id.mode.type.name)
|
||||
if means is None:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("Invalid payment type mode for HSBC '%s'")
|
||||
% line.order_id.mode.type.name
|
||||
)
|
||||
|
||||
if not line.info_partner:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("No default address for transaction '%s'") % line.name
|
||||
)
|
||||
|
||||
try:
|
||||
return paymul.Transaction(
|
||||
amount=Decimal(str(line.amount_currency)),
|
||||
currency=line.currency.name,
|
||||
account=dest_account,
|
||||
means=means,
|
||||
name_address=line.info_partner,
|
||||
customer_reference=line.name,
|
||||
payment_reference=line.name,
|
||||
**transaction_kwargs
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('Transaction invalid: %s') + ustr(exc)
|
||||
)
|
||||
|
||||
def wizard_export(self, cursor, uid, wizard_data_ids, context):
|
||||
'''
|
||||
Wizard to actually create the HSBC file
|
||||
'''
|
||||
|
||||
wizard_data = self.browse(cursor, uid, wizard_data_ids, context)[0]
|
||||
result_model = self.pool.get('banking.export.hsbc')
|
||||
payment_orders = wizard_data.payment_order_ids
|
||||
|
||||
try:
|
||||
self.logger.info(
|
||||
'Source - %s (%s) %s' % (
|
||||
payment_orders[0].mode.bank_id.partner_id.name,
|
||||
payment_orders[0].mode.bank_id.acc_number,
|
||||
payment_orders[0].mode.bank_id.country_id.code)
|
||||
)
|
||||
src_account = self._create_account(
|
||||
payment_orders[0].mode.bank_id,
|
||||
payment_orders[0].mode.bank_id.country_id.code,
|
||||
is_origin_account=True
|
||||
)[0]
|
||||
except ValueError as exc:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('Source account invalid: ') + ustr(exc)
|
||||
)
|
||||
|
||||
if not isinstance(src_account, paymul.UKAccount):
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("Your company's bank account has to have a valid UK "
|
||||
"account number (not IBAN)" + ustr(type(src_account)))
|
||||
)
|
||||
|
||||
try:
|
||||
self.logger.info('Create transactions...')
|
||||
transactions = []
|
||||
hsbc_clientid = ''
|
||||
for po in payment_orders:
|
||||
transactions += [
|
||||
self._create_transaction(l) for l in po.line_ids
|
||||
]
|
||||
hsbc_clientid = po.hsbc_clientid_id.clientid
|
||||
|
||||
batch = paymul.Batch(
|
||||
exec_date=strpdate(wizard_data.execution_date_create),
|
||||
reference=wizard_data.reference,
|
||||
debit_account=src_account,
|
||||
name_address=payment_orders[0].line_ids[0].info_owner,
|
||||
)
|
||||
batch.transactions = transactions
|
||||
except ValueError as exc:
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_('Batch invalid: ') + ustr(exc)
|
||||
)
|
||||
|
||||
# Generate random identifier until an unused one is found
|
||||
while True:
|
||||
ref = ''.join(random.choice(string.ascii_uppercase + string.digits)
|
||||
for x in range(15))
|
||||
|
||||
ids = result_model.search(cursor, uid, [
|
||||
('identification', '=', ref)
|
||||
])
|
||||
|
||||
if not ids:
|
||||
break
|
||||
|
||||
message = paymul.Message(reference=ref)
|
||||
message.batches.append(batch)
|
||||
interchange = paymul.Interchange(client_id=hsbc_clientid,
|
||||
reference=ref,
|
||||
message=message)
|
||||
|
||||
export_result = {
|
||||
'identification': interchange.reference,
|
||||
'execution_date': batch.exec_date,
|
||||
'total_amount': batch.amount(),
|
||||
'no_transactions': len(batch.transactions),
|
||||
'file': base64.encodestring(str(interchange)),
|
||||
'payment_order_ids': [
|
||||
[6, 0, [po.id for po in payment_orders]]
|
||||
],
|
||||
}
|
||||
file_id = result_model.create(cursor, uid, export_result, context)
|
||||
|
||||
self.write(cursor, uid, [wizard_data_ids[0]], {
|
||||
'file_id': file_id,
|
||||
'no_transactions': len(batch.transactions),
|
||||
'state': 'finish',
|
||||
}, context)
|
||||
|
||||
return {
|
||||
'name': _('HSBC Export'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': self._name,
|
||||
'domain': [],
|
||||
'context': dict(context, active_ids=wizard_data_ids),
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'res_id': wizard_data_ids[0] or False,
|
||||
}
|
||||
|
||||
def wizard_cancel(self, cursor, uid, ids, context):
|
||||
'''
|
||||
Cancel the export: just drop the file
|
||||
'''
|
||||
|
||||
wizard_data = self.browse(cursor, uid, ids, context)[0]
|
||||
result_model = self.pool.get('banking.export.hsbc')
|
||||
|
||||
try:
|
||||
result_model.unlink(cursor, uid, wizard_data.file_id.id)
|
||||
except AttributeError:
|
||||
# file_id missing, wizard storage gone, server was restarted
|
||||
pass
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def wizard_save(self, cursor, uid, ids, context):
|
||||
'''
|
||||
Save the export: mark all payments in the file as 'sent'
|
||||
'''
|
||||
|
||||
wizard_data = self.browse(cursor, uid, ids, context)[0]
|
||||
result_model = self.pool.get('banking.export.hsbc')
|
||||
po_model = self.pool.get('payment.order')
|
||||
|
||||
result_model.write(cursor, uid, [wizard_data.file_id.id],
|
||||
{'state': 'sent'})
|
||||
|
||||
po_ids = [po.id for po in wizard_data.payment_order_ids]
|
||||
po_model.action_sent(cursor, uid, po_ids)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="wizard_banking_export_wizard_view" model="ir.ui.view">
|
||||
<field name="name">banking.export.hsbc.wizard.view</field>
|
||||
<field name="model">banking.export.hsbc.wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="HSBC Export">
|
||||
<field name="state" invisible="True"/>
|
||||
<group states="create">
|
||||
<separator colspan="4" string="Processing Details"/>
|
||||
<field name="execution_date_create"/>
|
||||
<field name="test"/>
|
||||
<separator colspan="4" string="Reference for further communication"/>
|
||||
<field name="reference" colspan="2"/>
|
||||
<separator colspan="4" string="Additional message for all transactions"/>
|
||||
<newline/>
|
||||
<button icon="gtk-close" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-ok" string="Export" name="wizard_export" type="object"/>
|
||||
</group>
|
||||
<group states="finish">
|
||||
<field name="total_amount"/>
|
||||
<field name="no_transactions"/>
|
||||
<field name="execution_date_finish"/>
|
||||
<newline/>
|
||||
<!--<field name="file_id"/>-->
|
||||
<field name="file"/>
|
||||
<newline/>
|
||||
<button icon="gtk-close" string="Cancel" name="wizard_cancel" type="object"/>
|
||||
<button icon="gtk-ok" string="Finish" name="wizard_save" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
686
__unported__/account_banking_uk_hsbc/wizard/paymul.py
Normal file
686
__unported__/account_banking_uk_hsbc/wizard/paymul.py
Normal file
@@ -0,0 +1,686 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 account_banking import sepa
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
import re
|
||||
import unicodedata
|
||||
|
||||
from openerp.tools import ustr
|
||||
|
||||
|
||||
def strip_accents(string):
|
||||
res = unicodedata.normalize('NFKD', ustr(string))
|
||||
res = res.encode('ASCII', 'ignore')
|
||||
return res
|
||||
|
||||
|
||||
def split_account_holder(holder):
|
||||
holder_parts = holder.split("\n")
|
||||
|
||||
try:
|
||||
line2 = holder_parts[1]
|
||||
except IndexError:
|
||||
line2 = ''
|
||||
|
||||
return holder_parts[0], line2
|
||||
|
||||
|
||||
def address_truncate(name_address):
|
||||
addr_line = name_address.upper().split("\n")[0:5]
|
||||
addr_line = [s[:35] for s in addr_line]
|
||||
return addr_line
|
||||
|
||||
|
||||
def edifact_isalnum(s):
|
||||
"""The standard says alphanumeric characters, but spaces are also
|
||||
allowed
|
||||
"""
|
||||
return bool(re.match(r'^[A-Za-z0-9 ]*$', s))
|
||||
|
||||
|
||||
def edifact_digits(val, digits=None, mindigits=None):
|
||||
if digits is None:
|
||||
digits = ''
|
||||
if mindigits is None:
|
||||
mindigits = digits
|
||||
|
||||
pattern = r'^[0-9]{' + str(mindigits) + ',' + str(digits) + r'}$'
|
||||
return bool(re.match(pattern, str(val)))
|
||||
|
||||
|
||||
def edifact_isalnum_size(val, digits):
|
||||
pattern = r'^[A-Za-z0-9 ]{' + str(digits) + ',' + str(digits) + r'}$'
|
||||
return bool(re.match(pattern, str(val)))
|
||||
|
||||
|
||||
class HasCurrency(object):
|
||||
def _get_currency(self):
|
||||
return self._currency
|
||||
|
||||
def _set_currency(self, currency):
|
||||
if currency is None:
|
||||
self._currency = None
|
||||
else:
|
||||
if not len(currency) <= 3:
|
||||
raise ValueError("Currency must be <= 3 characters long: %s" %
|
||||
ustr(currency))
|
||||
|
||||
if not edifact_isalnum(currency):
|
||||
raise ValueError("Currency must be alphanumeric: %s" %
|
||||
ustr(currency))
|
||||
|
||||
self._currency = currency.upper()
|
||||
|
||||
currency = property(_get_currency, _set_currency)
|
||||
|
||||
|
||||
class LogicalSection(object):
|
||||
|
||||
def __str__(self):
|
||||
segments = self.segments()
|
||||
|
||||
def format_segment(segment):
|
||||
return '+'.join(
|
||||
[':'.join([str(strip_accents(y)) for y in x]) for x in segment]
|
||||
) + "'"
|
||||
|
||||
return "\n".join([format_segment(s) for s in segments])
|
||||
|
||||
|
||||
def _fii_segment(self, party_qualifier):
|
||||
holder = split_account_holder(self.holder)
|
||||
account_identification = [self.number.replace(' ', ''), holder[0]]
|
||||
if holder[1] or self.currency:
|
||||
account_identification.append(holder[1])
|
||||
if self.currency:
|
||||
account_identification.append(self.currency)
|
||||
return [
|
||||
['FII'],
|
||||
[party_qualifier],
|
||||
account_identification,
|
||||
self.institution_identification,
|
||||
[self.country],
|
||||
]
|
||||
|
||||
|
||||
class UKAccount(HasCurrency):
|
||||
def _get_number(self):
|
||||
return self._number
|
||||
|
||||
def _set_number(self, number):
|
||||
if not edifact_digits(number, 8):
|
||||
raise ValueError("Account number must be 8 digits long: " +
|
||||
str(number))
|
||||
|
||||
self._number = number
|
||||
|
||||
number = property(_get_number, _set_number)
|
||||
|
||||
def _get_sortcode(self):
|
||||
return self._sortcode
|
||||
|
||||
def _set_sortcode(self, sortcode):
|
||||
if not edifact_digits(sortcode, 6):
|
||||
raise ValueError("Account sort code must be 6 digits long: %s" %
|
||||
ustr(sortcode))
|
||||
|
||||
self._sortcode = sortcode
|
||||
|
||||
sortcode = property(_get_sortcode, _set_sortcode)
|
||||
|
||||
def _get_holder(self):
|
||||
return self._holder
|
||||
|
||||
def _set_holder(self, holder):
|
||||
holder_parts = split_account_holder(holder)
|
||||
|
||||
if not len(holder_parts[0]) <= 35:
|
||||
raise ValueError("Account holder must be <= 35 characters long: %s"
|
||||
% ustr(holder_parts[0]))
|
||||
|
||||
if not len(holder_parts[1]) <= 35:
|
||||
raise ValueError("Second line of account holder must be <= 35 "
|
||||
"characters long: %s" % ustr(holder_parts[1]))
|
||||
|
||||
if not edifact_isalnum(holder_parts[0]):
|
||||
raise ValueError("Account holder must be alphanumeric: %s" %
|
||||
ustr(holder_parts[0]))
|
||||
|
||||
if not edifact_isalnum(holder_parts[1]):
|
||||
raise ValueError("Second line of account holder must be "
|
||||
"alphanumeric: %s" % ustr(holder_parts[1]))
|
||||
|
||||
self._holder = holder.upper()
|
||||
|
||||
holder = property(_get_holder, _set_holder)
|
||||
|
||||
def __init__(self, number, holder, currency, sortcode):
|
||||
self.number = number
|
||||
self.holder = holder
|
||||
self.currency = currency
|
||||
self.sortcode = sortcode
|
||||
self.country = 'GB'
|
||||
self.institution_identification = ['', '', '', self.sortcode, 154, 133]
|
||||
|
||||
def fii_bf_segment(self):
|
||||
return _fii_segment(self, 'BF')
|
||||
|
||||
def fii_or_segment(self):
|
||||
return _fii_segment(self, 'OR')
|
||||
|
||||
|
||||
class NorthAmericanAccount(UKAccount):
|
||||
|
||||
def _set_account_ident(self):
|
||||
if self.origin_country in ('US', 'CA'):
|
||||
# Use the routing number
|
||||
account_ident = ['', '', '', self.sortcode, 155, 114]
|
||||
else:
|
||||
# Using the BIC/Swift Code
|
||||
account_ident = [self.bic, 25, 5, '', '', '']
|
||||
return account_ident
|
||||
|
||||
def _set_sortcode(self, sortcode):
|
||||
if self.origin_country == 'CA' and self.is_origin_account:
|
||||
expected_digits = 6
|
||||
else:
|
||||
expected_digits = 9
|
||||
if not edifact_digits(sortcode, expected_digits):
|
||||
raise ValueError("Account routing number must be %d digits long: "
|
||||
"%s" % (expected_digits, ustr(sortcode)))
|
||||
|
||||
self._sortcode = sortcode
|
||||
|
||||
def _get_sortcode(self):
|
||||
return self._sortcode
|
||||
|
||||
sortcode = property(_get_sortcode, _set_sortcode)
|
||||
|
||||
def _set_bic(self, bic):
|
||||
if (not edifact_isalnum_size(bic, 8)
|
||||
and not edifact_isalnum_size(bic, 11)):
|
||||
raise ValueError("Account BIC/Swift code must be 8 or 11 "
|
||||
"characters long: %s" % ustr(bic))
|
||||
self._bic = bic
|
||||
|
||||
def _get_bic(self):
|
||||
return self._bic
|
||||
|
||||
bic = property(_get_bic, _set_bic)
|
||||
|
||||
def _set_number(self, number):
|
||||
if not edifact_digits(number, mindigits=1):
|
||||
raise ValueError("Account number is invalid: %s" % ustr(number))
|
||||
|
||||
self._number = number
|
||||
|
||||
def _get_number(self):
|
||||
return self._number
|
||||
|
||||
number = property(_get_number, _set_number)
|
||||
|
||||
def __init__(self, number, holder, currency, sortcode, swiftcode, country,
|
||||
origin_country=None, is_origin_account=False):
|
||||
self.origin_country = origin_country
|
||||
self.is_origin_account = is_origin_account
|
||||
self.number = number
|
||||
self.holder = holder
|
||||
self.currency = currency
|
||||
self.sortcode = sortcode
|
||||
self.country = country
|
||||
self.bic = swiftcode
|
||||
self.institution_identification = self._set_account_ident()
|
||||
|
||||
|
||||
class SWIFTAccount(UKAccount):
|
||||
|
||||
def _set_account_ident(self):
|
||||
# Using the BIC/Swift Code
|
||||
return [self.bic, 25, 5, '', '', '']
|
||||
|
||||
def _set_sortcode(self, sortcode):
|
||||
self._sortcode = sortcode
|
||||
|
||||
def _get_sortcode(self):
|
||||
return self._sortcode
|
||||
|
||||
sortcode = property(_get_sortcode, _set_sortcode)
|
||||
|
||||
def _set_bic(self, bic):
|
||||
if (not edifact_isalnum_size(bic, 8)
|
||||
and not edifact_isalnum_size(bic, 11)):
|
||||
raise ValueError("Account BIC/Swift code must be 8 or 11 "
|
||||
"characters long: %s" % ustr(bic))
|
||||
self._bic = bic
|
||||
|
||||
def _get_bic(self):
|
||||
return self._bic
|
||||
|
||||
bic = property(_get_bic, _set_bic)
|
||||
|
||||
def _set_number(self, number):
|
||||
if not edifact_digits(number, mindigits=1):
|
||||
raise ValueError("Account number is invalid: %s" %
|
||||
ustr(number))
|
||||
|
||||
self._number = number
|
||||
|
||||
def _get_number(self):
|
||||
return self._number
|
||||
|
||||
number = property(_get_number, _set_number)
|
||||
|
||||
def __init__(self, number, holder, currency, sortcode, swiftcode, country,
|
||||
origin_country=None, is_origin_account=False):
|
||||
self.origin_country = origin_country
|
||||
self.is_origin_account = is_origin_account
|
||||
self.number = number
|
||||
self.holder = holder
|
||||
self.currency = currency
|
||||
self.sortcode = sortcode
|
||||
self.country = country
|
||||
self.bic = swiftcode
|
||||
self.institution_identification = self._set_account_ident()
|
||||
|
||||
|
||||
class IBANAccount(HasCurrency):
|
||||
def _get_iban(self):
|
||||
return self._iban
|
||||
|
||||
def _set_iban(self, iban):
|
||||
iban_obj = sepa.IBAN(iban)
|
||||
if not iban_obj.valid:
|
||||
raise ValueError("IBAN is invalid: %s" % ustr(iban))
|
||||
|
||||
self._iban = iban
|
||||
self.country = iban_obj.countrycode
|
||||
|
||||
iban = property(_get_iban, _set_iban)
|
||||
|
||||
def __init__(self, iban, bic, currency, holder):
|
||||
self.iban = iban
|
||||
self.number = iban
|
||||
self.bic = bic
|
||||
self.currency = currency
|
||||
self.holder = holder
|
||||
self.institution_identification = [self.bic, 25, 5, '', '', '']
|
||||
|
||||
def fii_bf_segment(self):
|
||||
return _fii_segment(self, 'BF')
|
||||
|
||||
|
||||
class Interchange(LogicalSection):
|
||||
def _get_reference(self):
|
||||
return self._reference
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 15:
|
||||
raise ValueError("Reference must be <= 15 characters long: %s" %
|
||||
ustr(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric: %s" %
|
||||
ustr(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
reference = property(_get_reference, _set_reference)
|
||||
|
||||
def __init__(self, client_id, reference, create_dt=None, message=None):
|
||||
self.client_id = client_id
|
||||
self.create_dt = create_dt or datetime.datetime.now()
|
||||
self.reference = reference
|
||||
self.message = message
|
||||
|
||||
def segments(self):
|
||||
segments = []
|
||||
segments.append([
|
||||
['UNB'],
|
||||
['UNOA', 3],
|
||||
['', '', self.client_id],
|
||||
['', '', 'HEXAGON ABC'],
|
||||
[self.create_dt.strftime('%y%m%d'),
|
||||
self.create_dt.strftime('%H%M')],
|
||||
[self.reference],
|
||||
])
|
||||
segments += self.message.segments()
|
||||
segments.append([
|
||||
['UNZ'],
|
||||
[1],
|
||||
[self.reference],
|
||||
])
|
||||
return segments
|
||||
|
||||
|
||||
class Message(LogicalSection):
|
||||
def _get_reference(self):
|
||||
return self._reference
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 35:
|
||||
raise ValueError("Reference must be <= 35 characters long: %s" %
|
||||
ustr(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric: %s" %
|
||||
ustr(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
reference = property(_get_reference, _set_reference)
|
||||
|
||||
def __init__(self, reference, dt=None):
|
||||
if dt:
|
||||
self.dt = dt
|
||||
else:
|
||||
self.dt = datetime.datetime.now()
|
||||
|
||||
self.reference = reference
|
||||
self.batches = []
|
||||
|
||||
def segments(self):
|
||||
# HSBC only accepts one message per interchange
|
||||
message_reference_number = 1
|
||||
|
||||
segments = []
|
||||
|
||||
segments.append([
|
||||
['UNH'],
|
||||
[message_reference_number],
|
||||
['PAYMUL', 'D', '96A', 'UN', 'FUN01G'],
|
||||
])
|
||||
segments.append([
|
||||
['BGM'],
|
||||
[452],
|
||||
[self.reference],
|
||||
[9],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
(137, self.dt.strftime('%Y%m%d'), 102),
|
||||
])
|
||||
for index, batch in enumerate(self.batches):
|
||||
segments += batch.segments(index + 1)
|
||||
segments.append([
|
||||
['CNT'],
|
||||
['39', sum([len(x.transactions) for x in self.batches])],
|
||||
])
|
||||
segments.append([
|
||||
['UNT'],
|
||||
[len(segments) + 1],
|
||||
[message_reference_number]
|
||||
])
|
||||
|
||||
return segments
|
||||
|
||||
|
||||
class Batch(LogicalSection):
|
||||
def _get_reference(self):
|
||||
return self._reference
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 18:
|
||||
raise ValueError("Reference must be <= 18 characters long: %s" %
|
||||
ustr(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric: %s" %
|
||||
ustr(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
reference = property(_get_reference, _set_reference)
|
||||
|
||||
def __init__(self, exec_date, reference, debit_account, name_address):
|
||||
self.exec_date = exec_date
|
||||
self.reference = reference
|
||||
self.debit_account = debit_account
|
||||
self.name_address = name_address
|
||||
self.transactions = []
|
||||
|
||||
def amount(self):
|
||||
return sum([x.amount for x in self.transactions])
|
||||
|
||||
def segments(self, index):
|
||||
if not edifact_digits(index, 6, 1):
|
||||
raise ValueError("Index must be 6 digits or less: " + str(index))
|
||||
|
||||
# Store the payment means
|
||||
means = None
|
||||
if len(self.transactions) > 0:
|
||||
means = self.transactions[0].means
|
||||
|
||||
segments = []
|
||||
|
||||
if means != MEANS_PRIORITY_PAYMENT:
|
||||
segments.append([
|
||||
['LIN'],
|
||||
[index],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
[203, self.exec_date.strftime('%Y%m%d'), 102],
|
||||
])
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['AEK', self.reference],
|
||||
])
|
||||
|
||||
currencies = set([x.currency for x in self.transactions])
|
||||
if len(currencies) > 1:
|
||||
raise ValueError("All transactions in a batch must have the "
|
||||
"same currency")
|
||||
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, self.amount().quantize(Decimal('0.00')), currencies.pop()],
|
||||
])
|
||||
segments.append(self.debit_account.fii_or_segment())
|
||||
segments.append([
|
||||
['NAD'],
|
||||
['OY'],
|
||||
[''],
|
||||
address_truncate(self.name_address),
|
||||
])
|
||||
|
||||
for index, transaction in enumerate(self.transactions):
|
||||
if transaction.means == MEANS_PRIORITY_PAYMENT:
|
||||
# Need a debit-credit format for Priority Payments
|
||||
segments.append([
|
||||
['LIN'],
|
||||
[index+1],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
[203, self.exec_date.strftime('%Y%m%d'), 102],
|
||||
])
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['AEK', self.reference],
|
||||
])
|
||||
|
||||
# Use the transaction amount and currency for the debit line
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, transaction.amount.quantize(Decimal('0.00')),
|
||||
transaction.currency],
|
||||
])
|
||||
segments.append(self.debit_account.fii_or_segment())
|
||||
segments.append([
|
||||
['NAD'],
|
||||
['OY'],
|
||||
[''],
|
||||
address_truncate(self.name_address),
|
||||
])
|
||||
use_index = 1
|
||||
else:
|
||||
use_index = index + 1
|
||||
|
||||
segments += transaction.segments(use_index)
|
||||
|
||||
return segments
|
||||
|
||||
# From the spec for FCA segments:
|
||||
# 13 = All charges borne by payee (or beneficiary)
|
||||
# 14 = Each pay own cost
|
||||
# 15 = All charges borne by payor (or ordering customer)
|
||||
# For Faster Payments this should always be ‘14’
|
||||
# Where this field is not present, “14” will be used as a default.
|
||||
CHARGES_PAYEE = 13
|
||||
CHARGES_EACH_OWN = 14
|
||||
CHARGES_PAYER = 15
|
||||
|
||||
# values per section 2.8.5 "PAI, Payment Instructions" of
|
||||
# "HSBC - CRG Paymul Message Implementation Guide"
|
||||
MEANS_ACH_OR_EZONE = 2
|
||||
MEANS_PRIORITY_PAYMENT = 52
|
||||
MEANS_FASTER_PAYMENT = 'FPS'
|
||||
|
||||
CHANNEL_INTRA_COMPANY = 'Z24'
|
||||
|
||||
|
||||
class Transaction(LogicalSection, HasCurrency):
|
||||
def _get_amount(self):
|
||||
return self._amount
|
||||
|
||||
def _set_amount(self, amount):
|
||||
if len(str(amount)) > 18:
|
||||
raise ValueError("Amount must be shorter than 18 bytes: %s" %
|
||||
ustr(amount))
|
||||
|
||||
self._amount = amount
|
||||
|
||||
amount = property(_get_amount, _set_amount)
|
||||
|
||||
def _get_payment_reference(self):
|
||||
return self._payment_reference
|
||||
|
||||
def _set_payment_reference(self, payment_reference):
|
||||
if not len(payment_reference) <= 18:
|
||||
raise ValueError(
|
||||
"Payment reference must be <= 18 characters long: %s" %
|
||||
ustr(payment_reference)
|
||||
)
|
||||
|
||||
if not edifact_isalnum(payment_reference):
|
||||
raise ValueError("Payment reference must be alphanumeric: %s" %
|
||||
ustr(payment_reference))
|
||||
|
||||
self._payment_reference = payment_reference.upper()
|
||||
|
||||
payment_reference = property(
|
||||
_get_payment_reference, _set_payment_reference
|
||||
)
|
||||
|
||||
def _get_customer_reference(self):
|
||||
return self._customer_reference
|
||||
|
||||
def _set_customer_reference(self, customer_reference):
|
||||
if not len(customer_reference) <= 18:
|
||||
raise ValueError(
|
||||
"Customer reference must be <= 18 characters long: %s" %
|
||||
ustr(customer_reference)
|
||||
)
|
||||
|
||||
if not edifact_isalnum(customer_reference):
|
||||
raise ValueError("Customer reference must be alphanumeric: %s" %
|
||||
ustr(customer_reference))
|
||||
|
||||
self._customer_reference = customer_reference.upper()
|
||||
|
||||
customer_reference = property(
|
||||
_get_customer_reference,
|
||||
_set_customer_reference
|
||||
)
|
||||
|
||||
def __init__(self, amount, currency, account, means,
|
||||
name_address=None, party_name=None, channel='',
|
||||
charges=CHARGES_EACH_OWN, customer_reference=None,
|
||||
payment_reference=None):
|
||||
self.amount = amount
|
||||
self.currency = currency
|
||||
self.account = account
|
||||
self.name_address = name_address
|
||||
self.party_name = party_name
|
||||
self.means = means
|
||||
self.channel = channel
|
||||
self.charges = charges
|
||||
self.payment_reference = payment_reference
|
||||
self.customer_reference = customer_reference
|
||||
|
||||
def segments(self, index):
|
||||
segments = []
|
||||
segments.append([
|
||||
['SEQ'],
|
||||
[''],
|
||||
[index],
|
||||
])
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, self.amount.quantize(Decimal('0.00')), self.currency],
|
||||
])
|
||||
|
||||
if self.customer_reference:
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['CR', self.customer_reference],
|
||||
])
|
||||
|
||||
if self.payment_reference:
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['PQ', self.payment_reference],
|
||||
])
|
||||
|
||||
if self.channel:
|
||||
segments.append([
|
||||
['PAI'],
|
||||
['', '', self.means, '', '', self.channel],
|
||||
])
|
||||
else:
|
||||
segments.append([
|
||||
['PAI'],
|
||||
['', '', self.means],
|
||||
])
|
||||
|
||||
segments.append([
|
||||
['FCA'],
|
||||
[self.charges],
|
||||
])
|
||||
|
||||
segments.append(self.account.fii_bf_segment())
|
||||
|
||||
nad_segment = [
|
||||
['NAD'],
|
||||
['BE'],
|
||||
[''],
|
||||
]
|
||||
if self.name_address:
|
||||
nad_segment.append(address_truncate(self.name_address))
|
||||
else:
|
||||
nad_segment.append('')
|
||||
if self.party_name:
|
||||
nad_segment.append(address_truncate(self.party_name))
|
||||
segments.append(nad_segment)
|
||||
|
||||
return segments
|
||||
300
__unported__/account_banking_uk_hsbc/wizard/paymul_test.py
Normal file
300
__unported__/account_banking_uk_hsbc/wizard/paymul_test.py
Normal file
@@ -0,0 +1,300 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
|
||||
# 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 datetime
|
||||
import unittest2 as unittest
|
||||
import paymul
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
class PaymulTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
|
||||
def test_uk_high_value_priority_payment(self):
|
||||
# Changes from spec example: Removed DTM for transaction, HSBC ignores
|
||||
# it (section 2.8.3)
|
||||
expected = """\
|
||||
UNB+UNOA:3+::ABC00000001+::HEXAGON ABC+041111:1500+UKHIGHVALUE'
|
||||
UNH+1+PAYMUL:D:96A:UN:FUN01G'
|
||||
BGM+452+UKHIGHVALUE+9'
|
||||
DTM+137:20041111:102'
|
||||
LIN+1'
|
||||
DTM+203:20041112:102'
|
||||
RFF+AEK:UKHIGHVALUE'
|
||||
MOA+9:1.00:GBP'
|
||||
FII+OR+12345678:HSBC NET TEST::GBP+:::400515:154:133+GB'
|
||||
NAD+OY++HSBC BANK PLC:HSBC NET TEST:TEST:TEST:UNITED KINGDOM'
|
||||
SEQ++1'
|
||||
MOA+9:1.00:GBP'
|
||||
RFF+CR:CRUKHV5'
|
||||
RFF+PQ:PQUKHV5'
|
||||
PAI+::52:::Z24'
|
||||
FCA+13'
|
||||
FII+BF+87654321:XYX LTD FROM FII BF 1:BEN NAME 2:GBP+:::403124:154:133+GB'
|
||||
NAD+BE++SOME BANK PLC:HSBC NET TEST:TEST:TEST:UNITED KINGDOM'
|
||||
CNT+39:1'
|
||||
UNT+19+1'
|
||||
UNZ+1+UKHIGHVALUE'"""
|
||||
|
||||
src_account = paymul.UKAccount(
|
||||
number=12345678,
|
||||
holder='HSBC NET TEST',
|
||||
currency='GBP',
|
||||
sortcode=400515
|
||||
)
|
||||
|
||||
dest_account = paymul.UKAccount(
|
||||
number=87654321,
|
||||
holder="XYX LTD FROM FII BF 1\nBEN NAME 2",
|
||||
currency='GBP',
|
||||
sortcode=403124
|
||||
)
|
||||
|
||||
transaction = paymul.Transaction(
|
||||
amount=Decimal('1.00'),
|
||||
currency='GBP',
|
||||
account=dest_account,
|
||||
charges=paymul.CHARGES_PAYEE,
|
||||
means=paymul.MEANS_PRIORITY_PAYMENT,
|
||||
channel=paymul.CHANNEL_INTRA_COMPANY,
|
||||
name_address="SOME BANK PLC\n"
|
||||
"HSBC NET TEST\n"
|
||||
"TEST\n"
|
||||
"TEST\n"
|
||||
"UNITED KINGDOM",
|
||||
customer_reference='CRUKHV5',
|
||||
payment_reference='PQUKHV5'
|
||||
)
|
||||
|
||||
batch = paymul.Batch(
|
||||
exec_date=datetime.date(2004, 11, 12),
|
||||
reference='UKHIGHVALUE',
|
||||
debit_account=src_account,
|
||||
name_address="HSBC BANK PLC\n"
|
||||
"HSBC NET TEST\n"
|
||||
"TEST\n"
|
||||
"TEST\n"
|
||||
"UNITED KINGDOM")
|
||||
batch.transactions.append(transaction)
|
||||
|
||||
message = paymul.Message(reference='UKHIGHVALUE',
|
||||
dt=datetime.datetime(2004, 11, 11))
|
||||
message.batches.append(batch)
|
||||
|
||||
interchange = paymul.Interchange(
|
||||
client_id='ABC00000001',
|
||||
reference='UKHIGHVALUE',
|
||||
create_dt=datetime.datetime(2004, 11, 11, 15, 00),
|
||||
message=message
|
||||
)
|
||||
|
||||
self.assertMultiLineEqual(expected, str(interchange))
|
||||
|
||||
def test_ezone(self):
|
||||
# Changes from example in spec: Changed CNT from 27 to 39, because we
|
||||
# only generate that and it makes no difference which one we use
|
||||
# Removed DTM for transaction, HSBC ignores it (section 2.8.3)
|
||||
|
||||
expected = """UNB+UNOA:3+::ABC12016001+::HEXAGON ABC+080110:0856+EZONE'
|
||||
UNH+1+PAYMUL:D:96A:UN:FUN01G'
|
||||
BGM+452+EZONE+9'
|
||||
DTM+137:20080110:102'
|
||||
LIN+1'
|
||||
DTM+203:20080114:102'
|
||||
RFF+AEK:EZONE'
|
||||
MOA+9:1.00:EUR'
|
||||
FII+OR+12345678:ACCOUNT HOLDER NAME::EUR+:::403124:154:133+GB'
|
||||
NAD+OY++ORD PARTY NAME NADOY 01:CRG TC5 001 NADOY ADDRESS LINE 0001:CRG TC5 \
|
||||
1001 NADOY ADDRESS LINE 0002'
|
||||
SEQ++1'
|
||||
MOA+9:1.00:EUR'
|
||||
RFF+CR:EZONE 1A'
|
||||
RFF+PQ:EZONE 1A'
|
||||
PAI+::2'
|
||||
FCA+14'
|
||||
FII+BF+DE23300308800099990031:CRG TC5 001 BENE NAME FIIBF \
|
||||
000001::EUR+AACSDE33:25:5:::+DE'
|
||||
NAD+BE+++BENE NAME NADBE T1 001:CRG TC5 001T1 NADBE ADD LINE 1 0001:CRG TC5 \
|
||||
001T1 NADBE ADD LINE 2 0001'
|
||||
CNT+39:1'
|
||||
UNT+19+1'
|
||||
UNZ+1+EZONE'"""
|
||||
|
||||
src_account = paymul.UKAccount(
|
||||
number=12345678,
|
||||
holder='ACCOUNT HOLDER NAME',
|
||||
currency='EUR',
|
||||
sortcode=403124
|
||||
)
|
||||
|
||||
dest_account = paymul.IBANAccount(
|
||||
iban="DE23300308800099990031",
|
||||
holder="CRG TC5 001 BENE NAME FIIBF 000001",
|
||||
currency='EUR',
|
||||
bic="AACSDE33"
|
||||
)
|
||||
|
||||
party_name = ("BENE NAME NADBE T1 001\n"
|
||||
"CRG TC5 001T1 NADBE ADD LINE 1 0001\n"
|
||||
"CRG TC5 001T1 NADBE ADD LINE 2 0001")
|
||||
transaction = paymul.Transaction(amount=Decimal('1.00'),
|
||||
currency='EUR',
|
||||
account=dest_account,
|
||||
party_name=party_name,
|
||||
charges=paymul.CHARGES_EACH_OWN,
|
||||
means=paymul.MEANS_EZONE,
|
||||
customer_reference='EZONE 1A',
|
||||
payment_reference='EZONE 1A')
|
||||
|
||||
name_address = ("ORD PARTY NAME NADOY 01\n"
|
||||
"CRG TC5 001 NADOY ADDRESS LINE 0001\n"
|
||||
"CRG TC5 001 NADOY ADDRESS LINE 0002")
|
||||
batch = paymul.Batch(exec_date=datetime.date(2008, 1, 14),
|
||||
reference='EZONE',
|
||||
debit_account=src_account,
|
||||
name_address=name_address)
|
||||
batch.transactions.append(transaction)
|
||||
|
||||
message = paymul.Message(reference='EZONE',
|
||||
dt=datetime.datetime(2008, 1, 10))
|
||||
message.batches.append(batch)
|
||||
|
||||
interchange = paymul.Interchange(
|
||||
client_id='ABC12016001',
|
||||
reference='EZONE',
|
||||
create_dt=datetime.datetime(2008, 1, 10, 8, 56),
|
||||
message=message
|
||||
)
|
||||
|
||||
self.assertMultiLineEqual(expected, str(interchange))
|
||||
|
||||
def test_uk_low_value_ach_instruction_level(self):
|
||||
dest_account1 = paymul.UKAccount(
|
||||
number=87654321,
|
||||
holder="HSBC NET RPS TEST\nHSBC BANK",
|
||||
currency='GBP',
|
||||
sortcode=403124
|
||||
)
|
||||
name_address = ("HSBC BANK PLC\n"
|
||||
"PCM\n"
|
||||
"8CS37\n"
|
||||
"E14 5HQ\n"
|
||||
"UNITED KINGDOM")
|
||||
transaction1 = paymul.Transaction(amount=Decimal('1.00'),
|
||||
currency='GBP',
|
||||
account=dest_account1,
|
||||
name_address=name_address,
|
||||
charges=paymul.CHARGES_PAYEE,
|
||||
means=paymul.MEANS_ACH,
|
||||
customer_reference='CREDIT',
|
||||
payment_reference='CREDIT')
|
||||
|
||||
dest_account2 = paymul.UKAccount(
|
||||
number=12341234,
|
||||
holder="HSBC NET RPS TEST\nHSBC BANK",
|
||||
currency='GBP',
|
||||
sortcode=403124
|
||||
)
|
||||
name_address = ("HSBC BANK PLC\n"
|
||||
"PCM\n"
|
||||
"8CS37\n"
|
||||
"E14 5HQ\n"
|
||||
"UNITED KINGDOM")
|
||||
transaction2 = paymul.Transaction(amount=Decimal('1.00'),
|
||||
currency='GBP',
|
||||
account=dest_account2,
|
||||
name_address=name_address,
|
||||
charges=paymul.CHARGES_PAYEE,
|
||||
means=paymul.MEANS_ACH,
|
||||
customer_reference='CREDIT1',
|
||||
payment_reference='CREDIT1')
|
||||
|
||||
name_address = ("HSBC BANK PLC\n"
|
||||
"PCM\n"
|
||||
"8CS37\n"
|
||||
"E14 5HQ\n"
|
||||
"UNITED KINGDOM")
|
||||
|
||||
src_account = paymul.UKAccount(number=12345678,
|
||||
holder='BHEX RPS TEST',
|
||||
currency='GBP',
|
||||
sortcode=401234)
|
||||
batch = paymul.Batch(exec_date=datetime.date(2004, 11, 15),
|
||||
reference='UKLVPLIL',
|
||||
debit_account=src_account,
|
||||
name_address=name_address)
|
||||
batch.transactions = [transaction1, transaction2]
|
||||
|
||||
message = paymul.Message(
|
||||
reference='UKLVPLIL',
|
||||
dt=datetime.datetime(2004, 11, 11)
|
||||
)
|
||||
message.batches.append(batch)
|
||||
|
||||
interchange = paymul.Interchange(
|
||||
client_id='ABC00000001',
|
||||
reference='UKLVPLIL',
|
||||
create_dt=datetime.datetime(2004, 11, 11, 15, 0),
|
||||
message=message
|
||||
)
|
||||
|
||||
# Changes from example:
|
||||
# * Change second transaction from EUR to GBP, because we don't support
|
||||
# multi-currency batches
|
||||
# * Removed DTM for transaction, HSBC ignores it (section 2.8.3)
|
||||
expected = """\
|
||||
UNB+UNOA:3+::ABC00000001+::HEXAGON ABC+041111:1500+UKLVPLIL'
|
||||
UNH+1+PAYMUL:D:96A:UN:FUN01G'
|
||||
BGM+452+UKLVPLIL+9'
|
||||
DTM+137:20041111:102'
|
||||
LIN+1'
|
||||
DTM+203:20041115:102'
|
||||
RFF+AEK:UKLVPLIL'
|
||||
MOA+9:2.00:GBP'
|
||||
FII+OR+12345678:BHEX RPS TEST::GBP+:::401234:154:133+GB'
|
||||
NAD+OY++HSBC BANK PLC:PCM:8CS37:E14 5HQ:UNITED KINGDOM'
|
||||
SEQ++1'
|
||||
MOA+9:1.00:GBP'
|
||||
RFF+CR:CREDIT'
|
||||
RFF+PQ:CREDIT'
|
||||
PAI+::2'
|
||||
FCA+13'
|
||||
FII+BF+87654321:HSBC NET RPS TEST:HSBC BANK:GBP+:::403124:154:133+GB'
|
||||
NAD+BE++HSBC BANK PLC:PCM:8CS37:E14 5HQ:UNITED KINGDOM'
|
||||
SEQ++2'
|
||||
MOA+9:1.00:GBP'
|
||||
RFF+CR:CREDIT1'
|
||||
RFF+PQ:CREDIT1'
|
||||
PAI+::2'
|
||||
FCA+13'
|
||||
FII+BF+12341234:HSBC NET RPS TEST:HSBC BANK:GBP+:::403124:154:133+GB'
|
||||
NAD+BE++HSBC BANK PLC:PCM:8CS37:E14 5HQ:UNITED KINGDOM'
|
||||
CNT+39:2'
|
||||
UNT+27+1'
|
||||
UNZ+1+UKLVPLIL'"""
|
||||
|
||||
self.assertMultiLineEqual(expected, str(interchange))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user