From 8ee95510674598146e7190a16c7f53b05a022c0c Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 11:08:52 -0400 Subject: [PATCH 01/29] Flake8 on base_iban_bic_not_required --- base_iban_bic_not_required/__openerp__.py | 2 +- .../model/res_partner_bank.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/base_iban_bic_not_required/__openerp__.py b/base_iban_bic_not_required/__openerp__.py index 08a6fb582..d579bd492 100644 --- a/base_iban_bic_not_required/__openerp__.py +++ b/base_iban_bic_not_required/__openerp__.py @@ -38,7 +38,7 @@ base_iban module. See also https://bugs.launchpad.net/openobject-addons/+bug/933472 -[1] http://www.europarl.europa.eu/sides/getDoc.do?pubRef=-//EP//TEXT+TA+P7-TA-2012-0037+0+DOC+XML+V0//EN&language=EN#BKMD-9 +[1] http://goo.gl/iXM2Cg ''', 'data': [ 'data/res_partner_bank_type_field.xml', diff --git a/base_iban_bic_not_required/model/res_partner_bank.py b/base_iban_bic_not_required/model/res_partner_bank.py index 126e628bd..d3b7fedf9 100644 --- a/base_iban_bic_not_required/model/res_partner_bank.py +++ b/base_iban_bic_not_required/model/res_partner_bank.py @@ -18,21 +18,24 @@ # along with this program. If not, see . # ############################################################################## + from openerp.osv import orm +from openerp.tools.translate import _ class res_partner_bank(orm.Model): _inherit = 'res.partner.bank' def _check_bank(self, cr, uid, ids, context=None): - #suppress base_iban's constraint to enforce BICs for IBANs - #workaround for lp:933472 + # suppress base_iban's constraint to enforce BICs for IBANs + # workaround for lp:933472 return True + def _constr_bank_message(self, cr, uid, ids, context=None): + return _('\nPlease define BIC/Swift code on bank for bank ' + 'type IBAN Account to make valid payments') + # Redefine constraint to update its function reference _constraints = [ - (_check_bank, - '\nPlease define BIC/Swift code on bank for bank ' - 'type IBAN Account to make valid payments', - ['bic']) + (_check_bank, _constr_bank_message, ['bic']), ] From 7296904e5eba9b39711fdc5a2d3a07cd8dcce22e Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 11:22:30 -0400 Subject: [PATCH 02/29] PEP8 on bank_statement_instant_voucher --- .../model/account_bank_statement_line.py | 4 +- .../model/account_voucher_instant.py | 75 +++++++++++-------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/bank_statement_instant_voucher/model/account_bank_statement_line.py b/bank_statement_instant_voucher/model/account_bank_statement_line.py index a72205281..c173d8640 100644 --- a/bank_statement_instant_voucher/model/account_bank_statement_line.py +++ b/bank_statement_instant_voucher/model/account_bank_statement_line.py @@ -19,11 +19,13 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp.osv import orm class account_bank_statement_line(orm.Model): + _inherit = 'account.bank.statement.line' + def create_instant_voucher(self, cr, uid, ids, context=None): res = False if ids: diff --git a/bank_statement_instant_voucher/model/account_voucher_instant.py b/bank_statement_instant_voucher/model/account_voucher_instant.py index 3c7354ded..15b6bc55a 100644 --- a/bank_statement_instant_voucher/model/account_voucher_instant.py +++ b/bank_statement_instant_voucher/model/account_voucher_instant.py @@ -41,8 +41,7 @@ class instant_voucher(orm.TransientModel): cr, uid, [instant.voucher_id.id], context=context) return {'type': 'ir.actions.act_window_close'} - def get_voucher_defaults( - self, cr, uid, vals, context=None): + def get_voucher_defaults(self, cr, uid, vals, context=None): """ Gather conditional defaults based on given key, value pairs @@ -55,7 +54,7 @@ class instant_voucher(orm.TransientModel): for (key, val) in vals.iteritems(): if val and voucher_pool._all_columns[key].column.change_default: for default in values_pool.get_defaults( - cr, uid, 'account.voucher', '%s=%s' % (key, val)): + cr, uid, 'account.voucher', '%s=%s' % (key, val)): if default[1] not in vals: res[default[1]] = default[2] return res @@ -79,21 +78,26 @@ class instant_voucher(orm.TransientModel): orm.exept_orm( _('Error'), _('No %s journal defined') % voucher_type) - + journal = self.pool.get('account.journal').browse( cr, uid, journal_ids[0], context=context) if journal.type in ('sale', 'sale_refund'): - line_account_id = (journal.default_credit_account_id and - journal.default_credit_account_id.id or False) + line_account_id = ( + journal.default_credit_account_id and + journal.default_credit_account_id.id or False + ) elif journal.type in ('purchase', 'expense', 'purchase_refund'): - line_account_id = (journal.default_debit_account_id and - journal.default_debit_account_id.id or False) + line_account_id = ( + journal.default_debit_account_id and + journal.default_debit_account_id.id or False + ) vals = { - 'name': _('Voucher for statement line %s.%s') % (line.statement_id.name, line.name), + 'name': (_('Voucher for statement line %s.%s') % + (line.statement_id.name, line.name)), 'reference': line.ref or False, 'company_id': line.company_id.id, 'partner_id': instant.partner_id.id, - 'date': line.date or res.get('line.date', False), + 'date': line.date or False, 'account_id': line.account_id.id, 'type': voucher_type, 'line_ids': [(0, 0, {'amount': abs(line.amount), @@ -101,11 +105,13 @@ class instant_voucher(orm.TransientModel): 'type': line.amount < 0 and 'dr' or 'cr', 'name': line.ref or False, })], - 'amount': line.amount and abs(line.amount) or res.get('amount', False), + 'amount': line.amount and abs(line.amount) or False, 'journal_id': journal_ids[0], } if vals['date']: - period_ids = period_pool.find(cr, uid, vals['date'], context=context) + period_ids = period_pool.find( + cr, uid, vals['date'], context=context + ) if period_ids: vals['period_id'] = period_ids[0] vals.update(self.get_voucher_defaults(cr, uid, vals, context=context)) @@ -113,7 +119,7 @@ class instant_voucher(orm.TransientModel): voucher_id = voucher_pool.create( cr, uid, vals, context=context) self.write( - cr, uid, ids[0], + cr, uid, ids[0], {'voucher_id': voucher_id, 'state': 'ready', 'type': voucher_type, @@ -180,15 +186,17 @@ class instant_voucher(orm.TransientModel): if instant.voucher_id and instant.voucher_id.state == 'posted': amount = instant.statement_line_id.amount counteramount = 0.0 + statement_account_id = instant.statement_line_id.account_id.id for line in instant.voucher_id.move_ids: - if line.account_id.id == instant.statement_line_id.account_id.id: + if line.account_id.id == statement_account_id: counteramount = line.debit - line.credit for line in instant.voucher_id.move_ids: - if line.account_id.id == instant.statement_line_id.account_id.id: + if line.account_id.id == statement_account_id: counteramount = line.debit - line.credit else: amount = abs(instant.statement_line_id.amount) - counteramount = abs(instant.voucher_id and instant.voucher_id.amount or 0.0) + counteramount = abs(instant.voucher_id + and instant.voucher_id.amount or 0.0) res[instant.id] = amount - counteramount return res @@ -197,7 +205,7 @@ class instant_voucher(orm.TransientModel): Post the voucher if necessary Post the voucher's move lines if necessary Sanity checks on currency and residual = 0.0 - + If the account_banking module is installed, perform matching and reconciliation. If not, the user is left to manual reconciliation of OpenERP. @@ -207,11 +215,11 @@ class instant_voucher(orm.TransientModel): voucher_obj = self.pool.get('account.voucher') move_obj = self.pool.get('account.move') instant = self.browse(cr, uid, ids[0], context=context) + statement_line = instant.statement_line_id voucher_currency = (instant.voucher_id.currency_id and instant.voucher_id.currency_id or instant.voucher_id.company_id.currency_id) - if (instant.statement_line_id.statement_id.currency.id != - voucher_currency.id): + if (statement_line.statement_id.currency.id != voucher_currency.id): raise orm.except_orm( _("Error"), _("Currency on the bank statement line needs to be the " @@ -234,7 +242,7 @@ class instant_voucher(orm.TransientModel): _("Error"), _("The voucher's move line could not be posted.")) if not self.pool.get('res.currency').is_zero( - cr, uid, voucher_currency, instant.balance): + cr, uid, voucher_currency, instant.balance): raise orm.except_orm( _("Error"), _("The amount on the bank statement line needs to be the " @@ -248,33 +256,38 @@ class instant_voucher(orm.TransientModel): raise orm.except_orm( _("Error"), _("Cannot match a confirmed statement line")) - if not instant.statement_line_id.import_transaction_id: + if not statement_line.import_transaction_id: statement_line_obj.create_instant_transaction( - cr, uid, instant.statement_line_id.id, context=context) - instant.statement_line_id.refresh() + cr, uid, statement_line.id, context=context) + statement_line.refresh() for line in instant.voucher_id.move_ids: - if line.account_id.id == instant.statement_line_id.account_id.id: + if line.account_id.id == statement_line.account_id.id: self.pool.get('banking.import.transaction').write( - cr, uid, instant.statement_line_id.import_transaction_id.id, + cr, + uid, + statement_line.import_transaction_id.id, { 'move_line_id': line.id, 'move_line_ids': [(6, 0, [line.id])], 'match_type': 'move', 'invoice_id': False, 'invoice_ids': [(6, 0, [])], - }, context=context) + }, + context=context + ) statement_line_obj.confirm( - cr, uid, [instant.statement_line_id.id], context=context) + cr, uid, [statement_line.id], context=context + ) break return {'type': 'ir.actions.act_window_close'} _columns = { 'balance': fields.function( - _get_balance, - type='float', - digits_compute=dp.get_precision('Account'), - string="Balance",), + _get_balance, + type='float', + digits_compute=dp.get_precision('Account'), + string="Balance",), 'partner_id': fields.many2one( 'res.partner', 'Partner', From 0c9e4c8e657f7d23b261c30de098a80171b561d0 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 11:25:17 -0400 Subject: [PATCH 03/29] PEP8 on account_payment_shortcut --- account_payment_shortcut/__openerp__.py | 7 ++++--- account_payment_shortcut/payment_order.py | 15 +++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/account_payment_shortcut/__openerp__.py b/account_payment_shortcut/__openerp__.py index 30e3acc72..dcceaab45 100644 --- a/account_payment_shortcut/__openerp__.py +++ b/account_payment_shortcut/__openerp__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -27,7 +27,8 @@ 'category': 'Banking addons', 'depends': ['account_payment'], 'description': ''' -When composing a payment order, select all candidates by default (in the second step of the "Select invoices to pay" wizard). +When composing a payment order, select all candidates by default +(in the second step of the "Select invoices to pay" wizard). ''', 'installable': True, } diff --git a/account_payment_shortcut/payment_order.py b/account_payment_shortcut/payment_order.py index 93dfb125b..b44c6b8da 100644 --- a/account_payment_shortcut/payment_order.py +++ b/account_payment_shortcut/payment_order.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -24,11 +24,12 @@ from openerp.osv import orm + class payment_order_create(orm.TransientModel): _inherit = 'payment.order.create' def default_get(self, cr, uid, fields_list, context=None): - """ + """ Automatically add the candidate move lines to the payment order, instead of only applying them to the domain. @@ -39,13 +40,15 @@ class payment_order_create(orm.TransientModel): been placed in the context at object creation time. """ + if context is None: + context = {} res = super(payment_order_create, self).default_get( cr, uid, fields_list, context=context) - if (fields_list and 'entries' in fields_list - and 'entries' not in res - and context and context.get('line_ids', False) - ): + if (fields_list + and 'entries' in fields_list + and 'entries' not in res + and context.get('line_ids', False)): res['entries'] = context['line_ids'] return res From e34b30866c6b5333708e0049ae547a5fe11f3d62 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 11:25:55 -0400 Subject: [PATCH 04/29] PEP8 on account_iban_preserve_domestic --- account_iban_preserve_domestic/__openerp__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/account_iban_preserve_domestic/__openerp__.py b/account_iban_preserve_domestic/__openerp__.py index cef14a839..d78f8ec55 100644 --- a/account_iban_preserve_domestic/__openerp__.py +++ b/account_iban_preserve_domestic/__openerp__.py @@ -1,7 +1,7 @@ ############################################################################## # # Copyright (C) 2012 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -39,7 +39,7 @@ This module is compatible with OpenERP 7.0. The IBAN module in OpenERP 6.1/7.0 registers the IBAN -on the same field as the domestic account number, +on the same field as the domestic account number, instead of keeping both on separate fields as is the case in 6.0. From b6ea50c15f39dc463bef621de9d1af22f62067a6 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 11:37:59 -0400 Subject: [PATCH 05/29] PEP8 on account_direct_debit --- account_direct_debit/__openerp__.py | 4 +- .../migrations/7.0.2/post-migration.py | 3 +- .../migrations/7.0.2/pre-migration.py | 20 +++---- account_direct_debit/model/account_invoice.py | 54 ++++++++++--------- .../model/account_move_line.py | 7 +-- account_direct_debit/model/account_payment.py | 9 ++-- account_direct_debit/model/payment_line.py | 38 ++++++------- .../model/payment_order_create.py | 2 +- 8 files changed, 71 insertions(+), 66 deletions(-) diff --git a/account_direct_debit/__openerp__.py b/account_direct_debit/__openerp__.py index 12fa1d227..ac5637bd7 100644 --- a/account_direct_debit/__openerp__.py +++ b/account_direct_debit/__openerp__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, diff --git a/account_direct_debit/migrations/7.0.2/post-migration.py b/account_direct_debit/migrations/7.0.2/post-migration.py index a6ec3af59..f5c72c672 100644 --- a/account_direct_debit/migrations/7.0.2/post-migration.py +++ b/account_direct_debit/migrations/7.0.2/post-migration.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -22,6 +22,7 @@ # ############################################################################## + def migrate(cr, version): if not version: return diff --git a/account_direct_debit/migrations/7.0.2/pre-migration.py b/account_direct_debit/migrations/7.0.2/pre-migration.py index a167bca53..49c0db52f 100644 --- a/account_direct_debit/migrations/7.0.2/pre-migration.py +++ b/account_direct_debit/migrations/7.0.2/pre-migration.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -25,27 +25,29 @@ import logging logger = logging.getLogger() + def rename_columns(cr, column_spec): """ Rename table columns. Taken from OpenUpgrade. - :param column_spec: a hash with table keys, with lists of tuples as values. \ - Tuples consist of (old_name, new_name). + :param column_spec: a hash with table keys, with lists of tuples as \ + values. Tuples consist of (old_name, new_name). """ for table in column_spec.keys(): for (old, new) in column_spec[table]: - logger.info("table %s, column %s: renaming to %s", - table, old, new) - cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % (table, old, new,)) + logger.info("table %s, column %s: renaming to %s", table, old, new) + cr.execute('ALTER TABLE %s RENAME %s TO %s', (table, old, new,)) cr.execute('DROP INDEX IF EXISTS "%s_%s_index"' % (table, old)) + def migrate(cr, version): if not version: return # rename field debit_move_line_id rename_columns(cr, { - 'payment_line': [ - ('debit_move_line_id', 'banking_addons_61_debit_move_line_id'), - ]}) + 'payment_line': [ + ('debit_move_line_id', 'banking_addons_61_debit_move_line_id'), + ] + }) diff --git a/account_direct_debit/model/account_invoice.py b/account_direct_debit/model/account_invoice.py index b522c45b9..fe2e92337 100644 --- a/account_direct_debit/model/account_invoice.py +++ b/account_direct_debit/model/account_invoice.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -33,13 +33,13 @@ credited afterwards. Such a creditation is called a storno. Invoice workflow: -1 the sale leads to +1 the sale leads to 1300 Debtors 100 8000 Sales 100 -Balance: - Debtors 2000 | - Sales | 2000 +Balance: + Debtors 2000 | + Sales | 2000 2 an external booking takes place 1100 Bank 100 @@ -59,11 +59,11 @@ This module implements the following diversion: 2000 Transfer account 100 | 1300 Debtors | 100 - Reconciliation takes place between 1 and 2a. + Reconciliation takes place between 1 and 2a. The invoice gets set to state 'paid', and 'reconciled' = True Balance: - Debtors 0 | + Debtors 0 | Transfer account 2000 | Bank 0 | Sales | 2000 @@ -76,7 +76,7 @@ Balance: Reconciliation takes place between 3a and 2a Balance: - Debtors 0 | + Debtors 0 | Transfer account 0 | Bank 2000 | Sales | 2000 @@ -84,55 +84,57 @@ Balance: 4 a storno from invoice [1] triggers a new booking on the bank account 1300 Debtors 100 | 1100 Bank | 100 - + Balance: - Debtors 100 | + Debtors 100 | Transfer account 0 | Bank 1900 | Sales | 2000 - The reconciliation of 2a is undone. The booking of 2a is reconciled + The reconciliation of 2a is undone. The booking of 2a is reconciled with the booking of 4 instead. The payment line attribute 'storno' is set to True and the invoice state is no longer 'paid'. Two cases need to be distinguisted: 1) If the storno is a manual storno from the partner, the invoice is set to - state 'debit_denied', with 'reconciled' = False + state 'debit_denied', with 'reconciled' = False This module implements this option by allowing the bank module to call - + netsvc.LocalService("workflow").trg_validate( uid, 'account.invoice', ids, 'debit_denied', cr) 2) If the storno is an error generated by the bank (assumingly non-fatal), - the invoice is reopened for the next debit run. This is a call to existing - + the invoice is reopened for the next debit run. + This is a call to existing + netsvc.LocalService("workflow").trg_validate( uid, 'account.invoice', ids, 'open_test', cr) Should also be adding a log entry on the invoice for tracing purposes - self._log_event(cr, uid, ids, -1.0, 'Debit denied') + self._log_event(cr, uid, ids, -1.0, 'Debit denied') If not for that funny comment "#TODO: implement messages system" in account/invoice.py Repeating non-fatal fatal errors need to be dealt with manually by checking open invoices with a matured invoice- or due date. -""" +""" + class account_invoice(orm.Model): _inherit = "account.invoice" def __init__(self, pool, cr): - """ + """ Adding a state to the hardcoded state list of the inherited - model. The alternative is duplicating the field definition + model. The alternative is duplicating the field definition in columns but only one module can do that! - Maybe apply a similar trick when overriding the buttons' 'states' attributes - in the form view, manipulating the xml in fields_view_get(). - """ + Maybe apply a similar trick when overriding the buttons' 'states' + attributes in the form view, manipulating the xml in fields_view_get(). + """ super(account_invoice, self).__init__(pool, cr) invoice_obj = pool.get('account.invoice') invoice_obj._columns['state'].selection.append( @@ -144,8 +146,8 @@ class account_invoice(orm.Model): number = self.read( cr, uid, invoice_id, ['number'], context=context)['number'] raise orm.except_orm( - _('Error !'), - _('You cannot set invoice \'%s\' to state \'debit denied\', ' + + _('Error !'), + _("You cannot set invoice '%s' to state 'debit denied', " 'as it is still reconciled.') % number) self.write(cr, uid, ids, {'state': 'debit_denied'}, context=context) for inv_id, name in self.name_get(cr, uid, ids, context=context): @@ -154,9 +156,9 @@ class account_invoice(orm.Model): return True def test_undo_debit_denied(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 + invoices that were paid with bank transfers which are being cancelled """ for invoice in self.read(cr, uid, ids, ['reconciled'], context): if not invoice['reconciled']: diff --git a/account_direct_debit/model/account_move_line.py b/account_direct_debit/model/account_move_line.py index 4cd7fab6c..12842e45f 100644 --- a/account_direct_debit/model/account_move_line.py +++ b/account_direct_debit/model/account_move_line.py @@ -23,6 +23,7 @@ from operator import itemgetter from openerp.osv import fields, orm + class account_move_line(orm.Model): _inherit = "account.move.line" @@ -48,7 +49,7 @@ class account_move_line(orm.Model): AND pl.storno is false AND po.state != 'cancel') AS amount FROM account_move_line ml - WHERE id IN %s""", (tuple(ids),)) + WHERE id IN %s""", (tuple(ids), )) r = dict(cr.fetchall()) return r @@ -80,12 +81,12 @@ class account_move_line(orm.Model): WHERE type=%s AND active) AND reconcile_id IS null AND debit > 0 - AND ''' + where + ' and ' + query), ('receivable',)+sql_args ) + AND ''' + where + ' and ' + query), ('receivable', ) + sql_args) res = cr.fetchall() if not res: return [('id', '=', '0')] - return [('id', 'in', map(lambda x:x[0], res))] + return [('id', 'in', map(lambda x: x[0], res))] def line2bank(self, cr, uid, ids, payment_mode_id, context=None): '''I have to inherit this function for direct debits to fix the diff --git a/account_direct_debit/model/account_payment.py b/account_direct_debit/model/account_payment.py index 1b4ce9298..b346efec3 100644 --- a/account_direct_debit/model/account_payment.py +++ b/account_direct_debit/model/account_payment.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- -from openerp.osv import orm, fields -import netsvc -from tools.translate import _ +from openerp.osv import orm + class payment_order(orm.Model): _inherit = 'payment.order' def test_undo_done(self, cr, uid, ids, context=None): - """ + """ Called from the workflow. Used to unset done state on payment orders that were reconciled with bank transfers - which are being cancelled + which are being cancelled """ for order in self.browse(cr, uid, ids, context=context): if order.payment_order_type == 'debit': diff --git a/account_direct_debit/model/payment_line.py b/account_direct_debit/model/payment_line.py index 2c6bf7c51..2be0993db 100644 --- a/account_direct_debit/model/payment_line.py +++ b/account_direct_debit/model/payment_line.py @@ -3,6 +3,7 @@ from openerp.osv import orm, fields import netsvc from tools.translate import _ + class payment_line(orm.Model): _inherit = 'payment.line' @@ -22,15 +23,15 @@ class payment_line(orm.Model): :param payment_line_id: the single payment line id :param amount: the (signed) amount debited from the bank account :param currency: the bank account's currency *browse object* - :param boolean storno_retry: when True, attempt to reopen the invoice, \ - set the invoice to 'Debit denied' otherwise. + :param boolean storno_retry: when True, attempt to reopen the \ + invoice, set the invoice to 'Debit denied' otherwise. :return: an incomplete reconcile for the caller to fill :rtype: database id of an account.move.reconcile resource. """ - move_line_obj = self.pool.get('account.move.line') reconcile_obj = self.pool.get('account.move.reconcile') line = self.browse(cr, uid, payment_line_id) + transit_move_line = line.transit_move_line_id reconcile_id = False if (line.transit_move_line_id and not line.storno and self.pool.get('res.currency').is_zero( @@ -43,14 +44,13 @@ class payment_line(orm.Model): # Actually, given the nature of a direct debit order and storno, # we should not need to take partial into account on the side of # the transit_move_line. - if line.transit_move_line_id.reconcile_partial_id: - reconcile_id = line.transit_move_line_id.reconcile_partial_id.id - attribute = 'reconcile_partial_id' - if len(line.transit_move_line_id.reconcile_id.line_partial_ids) == 2: + if transit_move_line.reconcile_partial_id: + reconcile_id = transit_move_line.reconcile_partial_id.id + if len(transit_move_line.reconcile_id.line_partial_ids) == 2: # reuse the simple reconcile for the storno transfer reconcile_obj.write( cr, uid, reconcile_id, { - 'line_id': [(6, 0, line.transit_move_line_id.id)], + 'line_id': [(6, 0, transit_move_line.id)], 'line_partial_ids': [(6, 0, [])], }, context=context) else: @@ -58,27 +58,27 @@ class payment_line(orm.Model): # and a new one for reconciling the storno transfer reconcile_obj.write( cr, uid, reconcile_id, { - 'line_partial_ids': [(3, line.transit_move_line_id.id)], + 'line_partial_ids': [(3, transit_move_line.id)], }, context=context) reconcile_id = reconcile_obj.create( cr, uid, { 'type': 'auto', - 'line_id': [(6, 0, line.transit_move_line_id.id)], + 'line_id': [(6, 0, transit_move_line.id)], }, context=context) - elif line.transit_move_line_id.reconcile_id: - reconcile_id = line.transit_move_line_id.reconcile_id.id - if len(line.transit_move_line_id.reconcile_id.line_id) == 2: + elif transit_move_line.reconcile_id: + reconcile_id = transit_move_line.reconcile_id.id + if len(transit_move_line.reconcile_id.line_id) == 2: # reuse the simple reconcile for the storno transfer reconcile_obj.write( cr, uid, reconcile_id, { - 'line_id': [(6, 0, [line.transit_move_line_id.id])] + 'line_id': [(6, 0, [transit_move_line.id])] }, context=context) else: # split up the original reconcile in a partial one # and a new one for reconciling the storno transfer - partial_ids = [ - x.id for x in line.transit_move_line_id.reconcile_id.line_id - if x.id != line.transit_move_line_id.id + partial_ids = [ + x.id for x in transit_move_line.reconcile_id.line_id + if x.id != transit_move_line.id ] reconcile_obj.write( cr, uid, reconcile_id, { @@ -88,7 +88,7 @@ class payment_line(orm.Model): reconcile_id = reconcile_obj.create( cr, uid, { 'type': 'auto', - 'line_id': [(6, 0, line.transit_move_line_id.id)], + 'line_id': [(6, 0, transit_move_line.id)], }, context=context) # mark the payment line for storno processed if reconcile_id: @@ -104,7 +104,7 @@ class payment_line(orm.Model): return reconcile_id def get_storno_account_id(self, cr, uid, payment_line_id, amount, - currency, context=None): + currency, context=None): """ Check the match of the arguments, and return the account associated with the storno. diff --git a/account_direct_debit/model/payment_order_create.py b/account_direct_debit/model/payment_order_create.py index b2bbdeb95..5625faac2 100644 --- a/account_direct_debit/model/payment_order_create.py +++ b/account_direct_debit/model/payment_order_create.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved From a5bab211ad01361f960a02c09c313159f3554107 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:33:48 -0400 Subject: [PATCH 06/29] PEP8 on account_banking_uk_hsbc --- account_banking_uk_hsbc/__openerp__.py | 17 +- .../account_banking_uk_hsbc.py | 92 ++++---- account_banking_uk_hsbc/hsbc_clientid.py | 49 ++-- account_banking_uk_hsbc/hsbc_mt940.py | 88 ++++--- account_banking_uk_hsbc/mt940_parser.py | 64 +++--- account_banking_uk_hsbc/wizard/__init__.py | 6 +- account_banking_uk_hsbc/wizard/export_hsbc.py | 133 ++++++----- account_banking_uk_hsbc/wizard/paymul.py | 169 +++++++++----- account_banking_uk_hsbc/wizard/paymul_test.py | 214 ++++++++++-------- 9 files changed, 492 insertions(+), 340 deletions(-) diff --git a/account_banking_uk_hsbc/__openerp__.py b/account_banking_uk_hsbc/__openerp__.py index 77a9359b9..a8f274120 100644 --- a/account_banking_uk_hsbc/__openerp__.py +++ b/account_banking_uk_hsbc/__openerp__.py @@ -34,16 +34,19 @@ '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). +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. +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. +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. +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. - ''', +Initial release of this module was co-sponsored by Canonical. +''', 'installable': True, } diff --git a/account_banking_uk_hsbc/account_banking_uk_hsbc.py b/account_banking_uk_hsbc/account_banking_uk_hsbc.py index 0989d3e76..340ddf733 100644 --- a/account_banking_uk_hsbc/account_banking_uk_hsbc.py +++ b/account_banking_uk_hsbc/account_banking_uk_hsbc.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -19,12 +19,14 @@ # ############################################################################## -from osv import osv, fields from datetime import date -from tools.translate import _ -class hsbc_export(osv.osv): - '''HSBC Export''' +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' @@ -39,7 +41,7 @@ class hsbc_export(osv.osv): 'identification': fields.char('Identification', size=15, readonly=True, select=True), 'execution_date': - fields.date('Execution Date',readonly=True), + fields.date('Execution Date', readonly=True), 'no_transactions': fields.integer('Number of Transactions', readonly=True), 'total_amount': @@ -57,51 +59,53 @@ class hsbc_export(osv.osv): } _defaults = { - 'date_generated': lambda *a: date.today().strftime('%Y-%m-%d'), - 'state': lambda *a: 'draft', + 'date_generated': lambda *a: date.today().strftime(OE_DATEFORMAT), + 'state': 'draft', } -hsbc_export() -class payment_line(osv.osv): - ''' - 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. +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. + """ - 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. - ''' - _name = 'payment.line' _inherit = 'payment.line' def info_owner(self, cr, uid, ids, name=None, args=None, context=None): - if not ids: return {} + + if not ids: + return {} result = {} - info='' + 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 + st1 = '' # no street2 in res.partner.bank zip = owner.zip and owner.zip or '' - city = owner.city and owner.city 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" + st + " " + st1 + "\n" + zip_city + "\n" +cntry + 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 {} + if not ids: + return {} result = {} info = '' @@ -110,24 +114,28 @@ class payment_line(osv.osv): name = partner.owner_name or partner.partner_id.name st = partner.street and partner.street or '' - st1 = '' #no street2 in res.partner.bank + st1 = '' # no street2 in res.partner.bank zip = partner.zip and partner.zip or '' - city = partner.city and partner.city 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" + st + " " + st1 + "\n" + zip_city + "\n" +cntry + 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.'), + '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.' + ), } - -payment_line() - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/hsbc_clientid.py b/account_banking_uk_hsbc/hsbc_clientid.py index 84acd5c05..2f33cf9c5 100644 --- a/account_banking_uk_hsbc/hsbc_clientid.py +++ b/account_banking_uk_hsbc/hsbc_clientid.py @@ -1,7 +1,8 @@ # -*- encoding: utf-8 -*- -from osv import osv, fields +from openerp.osv import orm, fields -class hsbc_clientid(osv.osv): + +class hsbc_clientid(orm.Model): """ Record to hold the HSBCNet Client ID for the company. """ @@ -11,38 +12,38 @@ class hsbc_clientid(osv.osv): _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), - } + '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, - } - -hsbc_clientid() + 'company_id': ( + lambda self, cr, uid, c: + self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id), + } -class payment_order(osv.osv): - _name = 'payment.order' +class payment_order(orm.Model): _inherit = 'payment.order' - _columns = { - 'hsbc_clientid_id': fields.many2one('banking.hsbc.clientid', 'HSBC Client ID', required=True), - } - + 'hsbc_clientid_id': fields.many2one( + 'banking.hsbc.clientid', + 'HSBC Client ID', + required=True, + ), + } def _default_hsbc_clientid(self, cr, uid, context=None): - company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id - - clientid_ids = self.pool.get('banking.hsbc.clientid').search(cr, uid, [('company_id','=',company_id)]) - if len(clientid_ids)==0: + 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, - } - -payment_order() - + 'hsbc_clientid_id': _default_hsbc_clientid, + } diff --git a/account_banking_uk_hsbc/hsbc_mt940.py b/account_banking_uk_hsbc/hsbc_mt940.py index 5016ba1e2..c1d7b7abc 100644 --- a/account_banking_uk_hsbc/hsbc_mt940.py +++ b/account_banking_uk_hsbc/hsbc_mt940.py @@ -22,29 +22,32 @@ # from account_banking.parsers import models -from tools.translate import _ from mt940_parser import HSBCParser import re -import osv 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' + 'execution_date': 'valuedate', + 'value_date': 'valuedate', + 'local_currency': 'currency', + 'transfer_type': 'bookingcode', + 'reference': 'custrefno', + 'message': 'furtherinfo' } type_map = { @@ -60,13 +63,13 @@ class transaction(models.mem_bank_transaction): ''' super(transaction, self).__init__(*args, **kwargs) for key, value in self.mapping.iteritems(): - if record.has_key(value): + 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: + 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 @@ -74,6 +77,7 @@ class transaction(models.mem_bank_transaction): if not self.is_valid(): logger.info("Invalid: %s", record) + def is_valid(self): ''' We don't have remote_account so override base @@ -81,6 +85,7 @@ class transaction(models.mem_bank_transaction): return (self.execution_date and self.transferred_amount and True) or False + class statement(models.mem_bank_statement): ''' Bank statement imported data @@ -89,35 +94,44 @@ class statement(models.mem_bank_statement): 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) + self.local_account = ( + record['sortcode'] + ' ' + record['accnum'].zfill(8) + ) + def _statement_number(): - self.id = '-'.join([self.id, self.local_account, record['statementnr']]) + self.id = '-'.join( + [self.id, self.local_account, record['statementnr']] + ) + def _opening_balance(): - self.start_balance = record2float(record,'startingbalance') + 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, + '20': _transmission_number, + '25': _account_number, + '28': _statement_number, '28C': _statement_number, '60F': _opening_balance, '62F': _closing_balance, - #'64' : _forward_available, - #'62M': _interim_balance, - '61' : _transaction_new, - '86' : _transaction_info, + '61': _transaction_new, + '86': _transaction_info, } rectypes.get(record['recordid'], _not_used)() @@ -128,15 +142,28 @@ class statement(models.mem_bank_statement): ''' # Additional information for previous transaction if len(self.transactions) < 1: - logger.info("Received additional information for non existent transaction:") + 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 record.has_key(k)]) + 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 osv.osv.except_osv(_('Import error'), - 'Error in import:%s\n\n%s' % (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' @@ -153,14 +180,19 @@ class parser_hsbc_mt940(models.parser): # 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] + 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] + 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: @@ -168,5 +200,3 @@ class parser_hsbc_mt940(models.parser): logger.info(records[0]) return result - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/mt940_parser.py b/account_banking_uk_hsbc/mt940_parser.py index 4cfd7ffbe..ea18337ad 100644 --- a/account_banking_uk_hsbc/mt940_parser.py +++ b/account_banking_uk_hsbc/mt940_parser.py @@ -27,21 +27,23 @@ Based on fi_patu's parser import re from datetime import datetime + class HSBCParser(object): - def __init__( self ): + def __init__(self): recparse = dict() patterns = {'ebcdic': "\w/\?:\(\).,'+{} -"} # MT940 header recparse["20"] = ":(?P20):(?P.{1,16})" - recparse["25"] = ":(?P25):(?P\d{6})(?P\d{1,29})" + recparse["25"] = (":(?P25):(?P\d{6})" + "(?P\d{1,29})") recparse["28"] = ":(?P28C?):(?P.{1,8})" # Opening balance 60F - recparse["60F"] = ":(?P60F):(?P[CD])" \ - + "(?P\d{6})(?P.{3})" \ - + "(?P[\d,]{1,15})" + recparse["60F"] = (":(?P60F):(?P[CD])" + "(?P\d{6})(?P.{3})" + "(?P[\d,]{1,15})") # Transaction recparse["61"] = """\ @@ -58,24 +60,24 @@ class HSBCParser(object): """ % (patterns) # Further info - recparse["86"] = ":(?P86):" \ - + "(?P.{1,80})?" \ - + "(?:\n(?P.{1,80}))?" \ - + "(?:\n(?P.{1,80}))?" \ - + "(?:\n(?P.{1,80}))?" \ - + "(?:\n(?P.{1,80}))?" + recparse["86"] = (":(?P86):" + "(?P.{1,80})?" + "(?:\n(?P.{1,80}))?" + "(?:\n(?P.{1,80}))?" + "(?:\n(?P.{1,80}))?" + "(?:\n(?P.{1,80}))?") - # Forward available balance (64) / Closing balance (62F) / Interim balance (62M) - recparse["64"] = ":(?P64|62[FM]):" \ - + "(?P[CD])" \ - + "(?P\d{6})(?P.{3})" \ - + "(?P[\d,]{1,15})" + # Forward available balance (64) / Closing balance (62F) + # / Interim balance (62M) + recparse["64"] = (":(?P64|62[FM]):" + "(?P[CD])" + "(?P\d{6})(?P.{3})" + "(?P[\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 @@ -85,25 +87,27 @@ class HSBCParser(object): if matchobj: break if not matchobj: - print " **** failed to match line '%s'" % (line) + 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]) + matchdict = dict([(k, v) for k, v in matchdict.iteritems() if v]) matchkeys = set(matchdict.keys()) - needstrip = set(["transref", "accnum", "statementnr", "custrefno", + needstrip = set([ + "transref", "accnum", "statementnr", "custrefno", "bankref", "furtherinfo", "infoline1", "infoline2", "infoline3", - "infoline4", "infoline5", "startingbalance", "endingbalance"]) + "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(',','.')) + matchdict[field] = float(matchdict[field].replace(',', '.')) # Convert date fields needdate = set(["prevstmtdate", "valuedate", "bookingdate"]) @@ -111,14 +115,18 @@ class HSBCParser(object): datestring = matchdict[field] post_check = False - if len(datestring) == 4 and field=="bookingdate" and matchdict.has_key("valuedate"): + 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') + 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) + matchdict[field] = matchdict[field].replace( + year=matchdict[field].year-1 + ) except ValueError: matchdict[field] = None @@ -141,9 +149,11 @@ class HSBCParser(object): return output + def parse_file(filename): - hsbcfile = open(filename, "r") - p = HSBCParser().parse(hsbcfile.readlines()) + with open(filename, "r") as hsbcfile: + HSBCParser().parse(hsbcfile.readlines()) + def main(): """The main function, currently just calls a dummy filename diff --git a/account_banking_uk_hsbc/wizard/__init__.py b/account_banking_uk_hsbc/wizard/__init__.py index fb44b448a..beb426b86 100644 --- a/account_banking_uk_hsbc/wizard/__init__.py +++ b/account_banking_uk_hsbc/wizard/__init__.py @@ -6,8 +6,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -20,4 +20,4 @@ # ############################################################################## -import export_hsbc \ No newline at end of file +from . import export_hsbc diff --git a/account_banking_uk_hsbc/wizard/export_hsbc.py b/account_banking_uk_hsbc/wizard/export_hsbc.py index 05bb822fe..ecc4e9902 100644 --- a/account_banking_uk_hsbc/wizard/export_hsbc.py +++ b/account_banking_uk_hsbc/wizard/export_hsbc.py @@ -6,8 +6,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -22,23 +22,28 @@ import base64 from datetime import datetime, date -from osv import osv, fields -from tools.translate import _ 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''' + """shortcut""" return datetime.strptime(arg, format).date() + def strfdate(arg, format='%Y-%m-%d'): - '''shortcut''' + """shortcut""" return arg.strftime(format) -class banking_export_hsbc_wizard(osv.osv_memory): + +class banking_export_hsbc_wizard(orm.TransientModel): _name = 'banking.export.hsbc.wizard' _description = 'HSBC Export' _columns = { @@ -62,9 +67,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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.' + '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( @@ -107,7 +112,7 @@ class banking_export_hsbc_wizard(osv.osv_memory): from the context. ''' - if not 'execution_date_create' in wizard_data: + 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) @@ -120,7 +125,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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) + date_maturity = strpdate( + line.move_line_id.date_maturity + ) if date_maturity < execution_date: execution_date = date_maturity @@ -139,8 +146,10 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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): - currency = None # let the receiving bank select the currency from the batch + 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)) @@ -158,12 +167,13 @@ class banking_export_hsbc_wizard(osv.osv_memory): '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)) + 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 osv.except_osv( + raise orm.except_orm( _('Error'), "Invalid GB acccount number '%s'" % oe_account.acc_number) paymul_account = paymul.UKAccount( @@ -175,15 +185,17 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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)) + 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 osv.except_osv( + raise orm.except_orm( _('Error'), - "Invalid %s account number '%s'" % (oe_account.country_id.code,oe_account.acc_number)) + _("Invalid %s account number '%s'") % + (oe_account.country_id.code, oe_account.acc_number)) paymul_account = paymul.NorthAmericanAccount( number=accountno, sortcode=sortcode, @@ -201,14 +213,15 @@ class banking_export_hsbc_wizard(osv.osv_memory): 'charges': paymul.CHARGES_PAYEE, } else: - self.logger.info('SWIFT Account: %s' % (oe_account.country_id.code)) + 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 osv.except_osv( + raise orm.except_orm( _('Error'), - "Invalid %s account number '%s'" % (oe_account.country_id.code,oe_account.acc_number)) + _("Invalid %s account number '%s'") % + (oe_account.country_id.code, oe_account.acc_number)) paymul_account = paymul.SWIFTAccount( number=accountno, sortcode=sortcode, @@ -229,25 +242,35 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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 osv.except_osv( + raise orm.except_orm( _('Error'), _('There is insufficient information.\r\n' - 'Both destination address and account ' - 'number must be provided' - ) + '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) + 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 osv.except_osv('Error', "Invalid payment type mode for HSBC '%s'" % line.order_id.mode.type.name) + raise orm.except_orm( + _('Error'), + _("Invalid payment type mode for HSBC '%s'") + % line.order_id.mode.type.name + ) if not line.info_partner: - raise osv.except_osv('Error', "No default address for transaction '%s'" % line.name) + raise orm.except_orm( + _('Error'), + _("No default address for transaction '%s'") % line.name + ) try: return paymul.Transaction( @@ -261,9 +284,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): **transaction_kwargs ) except ValueError as exc: - raise osv.except_osv( + raise orm.except_orm( _('Error'), - _('Transaction invalid: ') + str(exc) + _('Transaction invalid: %s') + ustr(exc) ) def wizard_export(self, cursor, uid, wizard_data_ids, context): @@ -275,23 +298,29 @@ class banking_export_hsbc_wizard(osv.osv_memory): 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)) + 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 + 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 osv.except_osv( + raise orm.except_orm( _('Error'), - _('Source account invalid: ') + str(exc) + _('Source account invalid: ') + ustr(exc) ) if not isinstance(src_account, paymul.UKAccount): - raise osv.except_osv( + raise orm.except_orm( _('Error'), _("Your company's bank account has to have a valid UK " - "account number (not IBAN)" + str(type(src_account))) + "account number (not IBAN)" + ustr(type(src_account))) ) try: @@ -299,7 +328,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): transactions = [] hsbc_clientid = '' for po in payment_orders: - transactions += [self._create_transaction(l) for l in po.line_ids] + transactions += [ + self._create_transaction(l) for l in po.line_ids + ] hsbc_clientid = po.hsbc_clientid_id.clientid batch = paymul.Batch( @@ -310,9 +341,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): ) batch.transactions = transactions except ValueError as exc: - raise osv.except_osv( + raise orm.except_orm( _('Error'), - _('Batch invalid: ') + str(exc) + _('Batch invalid: ') + ustr(exc) ) # Generate random identifier until an unused one is found @@ -347,7 +378,7 @@ class banking_export_hsbc_wizard(osv.osv_memory): self.write(cursor, uid, [wizard_data_ids[0]], { 'file_id': file_id, - 'no_transactions' : len(batch.transactions), + 'no_transactions': len(batch.transactions), 'state': 'finish', }, context) @@ -389,13 +420,9 @@ class banking_export_hsbc_wizard(osv.osv_memory): po_model = self.pool.get('payment.order') result_model.write(cursor, uid, [wizard_data.file_id.id], - {'state':'sent'}) + {'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'} - -banking_export_hsbc_wizard() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/wizard/paymul.py b/account_banking_uk_hsbc/wizard/paymul.py index 66e8ecf63..09a9afe81 100644 --- a/account_banking_uk_hsbc/wizard/paymul.py +++ b/account_banking_uk_hsbc/wizard/paymul.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -25,8 +25,14 @@ import datetime import re import unicodedata +from openerp.tools import ustr + + def strip_accents(string): - return unicodedata.normalize('NFKD', unicode(string)).encode('ASCII', 'ignore') + res = unicodedata.normalize('NFKD', ustr(string)) + res = res.encode('ASCII', 'ignore') + return res + def split_account_holder(holder): holder_parts = holder.split("\n") @@ -38,17 +44,20 @@ def split_account_holder(holder): 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 -""" -The standard says alphanumeric characters, but spaces are also allowed -""" + 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 = '' @@ -58,10 +67,12 @@ def edifact_digits(val, digits=None, mindigits=None): 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 @@ -71,12 +82,13 @@ class HasCurrency(object): self._currency = None else: if not len(currency) <= 3: - raise ValueError("Currency must be <= 3 characters long: " + - str(currency)) - + raise ValueError("Currency must be <= 3 characters long: %s" % + ustr(currency)) + if not edifact_isalnum(currency): - raise ValueError("Currency must be alphanumeric: " + str(currency)) - + raise ValueError("Currency must be alphanumeric: %s" % + ustr(currency)) + self._currency = currency.upper() currency = property(_get_currency, _set_currency) @@ -88,17 +100,19 @@ class LogicalSection(object): segments = self.segments() def format_segment(segment): - return '+'.join([':'.join([str(strip_accents(y)) for y in x]) for x in 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]] + account_identification = [self.number.replace(' ', ''), holder[0]] if holder[1] or self.currency: account_identification.append(holder[1]) - if self.currency: + if self.currency: account_identification.append(self.currency) return [ ['FII'], @@ -127,8 +141,8 @@ class UKAccount(HasCurrency): def _set_sortcode(self, sortcode): if not edifact_digits(sortcode, 6): - raise ValueError("Account sort code must be 6 digits long: " + - str(sortcode)) + raise ValueError("Account sort code must be 6 digits long: %s" % + ustr(sortcode)) self._sortcode = sortcode @@ -141,16 +155,20 @@ class UKAccount(HasCurrency): holder_parts = split_account_holder(holder) if not len(holder_parts[0]) <= 35: - raise ValueError("Account holder must be <= 35 characters long: " + str(holder_parts[0])) + 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: " + str(holder_parts[1])) + 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: " + str(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: " + str(holder_parts[1])) + raise ValueError("Second line of account holder must be " + "alphanumeric: %s" % ustr(holder_parts[1])) self._holder = holder.upper() @@ -174,7 +192,7 @@ class UKAccount(HasCurrency): class NorthAmericanAccount(UKAccount): def _set_account_ident(self): - if self.origin_country in ('US','CA'): + if self.origin_country in ('US', 'CA'): # Use the routing number account_ident = ['', '', '', self.sortcode, 155, 114] else: @@ -188,9 +206,9 @@ class NorthAmericanAccount(UKAccount): else: expected_digits = 9 if not edifact_digits(sortcode, expected_digits): - raise ValueError("Account routing number must be %d digits long: %s" % - (expected_digits, str(sortcode))) - + raise ValueError("Account routing number must be %d digits long: " + "%s" % (expected_digits, ustr(sortcode))) + self._sortcode = sortcode def _get_sortcode(self): @@ -199,9 +217,10 @@ class NorthAmericanAccount(UKAccount): 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: " + - str(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): @@ -211,8 +230,7 @@ class NorthAmericanAccount(UKAccount): def _set_number(self, number): if not edifact_digits(number, mindigits=1): - raise ValueError("Account number is invalid: " + - str(number)) + raise ValueError("Account number is invalid: %s" % ustr(number)) self._number = number @@ -221,7 +239,8 @@ class NorthAmericanAccount(UKAccount): number = property(_get_number, _set_number) - def __init__(self, number, holder, currency, sortcode, swiftcode, country, origin_country=None, is_origin_account=False): + 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 @@ -248,9 +267,10 @@ class SWIFTAccount(UKAccount): 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: " + - str(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): @@ -260,8 +280,8 @@ class SWIFTAccount(UKAccount): def _set_number(self, number): if not edifact_digits(number, mindigits=1): - raise ValueError("Account number is invalid: " + - str(number)) + raise ValueError("Account number is invalid: %s" % + ustr(number)) self._number = number @@ -270,7 +290,8 @@ class SWIFTAccount(UKAccount): number = property(_get_number, _set_number) - def __init__(self, number, holder, currency, sortcode, swiftcode, country, origin_country=None, is_origin_account=False): + 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 @@ -289,7 +310,7 @@ class IBANAccount(HasCurrency): def _set_iban(self, iban): iban_obj = sepa.IBAN(iban) if not iban_obj.valid: - raise ValueError("IBAN is invalid: " + str(iban)) + raise ValueError("IBAN is invalid: %s" % ustr(iban)) self._iban = iban self.country = iban_obj.countrycode @@ -302,21 +323,24 @@ class IBANAccount(HasCurrency): self.bic = bic self.currency = currency self.holder = holder - self.institution_identification = [self.bic, 25, 5, '', '', '' ] + 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: " + str(reference)) + raise ValueError("Reference must be <= 15 characters long: %s" % + ustr(reference)) if not edifact_isalnum(reference): - raise ValueError("Reference must be alphanumeric: " + str(reference)) + raise ValueError("Reference must be alphanumeric: %s" % + ustr(reference)) self._reference = reference.upper() @@ -335,7 +359,8 @@ class Interchange(LogicalSection): ['UNOA', 3], ['', '', self.client_id], ['', '', 'HEXAGON ABC'], - [self.create_dt.strftime('%y%m%d'), self.create_dt.strftime('%H%M')], + [self.create_dt.strftime('%y%m%d'), + self.create_dt.strftime('%H%M')], [self.reference], ]) segments += self.message.segments() @@ -353,10 +378,12 @@ class Message(LogicalSection): def _set_reference(self, reference): if not len(reference) <= 35: - raise ValueError("Reference must be <= 35 characters long: " + str(reference)) + raise ValueError("Reference must be <= 35 characters long: %s" % + ustr(reference)) if not edifact_isalnum(reference): - raise ValueError("Reference must be alphanumeric: " + str(reference)) + raise ValueError("Reference must be alphanumeric: %s" % + ustr(reference)) self._reference = reference.upper() @@ -406,16 +433,19 @@ class Message(LogicalSection): 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: " + str(reference)) + raise ValueError("Reference must be <= 18 characters long: %s" % + ustr(reference)) if not edifact_isalnum(reference): - raise ValueError("Reference must be alphanumeric: " + str(reference)) + raise ValueError("Reference must be alphanumeric: %s" % + ustr(reference)) self._reference = reference.upper() @@ -437,7 +467,7 @@ class Batch(LogicalSection): # Store the payment means means = None - if len(self.transactions)>0: + if len(self.transactions) > 0: means = self.transactions[0].means segments = [] @@ -455,11 +485,12 @@ class Batch(LogicalSection): ['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") - + raise ValueError("All transactions in a batch must have the " + "same currency") + segments.append([ ['MOA'], [9, self.amount().quantize(Decimal('0.00')), currencies.pop()], @@ -487,11 +518,12 @@ class Batch(LogicalSection): ['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], + [9, transaction.amount.quantize(Decimal('0.00')), + transaction.currency], ]) segments.append(self.debit_account.fii_or_segment()) segments.append([ @@ -503,7 +535,7 @@ class Batch(LogicalSection): use_index = 1 else: use_index = index + 1 - + segments += transaction.segments(use_index) return segments @@ -518,20 +550,23 @@ 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" +# 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: " + str(amount)) + raise ValueError("Amount must be shorter than 18 bytes: %s" % + ustr(amount)) self._amount = amount @@ -542,28 +577,41 @@ class Transaction(LogicalSection, HasCurrency): def _set_payment_reference(self, payment_reference): if not len(payment_reference) <= 18: - raise ValueError("Payment reference must be <= 18 characters long: " + str(payment_reference)) + 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: " + str(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) + 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: " + str(customer_reference)) + 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: " + str(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) + customer_reference = property( + _get_customer_reference, + _set_customer_reference + ) def __init__(self, amount, currency, account, means, name_address=None, party_name=None, channel='', @@ -636,4 +684,3 @@ class Transaction(LogicalSection, HasCurrency): segments.append(nad_segment) return segments - diff --git a/account_banking_uk_hsbc/wizard/paymul_test.py b/account_banking_uk_hsbc/wizard/paymul_test.py index 7be23c3cd..e6225b93c 100644 --- a/account_banking_uk_hsbc/wizard/paymul_test.py +++ b/account_banking_uk_hsbc/wizard/paymul_test.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -25,15 +25,17 @@ 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' + # 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' @@ -55,46 +57,63 @@ CNT+39:1' UNT+19+1' UNZ+1+UKHIGHVALUE'""" - src_account = paymul.UKAccount(number=12345678, - holder='HSBC NET TEST', - currency='GBP', - sortcode=400515) + 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) + 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\nHSBC NET TEST\nTEST\nTEST\nUNITED KINGDOM", - customer_reference='CRUKHV5', - payment_reference='PQUKHV5') + 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\nHSBC NET TEST\nTEST\nTEST\nUNITED KINGDOM") + 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) + 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 + # 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' @@ -106,33 +125,39 @@ 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 001 NADOY ADDRESS LINE 0002' +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' +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 + ) - 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" + ) - 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" + 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, @@ -142,9 +167,9 @@ UNZ+1+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" + 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, @@ -155,23 +180,27 @@ UNZ+1+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) + 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" + 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, @@ -181,15 +210,17 @@ UNZ+1+EZONE'""" 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" + 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, @@ -199,12 +230,11 @@ UNZ+1+EZONE'""" customer_reference='CREDIT1', payment_reference='CREDIT1') - - name_address = "HSBC BANK PLC\n" \ - + "PCM\n" \ - + "8CS37\n" \ - + "E14 5HQ\n" \ - + "UNITED KINGDOM" + 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', @@ -216,23 +246,25 @@ UNZ+1+EZONE'""" name_address=name_address) batch.transactions = [transaction1, transaction2] - - message = paymul.Message(reference='UKLVPLIL', - dt=datetime.datetime(2004, 11, 11)) + 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) - + 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' + 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' @@ -264,11 +296,5 @@ UNZ+1+UKLVPLIL'""" self.assertMultiLineEqual(expected, str(interchange)) - - - if __name__ == "__main__": - # I ran this with - # env PYTHONPATH=$HOME/src/canonical/hsbc-banking:$HOME/src/openerp/6.0/server/bin:$HOME/src/openerp/6.0/addons python wizard/paymul_test.py - # is there a better way? unittest.main() From 66106bc9407c97c2b0082e8a4891d6b41f0ddb8c Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:37:17 -0400 Subject: [PATCH 07/29] PEP8 on account_banking_tests --- account_banking_tests/tests/__init__.py | 2 +- .../tests/test_payment_roundtrip.py | 65 ++++++++++--------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/account_banking_tests/tests/__init__.py b/account_banking_tests/tests/__init__.py index 991b780d8..2a658a292 100644 --- a/account_banking_tests/tests/__init__.py +++ b/account_banking_tests/tests/__init__.py @@ -2,4 +2,4 @@ import test_payment_roundtrip fast_suite = [ test_payment_roundtrip, - ] +] diff --git a/account_banking_tests/tests/test_payment_roundtrip.py b/account_banking_tests/tests/test_payment_roundtrip.py index a3c8223f4..ca42ab6fc 100644 --- a/account_banking_tests/tests/test_payment_roundtrip.py +++ b/account_banking_tests/tests/test_payment_roundtrip.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2013 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 @@ -83,7 +83,7 @@ class TestPaymentRoundtrip(SingleTransactionCase): reg('res.users').write( cr, uid, [uid], { 'company_id': self.company_id}) - + def setup_chart(self, reg, cr, uid): """ Set up the configurable chart of accounts and create periods @@ -115,7 +115,7 @@ class TestPaymentRoundtrip(SingleTransactionCase): reg('account.fiscalyear').create_period( cr, uid, [fiscalyear_id]) - def setup_payables(self, reg, cr, uid): + def setup_payables(self, reg, cr, uid, context=None): """ Set up suppliers and invoice them. Check that the invoices can be validated properly. @@ -126,25 +126,29 @@ class TestPaymentRoundtrip(SingleTransactionCase): 'name': 'Supplier 1', 'supplier': True, 'country_id': self.country_id, - 'bank_ids': [(0, False, { - 'state': 'iban', - 'acc_number': 'NL42INGB0000454000', - 'bank': self.bank_id, - 'bank_bic': 'INGBNL2A', - })], - }) + 'bank_ids': [ + (0, False, { + 'state': 'iban', + 'acc_number': 'NL42INGB0000454000', + 'bank': self.bank_id, + 'bank_bic': 'INGBNL2A', + }) + ], + }, context=context) supplier2 = partner_model.create( cr, uid, { 'name': 'Supplier 2', 'supplier': True, 'country_id': self.country_id, - 'bank_ids': [(0, False, { - 'state': 'iban', - 'acc_number': 'NL86INGB0002445588', - 'bank': self.bank_id, - 'bank_bic': 'INGBNL2A', - })], - }) + 'bank_ids': [ + (0, False, { + 'state': 'iban', + 'acc_number': 'NL86INGB0002445588', + 'bank': self.bank_id, + 'bank_bic': 'INGBNL2A', + }) + ], + }, context=context) self.payable_id = reg('account.account').search( cr, uid, [ ('company_id', '=', self.company_id), @@ -158,26 +162,29 @@ class TestPaymentRoundtrip(SingleTransactionCase): 'type': 'in_invoice', 'partner_id': supplier1, 'account_id': self.payable_id, - 'invoice_line': [(0, False, { - 'name': 'Purchase 1', - 'price_unit': 100.0, - 'quantity': 1, - 'account_id': expense_id,})], + 'invoice_line': [ + (0, False, { + 'name': 'Purchase 1', + 'price_unit': 100.0, + 'quantity': 1, + 'account_id': expense_id, + }) + ], 'reference_type': 'none', 'supplier_invoice_number': 'INV1', - } + } self.invoice_ids = [ invoice_model.create( cr, uid, values, context={ 'type': 'in_invoice', })] values.update({ - 'partner_id': supplier2, - 'name': 'Purchase 2', - 'reference_type': 'structured', - 'supplier_invoice_number': 'INV2', - 'reference': 'STR2', - }) + 'partner_id': supplier2, + 'name': 'Purchase 2', + 'reference_type': 'structured', + 'supplier_invoice_number': 'INV2', + 'reference': 'STR2', + }) self.invoice_ids.append( invoice_model.create( cr, uid, values, context={ From a82261939256555ebe361715f8bc207b91abe454 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:39:12 -0400 Subject: [PATCH 08/29] PEP8 on account_banking_sepa_direct_debit --- .../__openerp__.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/account_banking_sepa_direct_debit/__openerp__.py b/account_banking_sepa_direct_debit/__openerp__.py index 611127a84..5ea5dadb4 100644 --- a/account_banking_sepa_direct_debit/__openerp__.py +++ b/account_banking_sepa_direct_debit/__openerp__.py @@ -30,7 +30,7 @@ 'depends': ['account_direct_debit', 'account_banking_pain_base'], 'external_dependencies': { 'python': ['unidecode', 'lxml'], - }, + }, 'data': [ 'security/original_mandate_required_security.xml', 'account_banking_sdd_view.xml', @@ -49,13 +49,23 @@ 'description': ''' Module to export direct debit payment orders in SEPA XML file format. -SEPA PAIN (PAyment INitiation) is the new european standard for Customer-to-Bank payment instructions. This module implements SEPA Direct Debit (SDD), more specifically PAIN versions 008.001.02, 008.001.03 and 008.001.04. It is part of the ISO 20022 standard, available on http://www.iso20022.org. +SEPA PAIN (PAyment INitiation) is the new european standard for +Customer-to-Bank payment instructions. -The Implementation Guidelines for SEPA Direct Debit published by the European Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN version 008.001.02. So if you don't know which version your bank supports, you should try version 008.001.02 first. +This module implements SEPA Direct Debit (SDD), more specifically PAIN +versions 008.001.02, 008.001.03 and 008.001.04. +It is part of the ISO 20022 standard, available on http://www.iso20022.org. -This module uses the framework provided by the banking addons, cf https://launchpad.net/banking-addons +The Implementation Guidelines for SEPA Direct Debit published by the European +Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN +version 008.001.02. So if you don't know which version your bank supports, +you should try version 008.001.02 first. -Please contact Alexis de Lattre from Akretion for any help or question about this module. +This module uses the framework provided by the banking addons, +cf https://www.github.com/OCA/banking-addons + +Please contact Alexis de Lattre from Akretion +for any help or question about this module. ''', 'active': False, 'installable': True, From c12500d6f466cab5ab1f8306cb3cd8d87eb13b74 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:40:53 -0400 Subject: [PATCH 09/29] PEP8 on account_banking_sepa_credit_transfer --- .../__openerp__.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/account_banking_sepa_credit_transfer/__openerp__.py b/account_banking_sepa_credit_transfer/__openerp__.py index cdffa6eab..fa2aa04e6 100644 --- a/account_banking_sepa_credit_transfer/__openerp__.py +++ b/account_banking_sepa_credit_transfer/__openerp__.py @@ -30,7 +30,7 @@ 'depends': ['account_banking_pain_base'], 'external_dependencies': { 'python': ['unidecode', 'lxml'], - }, + }, 'data': [ 'account_banking_sepa_view.xml', 'wizard/export_sepa_view.xml', @@ -41,13 +41,23 @@ 'description': ''' Module to export payment orders in SEPA XML file format. -SEPA PAIN (PAyment INitiation) is the new european standard for Customer-to-Bank payment instructions. This module implements SEPA Credit Transfer (SCT), more specifically PAIN versions 001.001.02, 001.001.03, 001.001.04 and 001.001.05. It is part of the ISO 20022 standard, available on http://www.iso20022.org. +SEPA PAIN (PAyment INitiation) is the new european standard for +Customer-to-Bank payment instructions. -The Implementation Guidelines for SEPA Credit Transfer published by the European Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN version 001.001.03, so it's probably the version of PAIN that you should try first. +This module implements SEPA Credit Transfer (SCT), more specifically PAIN +versions 001.001.02, 001.001.03, 001.001.04 and 001.001.05. +It is part of the ISO 20022 standard, available on http://www.iso20022.org. -This module uses the framework provided by the banking addons, cf https://launchpad.net/banking-addons +The Implementation Guidelines for SEPA Credit Transfer published by the +European Payments Council (http://http://www.europeanpaymentscouncil.eu) +use PAIN version 001.001.03, so it's probably the version of PAIN that you +should try first. -Please contact Alexis de Lattre from Akretion for any help or question about this module. +This module uses the framework provided by the banking addons, +cf https://www.github.com/OCA/banking-addons + +Please contact Alexis de Lattre from Akretion +for any help or question about this module. ''', 'active': False, 'installable': True, From a4ad7a0fbd2ce8a91d782e7f02170354bda204ab Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:48:58 -0400 Subject: [PATCH 10/29] PEP8 on account_banking_payment_export --- account_banking_payment_export/__init__.py | 2 +- account_banking_payment_export/__openerp__.py | 28 ++++--- .../model/account_move_line.py | 17 ++-- .../model/account_payment.py | 13 ++-- .../model/bank_payment_manual.py | 20 +++-- .../model/payment_mode.py | 7 +- .../model/payment_mode_type.py | 12 +-- .../model/payment_order_create.py | 78 ++++++++++--------- 8 files changed, 101 insertions(+), 76 deletions(-) diff --git a/account_banking_payment_export/__init__.py b/account_banking_payment_export/__init__.py index 36ec7207a..9186ee3ad 100644 --- a/account_banking_payment_export/__init__.py +++ b/account_banking_payment_export/__init__.py @@ -1 +1 @@ -from . import model \ No newline at end of file +from . import model diff --git a/account_banking_payment_export/__openerp__.py b/account_banking_payment_export/__openerp__.py index 424be1620..4c93fe597 100644 --- a/account_banking_payment_export/__openerp__.py +++ b/account_banking_payment_export/__openerp__.py @@ -56,8 +56,8 @@ ], 'demo': ['demo/banking_demo.xml'], 'description': ''' - Infrastructure to export payment orders - plus some bug fixes and obvious enhancements to payment orders + Infrastructure to export payment orders + plus some bug fixes and obvious enhancements to payment orders that will hopefully land in offical addons one day. This technical module provides the base infrastructure to export @@ -65,21 +65,25 @@ technical features: * a new payment.mode.type model * payment.mode now has a mandatory type - * a better implementation of payment_mode.suitable_bank_types() based on payment.mode.type - * the "make payment" button launches a wizard depending on the payment.mode.type - * a manual payment mode type is provided as an example, with a default "do nothing" wizard + * a better implementation of payment_mode.suitable_bank_types() based + on payment.mode.type + * the "make payment" button launches a wizard depending on the + payment.mode.type + * a manual payment mode type is provided as an example, with a default + "do nothing" wizard - To enable the use of payment order to collect money for customers, - it adds a payment_order_type (payment|debit) as a basis of direct debit support - (this field becomes visible when account_direct_debit is installed). - Refactoring note: this field should ideally go in account_direct_debit, - but account_banking_payment currently depends on it. + To enable the use of payment order to collect money for customers, + it adds a payment_order_type (payment|debit) as a basis of direct debit + support (this field becomes visible when account_direct_debit is + installed). + Refactoring note: this field should ideally go in account_direct_debit, + but account_banking_payment currently depends on it. Bug fixes and enhancement that should land in official addons: * make the search function of the payment export wizard extensible * fix lp:1275478: allow payment of customer refunds - * display the maturity date of the move lines when you are in + * display the maturity date of the move lines when you are in the wizard to select the lines to pay - ''', +''', 'installable': True, } diff --git a/account_banking_payment_export/model/account_move_line.py b/account_banking_payment_export/model/account_move_line.py index 67c8b849d..6d7fad550 100644 --- a/account_banking_payment_export/model/account_move_line.py +++ b/account_banking_payment_export/model/account_move_line.py @@ -73,15 +73,18 @@ class account_move_line(orm.Model): ) %(operator)s %%s ''' % {'operator': x[1]}, args)) sql_args = tuple(map(itemgetter(2), args)) - cr.execute(('''SELECT id + cr.execute( + ('''\ + SELECT id FROM account_move_line l WHERE account_id IN (select id FROM account_account WHERE type in %s AND active) AND reconcile_id IS null AND credit > 0 - AND ''' + where + ' and ' + query), - (('payable', 'receivable'),)+sql_args ) + AND ''' + where + ' and ' + query + ), (('payable', 'receivable'), ) + sql_args + ) # The patch we have compared to the original function in # addons/account_payment is just above : # original code : type = 'payable' @@ -93,6 +96,10 @@ class account_move_line(orm.Model): return [('id', 'in', map(lambda x:x[0], res))] _columns = { - 'amount_to_pay': fields.function(amount_to_pay, - type='float', string='Amount to pay', fnct_search=_to_pay_search), + 'amount_to_pay': fields.function( + amount_to_pay, + type='float', + string='Amount to pay', + fnct_search=_to_pay_search + ), } diff --git a/account_banking_payment_export/model/account_payment.py b/account_banking_payment_export/model/account_payment.py index fe69c290f..bc720771a 100644 --- a/account_banking_payment_export/model/account_payment.py +++ b/account_banking_payment_export/model/account_payment.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -52,7 +52,7 @@ class payment_order(orm.Model): If type is manual. just confirm the order. Previously (pre-v6) in account_payment/wizard/wizard_pay.py """ - if context == None: + if context is None: context = {} result = {} orders = self.browse(cr, uid, ids, context) @@ -81,10 +81,13 @@ class payment_order(orm.Model): if order.mode.type and order.mode.type.ir_model_id: raise orm.except_orm( _('Error'), - _('You can only combine payment orders of the same type') - ) + _('You can only combine payment orders of the same ' + 'type') + ) # process manual payments wf_service = netsvc.LocalService('workflow') for order_id in ids: - wf_service.trg_validate(uid, 'payment.order', order_id, 'done', cr) + wf_service.trg_validate( + uid, 'payment.order', order_id, 'done', cr + ) return result diff --git a/account_banking_payment_export/model/bank_payment_manual.py b/account_banking_payment_export/model/bank_payment_manual.py index 8cfa35d53..cd17f4dd1 100644 --- a/account_banking_payment_export/model/bank_payment_manual.py +++ b/account_banking_payment_export/model/bank_payment_manual.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -37,18 +37,24 @@ class payment_manual(orm.TransientModel): _description = 'Send payment order(s) manually' _columns = { - 'payment_order_ids': fields.many2many('payment.order', - 'wiz_manual_payorders_rel', 'wizard_id', 'payment_order_id', - 'Payment orders', readonly=True), - } + 'payment_order_ids': fields.many2many( + 'payment.order', + 'wiz_manual_payorders_rel', + 'wizard_id', + 'payment_order_id', + 'Payment orders', + readonly=True + ), + } def create(self, cr, uid, vals, context=None): payment_order_ids = context.get('active_ids', []) vals.update({ 'payment_order_ids': [[6, 0, payment_order_ids]], }) - return super(payment_manual, self).create(cr, uid, - vals, context=context) + return super(payment_manual, self).create( + cr, uid, vals, context=context + ) def button_ok(self, cr, uid, ids, context=None): wf_service = netsvc.LocalService('workflow') diff --git a/account_banking_payment_export/model/payment_mode.py b/account_banking_payment_export/model/payment_mode.py index cac103402..e5cf3b452 100644 --- a/account_banking_payment_export/model/payment_mode.py +++ b/account_banking_payment_export/model/payment_mode.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -38,8 +38,9 @@ class payment_mode(orm.Model): res = [] payment_mode = self.browse( cr, uid, payment_mode_id, context) - if (payment_mode and payment_mode.type and - payment_mode.type.suitable_bank_types): + if (payment_mode + and payment_mode.type + and payment_mode.type.suitable_bank_types): res = [t.code for t in payment_mode.type.suitable_bank_types] return res diff --git a/account_banking_payment_export/model/payment_mode_type.py b/account_banking_payment_export/model/payment_mode_type.py index e65727715..5514595ec 100644 --- a/account_banking_payment_export/model/payment_mode_type.py +++ b/account_banking_payment_export/model/payment_mode_type.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -63,9 +63,11 @@ class payment_mode_type(orm.Model): def _auto_init(self, cr, context=None): r = super(payment_mode_type, self)._auto_init(cr, context=context) - # migrate xmlid from manual_bank_transfer to avoid dependency on account_banking - cr.execute("""UPDATE ir_model_data SET module='account_banking_payment_export' - WHERE module='account_banking' AND - name='manual_bank_tranfer' AND + # migrate xmlid from manual_bank_transfer to avoid dependency on + # account_banking + cr.execute("""UPDATE ir_model_data + SET module='account_banking_payment_export' + WHERE module='account_banking' AND + name='manual_bank_tranfer' AND model='payment.mode.type'""") return r diff --git a/account_banking_payment_export/model/payment_order_create.py b/account_banking_payment_export/model/payment_order_create.py index 20d8c3ac1..910673da7 100644 --- a/account_banking_payment_export/model/payment_order_create.py +++ b/account_banking_payment_export/model/payment_order_create.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -50,8 +50,8 @@ class payment_order_create(orm.TransientModel): context = {} data = self.read(cr, uid, ids, ['duedate'], context=context)[0] search_due_date = data['duedate'] - - ### start account_banking_payment ### + + # start account_banking_payment payment = self.pool.get('payment.order').browse( cr, uid, context['active_id'], context=context) # Search for move line to pay: @@ -62,7 +62,7 @@ class payment_order_create(orm.TransientModel): ] self.extend_payment_order_domain( cr, uid, payment, domain, context=context) - ### end account_direct_debit ### + # end account_direct_debit domain = domain + [ '|', ('date_maturity', '<=', search_due_date), @@ -71,21 +71,22 @@ class payment_order_create(orm.TransientModel): line_ids = line_obj.search(cr, uid, domain, context=context) context.update({'line_ids': line_ids}) model_data_ids = mod_obj.search( - cr, uid,[ + cr, uid, [ ('model', '=', 'ir.ui.view'), ('name', '=', 'view_create_payment_order_lines')], context=context) resource_id = mod_obj.read( cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id'] - return {'name': _('Entry Lines'), - 'context': context, - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'payment.order.create', - 'views': [(resource_id, 'form')], - 'type': 'ir.actions.act_window', - 'target': 'new', + return { + 'name': _('Entry Lines'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'payment.order.create', + 'views': [(resource_id, 'form')], + 'type': 'ir.actions.act_window', + 'target': 'new', } def _prepare_payment_line(self, cr, uid, payment, line, context=None): @@ -93,26 +94,26 @@ class payment_order_create(orm.TransientModel): The resulting dict is passed to the create method of payment.line''' _today = fields.date.context_today(self, cr, uid, context=context) if payment.date_prefered == "now": - #no payment date => immediate payment + # no payment date => immediate payment date_to_pay = False elif payment.date_prefered == 'due': - ### account_banking + # account_banking # date_to_pay = line.date_maturity date_to_pay = ( line.date_maturity if line.date_maturity and line.date_maturity > _today else False) - ### end account banking + # end account banking elif payment.date_prefered == 'fixed': - ### account_banking + # account_banking # date_to_pay = payment.date_scheduled date_to_pay = ( payment.date_scheduled if payment.date_scheduled and payment.date_scheduled > _today else False) - ### end account banking + # end account banking - ### account_banking + # account_banking state = 'normal' communication = line.ref or '-' if line.invoice: @@ -132,19 +133,19 @@ class payment_order_create(orm.TransientModel): state = 'structured' # support debit orders when enabled - if (payment.payment_order_type == 'debit' and - 'amount_to_receive' in line): + if (payment.payment_order_type == 'debit' + and 'amount_to_receive' in line): amount_currency = line.amount_to_receive else: amount_currency = line.amount_to_pay - ### end account_banking + # end account_banking - ### account banking + # account banking # t = None # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context) line2bank = self.pool['account.move.line'].line2bank( cr, uid, [line.id], payment.mode.id, context) - ### end account banking + # end account banking res = { 'move_line_id': line.id, @@ -152,11 +153,11 @@ class payment_order_create(orm.TransientModel): 'bank_id': line2bank.get(line.id), 'order_id': payment.id, 'partner_id': line.partner_id and line.partner_id.id or False, - ### account banking + # account banking # 'communication': line.ref or '/' 'communication': communication, 'state': state, - ### end account banking + # end account banking 'date': date_to_pay, 'currency': (line.invoice and line.invoice.currency_id.id or line.journal_id.currency.id @@ -166,11 +167,11 @@ class payment_order_create(orm.TransientModel): def create_payment(self, cr, uid, ids, context=None): ''' - This method is a slightly modified version of the existing method on this - model in account_payment. + This method is a slightly modified version of the existing method on + this model in account_payment. - pass the payment mode to line2bank() - - allow invoices to create influence on the payment process: not only 'Free' - references are allowed, but others as well + - allow invoices to create influence on the payment process: not only + 'Free' references are allowed, but others as well - check date_to_pay is not in the past. ''' if context is None: @@ -182,18 +183,19 @@ class payment_order_create(orm.TransientModel): payment = self.pool['payment.order'].browse( cr, uid, context['active_id'], context=context) - ## Populate the current payment with new lines: + # Populate the current payment with new lines: for line in self.pool['account.move.line'].browse( cr, uid, line_ids, context=context): vals = self._prepare_payment_line( cr, uid, payment, line, context=context) self.pool['payment.line'].create(cr, uid, vals, context=context) # Force reload of payment order view as a workaround for lp:1155525 - return {'name': _('Payment Orders'), - 'context': context, - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'payment.order', - 'res_id': context['active_id'], - 'type': 'ir.actions.act_window', + return { + 'name': _('Payment Orders'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'payment.order', + 'res_id': context['active_id'], + 'type': 'ir.actions.act_window', } From 3b4cfde486837c8cc80b58985f494270a469a2ac Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 12:59:50 -0400 Subject: [PATCH 11/29] PEP8 on account_banking_payment_export --- account_banking_payment/__openerp__.py | 4 +- .../model/banking_import_line.py | 22 ++-- .../model/banking_import_transaction.py | 108 +++++++++--------- .../model/banking_transaction_wizard.py | 63 ++++++---- account_banking_payment/model/payment_line.py | 27 +++-- 5 files changed, 126 insertions(+), 98 deletions(-) diff --git a/account_banking_payment/__openerp__.py b/account_banking_payment/__openerp__.py index 831e794ad..8fd9b7d80 100644 --- a/account_banking_payment/__openerp__.py +++ b/account_banking_payment/__openerp__.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -41,7 +41,7 @@ 'workflow/account_payment.xml', ], 'description': ''' - This addon adds payment reconciliation infrastructure to the Banking Addons. +This addon adds payment reconciliation infrastructure to the Banking Addons. * Extends payments for digital banking: + Adapted workflow in payments to reflect banking operations diff --git a/account_banking_payment/model/banking_import_line.py b/account_banking_payment/model/banking_import_line.py index ee7350d5e..da63b136a 100644 --- a/account_banking_payment/model/banking_import_line.py +++ b/account_banking_payment/model/banking_import_line.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -32,14 +32,12 @@ class banking_import_line(orm.TransientModel): 'payment_order_id': fields.many2one( 'payment.order', 'Payment order'), 'transaction_type': fields.selection([ - # Add payment order related transaction types - ('invoice', 'Invoice payment'), - ('payment_order_line', 'Payment from a payment order'), - ('payment_order', 'Aggregate payment order'), - ('storno', 'Canceled debit order'), - ('bank_costs', 'Bank costs'), - ('unknown', 'Unknown'), - ], 'Transaction type'), - } - - + # Add payment order related transaction types + ('invoice', 'Invoice payment'), + ('payment_order_line', 'Payment from a payment order'), + ('payment_order', 'Aggregate payment order'), + ('storno', 'Canceled debit order'), + ('bank_costs', 'Bank costs'), + ('unknown', 'Unknown'), + ], 'Transaction type'), + } diff --git a/account_banking_payment/model/banking_import_transaction.py b/account_banking_payment/model/banking_import_transaction.py index da6d268e4..17d0d8361 100644 --- a/account_banking_payment/model/banking_import_transaction.py +++ b/account_banking_payment/model/banking_import_transaction.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -27,14 +27,16 @@ from openerp.osv import orm, fields from openerp import netsvc from openerp.tools.translate import _ from openerp.addons.decimal_precision import decimal_precision as dp -from openerp.addons.account_banking.parsers.models import mem_bank_transaction as bt +from openerp.addons.account_banking.parsers.models import ( + mem_bank_transaction as bt +) class banking_import_transaction(orm.Model): _inherit = 'banking.import.transaction' def _match_payment_order( - self, cr, uid, trans, log, order_type='payment', context=None): + self, cr, uid, trans, log, order_type='payment', context=None): def equals_order_amount(payment_order, transferred_amount): if (not hasattr(payment_order, 'payment_order_type') @@ -60,25 +62,26 @@ class banking_import_transaction(orm.Model): if len(candidates) > 0: # retrieve the common account_id, if any account_id = False - if (candidates[0].line_ids[0].transit_move_line_id): - for line in candidates[0].line_ids[0].transit_move_line_id.move_id.line_id: + transit_move_lines = candidates[0].line_ids[0].transit_move_line_id + if transit_move_lines: + for line in transit_move_lines.move_id.line_id: if line.account_id.type == 'other': account_id = line.account_id.id break return dict( - move_line_ids = False, - match_type = 'payment_order', - payment_order_ids = [x.id for x in candidates], - account_id = account_id, - partner_id = False, - partner_bank_id = False, - reference = False, + move_line_ids=False, + match_type='payment_order', + payment_order_ids=[x.id for x in candidates], + account_id=account_id, + partner_id=False, + partner_bank_id=False, + reference=False, type='general', - ) + ) return False def _match_storno( - self, cr, uid, trans, log, context=None): + self, cr, uid, trans, log, context=None): payment_line_obj = self.pool.get('payment.line') line_ids = payment_line_obj.search( cr, uid, [ @@ -93,21 +96,21 @@ class banking_import_transaction(orm.Model): trans.statement_id.currency, context=None) if account_id: return dict( - account_id = account_id, - match_type = 'storno', - payment_line_id = line_ids[0], + account_id=account_id, + match_type='storno', + payment_line_id=line_ids[0], move_line_ids=False, partner_id=False, partner_bank_id=False, reference=False, type='customer', - ) + ) # TODO log the reason why there is no result for transfers marked # as storno return False def _match_payment(self, cr, uid, trans, payment_lines, - partner_ids, bank_account_ids, log, linked_payments): + partner_ids, bank_account_ids, log, linked_payments): ''' Find the payment order belonging to this reference - if there is one This is the easiest part: when sending payments, the returned bank info @@ -132,7 +135,7 @@ class banking_import_transaction(orm.Model): digits = dp.get_precision('Account')(cr)[1] candidates = [ line for line in payment_lines - if (line.communication == trans.reference + if (line.communication == trans.reference and round(line.amount, digits) == -round( trans.statement_line_id.amount, digits) and bank_match(trans.remote_account, line.bank_id)) @@ -145,15 +148,15 @@ class banking_import_transaction(orm.Model): move_info = self._get_move_info( cr, uid, [candidate.move_line_id.id]) move_info.update({ - 'match_type': 'payment', - 'payment_line_id': candidate.id, - }) + 'match_type': 'payment', + 'payment_line_id': candidate.id, + }) return move_info return False def _confirm_storno( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ Creation of the reconciliation has been delegated to *a* direct debit module, to allow for various direct debit styles @@ -167,18 +170,18 @@ class banking_import_transaction(orm.Model): _("No direct debit order item")) reconcile_id = payment_line_pool.debit_storno( cr, uid, - transaction.payment_line_id.id, + transaction.payment_line_id.id, transaction.statement_line_id.amount, transaction.statement_line_id.currency, transaction.storno_retry, context=context) statement_line_pool.write( - cr, uid, transaction.statement_line_id.id, + cr, uid, transaction.statement_line_id.id, {'reconcile_id': reconcile_id}, context=context) transaction.refresh() def _confirm_payment_order( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ Creation of the reconciliation has been delegated to *a* direct debit module, to allow for various direct debit styles @@ -197,11 +200,11 @@ class banking_import_transaction(orm.Model): transaction.statement_line_id.currency, context=context) statement_line_pool.write( - cr, uid, transaction.statement_line_id.id, + cr, uid, transaction.statement_line_id.id, {'reconcile_id': reconcile_id}, context=context) def _confirm_payment( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ Do some housekeeping on the payment line then pass on to _reconcile_move @@ -227,7 +230,7 @@ class banking_import_transaction(orm.Model): uid, 'payment.order', order_id, 'done', cr) def _cancel_payment( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ Do not support cancelling individual lines yet, because the workflow of the payment order does not support reopening. @@ -238,7 +241,7 @@ class banking_import_transaction(orm.Model): "match type 'payment'")) def _cancel_payment_order( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ """ payment_order_obj = self.pool.get('payment.order') @@ -259,7 +262,7 @@ class banking_import_transaction(orm.Model): transaction.statement_line_id.currency) def _cancel_storno( - self, cr, uid, transaction_id, context=None): + self, cr, uid, transaction_id, context=None): """ TODO: delegate unreconciliation to the direct debit module, to allow for various direct debit styles @@ -267,7 +270,7 @@ class banking_import_transaction(orm.Model): payment_line_obj = self.pool.get('payment.line') reconcile_obj = self.pool.get('account.move.reconcile') transaction = self.browse(cr, uid, transaction_id, context=context) - + if not transaction.payment_line_id: raise orm.except_orm( _("Cannot cancel link with storno"), @@ -295,7 +298,8 @@ class banking_import_transaction(orm.Model): raise orm.except_orm( _("Cannot cancel link with storno"), _("Line id not found")) - reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id + reconcile = (cancel_line.reconcile_id + or cancel_line.reconcile_partial_id) lines_reconcile = reconcile.line_id or reconcile.line_partial_ids if len(lines_reconcile) < 3: # delete the full reconciliation @@ -303,15 +307,15 @@ class banking_import_transaction(orm.Model): else: # we are left with a partial reconciliation reconcile_obj.write( - cr, uid, reconcile.id, - {'line_partial_ids': + cr, uid, reconcile.id, + {'line_partial_ids': [(6, 0, [x.id for x in lines_reconcile if x.id != cancel_line.id])], 'line_id': [(6, 0, [])], }, context) # redo the original payment line reconciliation with the invoice payment_line_obj.write( - cr, uid, transaction.payment_line_id.id, + cr, uid, transaction.payment_line_id.id, {'storno': False}, context) payment_line_obj.debit_reconcile( cr, uid, transaction.payment_line_id.id, context) @@ -333,7 +337,7 @@ class banking_import_transaction(orm.Model): for transaction in self.browse(cr, uid, ids, context): if transaction.match_type == 'payment_order': if (transaction.payment_order_ids and not - transaction.payment_order_id): + transaction.payment_order_id): res[transaction.id] = True return res @@ -354,7 +358,7 @@ class banking_import_transaction(orm.Model): vals['payment_order_ids'] = [ (6, 0, move_info.get('payment_order_ids') or [])] vals['payment_order_id'] = ( - move_info.get('payment_order_ids', False) and + move_info.get('payment_order_ids', False) and len(move_info['payment_order_ids']) == 1 and move_info['payment_order_ids'][0] ) @@ -388,17 +392,19 @@ class banking_import_transaction(orm.Model): super(banking_import_transaction, self).__init__(pool, cr) self.confirm_map.update({ - 'storno': banking_import_transaction._confirm_storno, - 'payment_order': banking_import_transaction._confirm_payment_order, - 'payment': banking_import_transaction._confirm_payment, - 'payment_order_manual': banking_import_transaction._confirm_payment_order, - 'payment_manual': banking_import_transaction._confirm_payment, - }) + 'storno': banking_import_transaction._confirm_storno, + 'payment_order': banking_import_transaction._confirm_payment_order, + 'payment': banking_import_transaction._confirm_payment, + 'payment_order_manual': ( + banking_import_transaction._confirm_payment_order), + 'payment_manual': banking_import_transaction._confirm_payment, + }) self.cancel_map.update({ - 'storno': banking_import_transaction._cancel_storno, - 'payment_order': banking_import_transaction._cancel_payment_order, - 'payment': banking_import_transaction._cancel_payment, - 'payment_order_manual': banking_import_transaction._cancel_payment_order, - 'payment_manual': banking_import_transaction._cancel_payment, - }) + 'storno': banking_import_transaction._cancel_storno, + 'payment_order': banking_import_transaction._cancel_payment_order, + 'payment': banking_import_transaction._cancel_payment, + 'payment_order_manual': ( + banking_import_transaction._cancel_payment_order), + 'payment_manual': banking_import_transaction._cancel_payment, + }) diff --git a/account_banking_payment/model/banking_transaction_wizard.py b/account_banking_payment/model/banking_transaction_wizard.py index a2f7a359b..dcc4d781b 100644 --- a/account_banking_payment/model/banking_transaction_wizard.py +++ b/account_banking_payment/model/banking_transaction_wizard.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -53,19 +53,23 @@ class banking_transaction_wizard(orm.TransientModel): sign = 1 else: sign = -1 - total = (payment_order.total + sign * + total = (payment_order.total + sign * transaction_id.statement_line_id.amount) if not self.pool.get('res.currency').is_zero( - cr, uid, transaction_id.statement_line_id.statement_id.currency, total): + cr, uid, + transaction_id.statement_line_id.statement_id.currency, + total): raise orm.except_orm( _('Error'), _('When matching a payment order, the amounts have to ' 'match exactly')) - - if payment_order.mode and payment_order.mode.transfer_account_id: + + if (payment_order.mode + and payment_order.mode.transfer_account_id): transaction_id.statement_line_id.write({ - 'account_id': payment_order.mode.transfer_account_id.id, - }) + 'account_id': ( + payment_order.mode.transfer_account_id.id), + }) write_vals.update( {'payment_order_id': manual_payment_order_id, 'match_type': 'payment_order_manual'}) @@ -79,25 +83,40 @@ class banking_transaction_wizard(orm.TransientModel): _columns = { 'payment_line_id': fields.related( - 'import_transaction_id', 'payment_line_id', - string="Matching payment or storno", - type='many2one', relation='payment.line', - readonly=True), + 'import_transaction_id', + 'payment_line_id', + string="Matching payment or storno", + type='many2one', + relation='payment.line', + readonly=True, + ), 'payment_order_ids': fields.related( - 'import_transaction_id', 'payment_order_ids', - string="Matching payment orders", - type='many2many', relation='payment.order'), + 'import_transaction_id', + 'payment_order_ids', + string="Matching payment orders", + type='many2many', + relation='payment.order', + ), 'payment_order_id': fields.related( - 'import_transaction_id', 'payment_order_id', - string="Payment order to reconcile", - type='many2one', relation='payment.order'), + 'import_transaction_id', + 'payment_order_id', + string="Payment order to reconcile", + type='many2one', + relation='payment.order', + ), 'manual_payment_order_id': fields.many2one( - 'payment.order', 'Match this payment order', - domain=[('state', '=', 'sent')]), + 'payment.order', + 'Match this payment order', + domain=[ + ('state', '=', 'sent'), + ], + ), 'manual_payment_line_id': fields.many2one( - 'payment.line', 'Match this payment line', + 'payment.line', + 'Match this payment line', domain=[ ('order_id.state', '=', 'sent'), ('date_done', '=', False), - ]), - } + ], + ), + } diff --git a/account_banking_payment/model/payment_line.py b/account_banking_payment/model/payment_line.py index 1cf14c614..0d41a966e 100644 --- a/account_banking_payment/model/payment_line.py +++ b/account_banking_payment/model/payment_line.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -27,6 +27,7 @@ from openerp.osv import orm, fields from openerp import netsvc from openerp.tools.translate import _ + class payment_line(orm.Model): ''' Add some fields; make destination bank account @@ -40,7 +41,7 @@ class payment_line(orm.Model): 'date_done': fields.date( 'Date Confirmed', select=True, readonly=True), 'transit_move_line_id': fields.many2one( - # this line is part of the credit side of move 2a + # this line is part of the credit side of move 2a # from the documentation 'account.move.line', 'Debit move line', readonly=True, @@ -57,7 +58,7 @@ class payment_line(orm.Model): account_direct_debit module. """ def get_storno_account_id(self, cr, uid, payment_line_id, amount, - currency_id, context=None): + currency_id, context=None): """ Hook for verifying a match of the payment line with the amount. Return the account associated with the storno. @@ -115,19 +116,21 @@ class payment_line(orm.Model): if (not transit_move_line or not torec_move_line): raise orm.except_orm( _('Can not reconcile'), - _('No move line for line %s') % payment_line.name) - if torec_move_line.reconcile_id: # torec_move_line.reconcile_partial_id: + _('No move line for line %s') % payment_line.name + ) + if torec_move_line.reconcile_id: raise orm.except_orm( _('Error'), - _('Move line %s has already been reconciled') % + _('Move line %s has already been reconciled') % torec_move_line.name ) - if transit_move_line.reconcile_id or transit_move_line.reconcile_partial_id: + if (transit_move_line.reconcile_id + or transit_move_line.reconcile_partial_id): raise orm.except_orm( _('Error'), - _('Move line %s has already been reconciled') % + _('Move line %s has already been reconciled') % transit_move_line.name - ) + ) def is_zero(total): return self.pool.get('res.currency').is_zero( @@ -136,7 +139,7 @@ class payment_line(orm.Model): line_ids = [transit_move_line.id, torec_move_line.id] if torec_move_line.reconcile_partial_id: line_ids = [ - x.id for x in + x.id for x in torec_move_line.reconcile_partial_id.line_partial_ids ] + [transit_move_line.id] @@ -144,7 +147,9 @@ class payment_line(orm.Model): vals = { 'type': 'auto', 'line_id': is_zero(total) and [(6, 0, line_ids)] or [(6, 0, [])], - 'line_partial_ids': is_zero(total) and [(6, 0, [])] or [(6, 0, line_ids)], + 'line_partial_ids': (is_zero(total) + and [(6, 0, [])] + or [(6, 0, line_ids)]), } if torec_move_line.reconcile_partial_id: From 542947c972a93880609bcdf4697146fa9c63970e Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:00:45 -0400 Subject: [PATCH 12/29] PEP8 on account_banking_partner_journal_account --- account_banking_partner_journal_account/__openerp__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/account_banking_partner_journal_account/__openerp__.py b/account_banking_partner_journal_account/__openerp__.py index 7a042283e..20b4e80bd 100644 --- a/account_banking_partner_journal_account/__openerp__.py +++ b/account_banking_partner_journal_account/__openerp__.py @@ -4,8 +4,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -18,7 +18,8 @@ # ############################################################################## { - 'name': 'Banking Addons - Default partner journal accounts for bank transactions', + 'name': 'Banking Addons - Default partner journal accounts for bank' + ' transactions', 'version': '0.1', 'license': 'AGPL-3', 'author': 'Therp BV', From 5be910f8865f5ea0d4144a845c8012538c50df42 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:03:35 -0400 Subject: [PATCH 13/29] PEP8 on account_banking_pain_base --- account_banking_pain_base/__openerp__.py | 11 ++++++++--- account_banking_pain_base/company.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/account_banking_pain_base/__openerp__.py b/account_banking_pain_base/__openerp__.py index 71c52d5d0..f2a6ad0d0 100644 --- a/account_banking_pain_base/__openerp__.py +++ b/account_banking_pain_base/__openerp__.py @@ -40,11 +40,16 @@ Base module for PAIN file generation ==================================== -This module contains fields and functions that are used by the module for SEPA Credit Transfer (account_banking_sepa_credit_transfer) and SEPA Direct Debit (account_banking_sepa_direct_debit). This module doesn't provide any functionnality by itself. +This module contains fields and functions that are used by the module for SEPA +Credit Transfer (account_banking_sepa_credit_transfer) and SEPA Direct Debit +(account_banking_sepa_direct_debit). This module doesn't provide any +functionnality by itself. -This module is part of the banking addons: https://launchpad.net/banking-addons +This module is part of the banking addons: + https://www.github.com/OCA/banking-addons -This module was started during the Akretion-Noviat code sprint of November 21st 2013 in Epiais les Louvres (France). +This module was started during the Akretion-Noviat code sprint of +November 21st 2013 in Epiais les Louvres (France). ''', 'active': False, 'installable': True, diff --git a/account_banking_pain_base/company.py b/account_banking_pain_base/company.py index 94864d548..222786c27 100644 --- a/account_banking_pain_base/company.py +++ b/account_banking_pain_base/company.py @@ -50,7 +50,7 @@ class res_company(orm.Model): if country_code == 'BE': party_identifier = company_vat[2:].replace(' ', '') elif country_code == 'ES': - party_identifier = company.sepa_creditor_identifier + party_identifier = company.sepa_creditor_identifier return party_identifier def _initiating_party_issuer_default(self, cr, uid, context=None): From 3b22d7e5fca7efe15a71ddcd328b92b39c846fa9 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:08:50 -0400 Subject: [PATCH 14/29] PEP8 on account_banking_nl_triodos --- account_banking_nl_triodos/__init__.py | 7 +- account_banking_nl_triodos/__openerp__.py | 4 +- account_banking_nl_triodos/triodos.py | 103 ++++++++++++---------- 3 files changed, 59 insertions(+), 55 deletions(-) diff --git a/account_banking_nl_triodos/__init__.py b/account_banking_nl_triodos/__init__.py index 18248e3ef..8bc732eeb 100644 --- a/account_banking_nl_triodos/__init__.py +++ b/account_banking_nl_triodos/__init__.py @@ -13,8 +13,8 @@ # 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 +# 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, @@ -26,6 +26,5 @@ # along with this program. If not, see . # ############################################################################## -import triodos -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import triodos diff --git a/account_banking_nl_triodos/__openerp__.py b/account_banking_nl_triodos/__openerp__.py index 72d451805..fb744ed78 100644 --- a/account_banking_nl_triodos/__openerp__.py +++ b/account_banking_nl_triodos/__openerp__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, diff --git a/account_banking_nl_triodos/triodos.py b/account_banking_nl_triodos/triodos.py index deca77764..3b3ccadd1 100644 --- a/account_banking_nl_triodos/triodos.py +++ b/account_banking_nl_triodos/triodos.py @@ -6,8 +6,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -28,10 +28,9 @@ 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 datetime import datetime + from account_banking.parsers import models from account_banking.parsers.convert import str2date -from account_banking.sepa import postalcode from tools.translate import _ import re @@ -41,6 +40,7 @@ __all__ = ['parser'] bt = models.mem_bank_transaction + class transaction_message(object): ''' A auxiliary class to validate and coerce read values @@ -72,50 +72,57 @@ class transaction_message(object): 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', - ] + 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 + '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): @@ -129,9 +136,9 @@ class transaction(models.mem_bank_transaction): self.message = '' # Decompose structured messages self.parse_message() - if (self.transfer_type == 'OV' and - not self.remote_account and - not self.remote_owner): + if (self.transfer_type == 'OV' + and not self.remote_account + and not self.remote_owner): self.transfer_type = 'KN' def is_valid(self): @@ -141,8 +148,7 @@ class transaction(models.mem_bank_transaction): 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' - ]: + 'KN', 'TG', 'GA', 'BA', 'CHIP']: self.error_message = ( "No remote account for transaction type %s" % self.transfer_type) @@ -172,7 +178,7 @@ class statement(models.mem_bank_statement): 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.start_balance = self.end_balance = 0 # msg.start_balance self.import_transaction(msg) def import_transaction(self, msg): @@ -183,6 +189,7 @@ class statement(models.mem_bank_statement): self.end_balance += trans.transferred_amount self.transactions.append(trans) + class parser(models.parser): code = 'TRIOD' country_code = 'NL' @@ -220,5 +227,3 @@ Statements. stmnt = statement(msg) result.append(stmnt) return result - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 2e786f24fccd4d48dcbcd32b59c4638c29ac5d5b Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:12:40 -0400 Subject: [PATCH 15/29] PEP8 on account_banking_nl_multibank --- account_banking_nl_multibank/multibank.py | 43 ++++++++++++----------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/account_banking_nl_multibank/multibank.py b/account_banking_nl_multibank/multibank.py index 5eee004df..23817e1e2 100644 --- a/account_banking_nl_multibank/multibank.py +++ b/account_banking_nl_multibank/multibank.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -37,6 +37,7 @@ __all__ = ['parser'] bt = models.mem_bank_transaction + class transaction_message(object): ''' A auxiliary class to validate and coerce read values @@ -60,7 +61,7 @@ class transaction_message(object): 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 + if len(accountno) == 10: # Invalid: longest number is 9 accountno = accountno[1:] # 9-scheme or 7-scheme? stripped = accountno.lstrip('0') @@ -73,18 +74,18 @@ class transaction_message(object): 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)) + raise ValueError( + _('Invalid transaction line: expected %d columns, found %d') + % (len(self.attrnames), len(values)) + ) self.__dict__.update(dict(zip(self.attrnames, values))) - #self.local_account = self.clean_account(self.local_account) - #self.remote_account = self.clean_account(self.remote_account) 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. @@ -93,7 +94,7 @@ class transaction(models.mem_bank_transaction): 'remote_owner', 'remote_currency', 'transferred_amount', 'execution_date', 'value_date', 'transfer_type', 'reference', 'message', 'statement_id', 'id', - ] + ] type_map = { 'ACC': bt.ORDER, @@ -151,14 +152,12 @@ class transaction(models.mem_bank_transaction): 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 - ) + 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): ''' @@ -172,7 +171,7 @@ class transaction(models.mem_bank_transaction): elif self.transfer_type == 'BEA': # Payment through payment terminal - # Remote owner is part of message, while remote_owner is set + # 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() @@ -188,8 +187,10 @@ class transaction(models.mem_bank_transaction): # 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.' + self.error_message = ( + 'Remote currency in message differs from ' + 'transaction.' + ) else: self.local_amount = float(amount) elif part.startswith('koers. '): @@ -262,6 +263,7 @@ class transaction(models.mem_bank_transaction): parts = parts[:-1] self.message = ' '.join(parts) + class statement(models.mem_bank_statement): ''' Implementation of bank_statement communication class of account_banking @@ -285,6 +287,7 @@ class statement(models.mem_bank_statement): self.end_balance += trans.transferred_amount self.transactions.append(trans) + class parser(models.parser): code = 'NLBT' country_code = 'NL' From 4c480d1084fa2979bf61456e7a4537c697a56b2e Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:14:38 -0400 Subject: [PATCH 16/29] PEP8 on account_banking_nl_ing_mt940 --- account_banking_nl_ing_mt940/__openerp__.py | 16 ++++++++-------- .../account_banking_nl_ing_mt940.py | 9 ++++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/account_banking_nl_ing_mt940/__openerp__.py b/account_banking_nl_ing_mt940/__openerp__.py index 112721951..d75d19ce7 100644 --- a/account_banking_nl_ing_mt940/__openerp__.py +++ b/account_banking_nl_ing_mt940/__openerp__.py @@ -19,19 +19,19 @@ # ############################################################################## { - "name" : "MT940 import for Dutch ING", - "version" : "1.1", - "author" : "Therp BV", + "name": "MT940 import for Dutch ING", + "version": "1.1", + "author": "Therp BV", "complexity": "normal", "description": """ This addon imports the structured MT940 format as offered by the Dutch ING bank. """, - "category" : "Account Banking", - "depends" : [ + "category": "Account Banking", + "depends": [ 'account_banking_mt940', ], - "data" : [ + "data": [ ], "js": [ ], @@ -42,7 +42,7 @@ bank. "auto_install": False, "installable": True, "application": False, - "external_dependencies" : { - 'python' : [], + "external_dependencies": { + 'python': [], }, } diff --git a/account_banking_nl_ing_mt940/account_banking_nl_ing_mt940.py b/account_banking_nl_ing_mt940/account_banking_nl_ing_mt940.py index 5c877c890..8591fa454 100644 --- a/account_banking_nl_ing_mt940/account_banking_nl_ing_mt940.py +++ b/account_banking_nl_ing_mt940/account_banking_nl_ing_mt940.py @@ -20,8 +20,10 @@ ############################################################################## import re from openerp.tools.translate import _ -from openerp.addons.account_banking.parsers.models import parser,\ - mem_bank_transaction +from openerp.addons.account_banking.parsers.models import ( + parser, + mem_bank_transaction, +) from openerp.addons.account_banking_mt940.mt940 import MT940, str2float @@ -30,6 +32,7 @@ class transaction(mem_bank_transaction): '''allow transactions without remote account''' return bool(self.execution_date) and bool(self.transferred_amount) + class IngMT940Parser(MT940, parser): name = _('ING MT940 (structured)') country_code = 'NL' @@ -104,5 +107,5 @@ class IngMT940Parser(MT940, parser): if not subfields: self.current_transaction.message = data - + self.current_transaction = None From 894d65ab2d3b401b7762bffc2867375ffe11e928 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:18:00 -0400 Subject: [PATCH 17/29] PEP8 on account_banking_nl_ing --- account_banking_nl_ing/__openerp__.py | 4 +- account_banking_nl_ing/ing.py | 67 +++++++++++++-------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/account_banking_nl_ing/__openerp__.py b/account_banking_nl_ing/__openerp__.py index d44b23b58..6148018fa 100644 --- a/account_banking_nl_ing/__openerp__.py +++ b/account_banking_nl_ing/__openerp__.py @@ -3,9 +3,9 @@ # Copyright (C) 2011 Therp BV () # (C) 2011 Smile BV () # -# Based on account-banking +# Based on account-banking # (C) 2009 - 2011 EduSense BV () -# +# # All Rights Reserved # # This program is free software: you can redistribute it and/or modify diff --git a/account_banking_nl_ing/ing.py b/account_banking_nl_ing/ing.py index 6384f1314..7ebcb62c1 100644 --- a/account_banking_nl_ing/ing.py +++ b/account_banking_nl_ing/ing.py @@ -24,10 +24,8 @@ # ############################################################################## -from datetime import datetime from openerp.addons.account_banking.parsers import models from openerp.addons.account_banking.parsers.convert import str2date -from openerp.addons.account_banking.sepa import postalcode from openerp.tools.translate import _ import re @@ -39,10 +37,12 @@ bt = models.mem_bank_transaction """ First line states the legend -"Datum","Naam / Omschrijving","Rekening","Tegenrekening","Code","Af Bij","Bedrag (EUR)","MutatieSoort","Mededelingen +"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 @@ -68,16 +68,18 @@ class transaction_message(object): if self.debcred == 'Af': self.transferred_amount = -self.transferred_amount try: - self.execution_date = self.value_date = str2date(self.date, '%Y%m%d') + 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.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) - + self.local_account = self.local_account.replace('.', '').zfill(10) + class transaction(models.mem_bank_transaction): ''' @@ -87,30 +89,30 @@ class transaction(models.mem_bank_transaction): '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 + + '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 @@ -167,10 +169,6 @@ class transaction(models.mem_bank_transaction): in the 'name' column, as well as full address information in the 'message' column' """ - reference = '' - street = False - zipcode = False - street = False before = False if self.remote_owner.startswith('KN: '): self.reference = self.remote_owner[4:] @@ -212,8 +210,7 @@ class transaction(models.mem_bank_transaction): 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' - ]: + 'BA', 'FL', 'GM', 'IC', 'PK', 'ST']: self.error_message = ( "No remote account for transaction type %s" % self.transfer_type) @@ -225,6 +222,7 @@ class transaction(models.mem_bank_transaction): No processing done here for Triodos, maybe later. ''' + class statement(models.mem_bank_statement): ''' Implementation of bank_statement communication class of account_banking @@ -240,7 +238,7 @@ class statement(models.mem_bank_statement): 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.start_balance = self.end_balance = 0 # msg.start_balance self.import_transaction(msg) def import_transaction(self, msg): @@ -251,6 +249,7 @@ class statement(models.mem_bank_statement): self.end_balance += trans.transferred_amount self.transactions.append(trans) + class parser(models.parser): code = 'ING' country_code = 'NL' @@ -287,5 +286,3 @@ Statements. stmnt = statement(msg) result.append(stmnt) return result - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From c40e501b2e22329cf1066050014542086f7d981b Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:21:24 -0400 Subject: [PATCH 18/29] PEP8 on account_banking_nl_girotel --- account_banking_nl_girotel/__init__.py | 7 ++--- account_banking_nl_girotel/__openerp__.py | 5 ++- account_banking_nl_girotel/girotel.py | 38 ++++++++++++++--------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/account_banking_nl_girotel/__init__.py b/account_banking_nl_girotel/__init__.py index 5a82466b2..bdcb0c3d6 100644 --- a/account_banking_nl_girotel/__init__.py +++ b/account_banking_nl_girotel/__init__.py @@ -11,8 +11,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,6 +24,5 @@ # along with this program. If not, see . # ############################################################################## -import girotel -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import girotel diff --git a/account_banking_nl_girotel/__openerp__.py b/account_banking_nl_girotel/__openerp__.py index 95e94629d..f5924d0db 100644 --- a/account_banking_nl_girotel/__openerp__.py +++ b/account_banking_nl_girotel/__openerp__.py @@ -4,8 +4,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -26,7 +26,6 @@ 'category': 'Account Banking', 'depends': ['account_banking'], 'data': [ - #'security/ir.model.access.csv', ], 'description': ''' Module to import Dutch Girotel format transation files. diff --git a/account_banking_nl_girotel/girotel.py b/account_banking_nl_girotel/girotel.py index 1b111b214..d6a637758 100644 --- a/account_banking_nl_girotel/girotel.py +++ b/account_banking_nl_girotel/girotel.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -40,7 +40,8 @@ Assumptions: 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. +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, to_swift @@ -52,6 +53,7 @@ bt = models.mem_bank_transaction __all__ = ['parser'] + class transaction_message(object): ''' A auxiliary class to validate and coerce read values @@ -81,7 +83,12 @@ class transaction_message(object): 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 + return attr != ( + 'strattrs' + and attr in self.strattrs + and to_swift(retval) + or retval + ) def genid(self): ''' @@ -99,14 +106,15 @@ class transaction_message(object): 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)) + 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 + # 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)) @@ -114,7 +122,7 @@ class transaction_message(object): self.transfer_type = 'PB' self.message = self.remote_owner self.remove_owner = False - #payment batch done via sepa + # payment batch done via sepa if self.transfer_type == 'VZ'\ and not self.remote_account\ and not self.remote_owner\ @@ -144,10 +152,10 @@ class transaction(models.mem_bank_transaction): ''' Implementation of transaction communication class for account_banking. ''' - attrnames = [ 'statement_id', 'remote_account', 'remote_owner', + attrnames = ['statement_id', 'remote_account', 'remote_owner', 'remote_currency', 'transferred_amount', 'execution_date', 'value_date', 'transfer_type', 'message', - ] + ] type_map = { 'BA': bt.PAYMENT_TERMINAL, @@ -225,7 +233,7 @@ class transaction(models.mem_bank_transaction): 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]) @@ -246,7 +254,7 @@ class transaction(models.mem_bank_transaction): 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 @@ -256,7 +264,7 @@ class transaction(models.mem_bank_transaction): # 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: @@ -306,6 +314,7 @@ class transaction(models.mem_bank_transaction): # message parts. self.message = self.refold_message(self.message) + class statement(models.mem_bank_statement): ''' Implementation of bank_statement communication class of account_banking @@ -329,6 +338,7 @@ class statement(models.mem_bank_statement): self.end_balance += trans.transferred_amount self.transactions.append(trans) + class parser(models.parser): code = 'NLGT' name = _('Dutch Girotel - Kommagescheiden') From 024d12454e3ac1392536b81187d3d9a0f98eabf9 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 13:37:43 -0400 Subject: [PATCH 19/29] PEP8 on account_banking_nl_clieop --- account_banking_nl_clieop/__init__.py | 9 +- account_banking_nl_clieop/__openerp__.py | 4 +- .../account_banking_nl_clieop.py | 17 +-- .../6.1.0.63/post-fill-ir_model_id.py | 40 ++--- .../6.1.0.64/post-set-payment-order-type.py | 27 ++-- account_banking_nl_clieop/wizard/__init__.py | 7 +- account_banking_nl_clieop/wizard/clieop.py | 83 +++++++---- .../wizard/export_clieop.py | 141 ++++++++++-------- 8 files changed, 181 insertions(+), 147 deletions(-) diff --git a/account_banking_nl_clieop/__init__.py b/account_banking_nl_clieop/__init__.py index aecaf7f24..30d067840 100644 --- a/account_banking_nl_clieop/__init__.py +++ b/account_banking_nl_clieop/__init__.py @@ -11,8 +11,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,7 +24,6 @@ # along with this program. If not, see . # ############################################################################## -import wizard -import account_banking_nl_clieop -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import wizard +from . import account_banking_nl_clieop diff --git a/account_banking_nl_clieop/__openerp__.py b/account_banking_nl_clieop/__openerp__.py index e1744aa95..f64e99f89 100644 --- a/account_banking_nl_clieop/__openerp__.py +++ b/account_banking_nl_clieop/__openerp__.py @@ -4,8 +4,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, diff --git a/account_banking_nl_clieop/account_banking_nl_clieop.py b/account_banking_nl_clieop/account_banking_nl_clieop.py index 97925c8f4..147989121 100644 --- a/account_banking_nl_clieop/account_banking_nl_clieop.py +++ b/account_banking_nl_clieop/account_banking_nl_clieop.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -19,7 +19,6 @@ # ############################################################################## -from datetime import date from openerp.osv import orm, fields from openerp.tools.translate import _ @@ -45,7 +44,7 @@ class clieop_export(orm.Model): 'duplicates': fields.integer('Number of Duplicates', readonly=True), 'prefered_date': - fields.date('Prefered Processing Date',readonly=True), + fields.date('Prefered Processing Date', readonly=True), 'no_transactions': fields.integer('Number of Transactions', readonly=True), 'check_no_accounts': @@ -81,13 +80,13 @@ class clieop_export(orm.Model): ''' last = 1 last_ids = self.search(cr, uid, [ - ('date_generated', '=', - fields.date.context_today(self, cr,uid,context)) - ], context=context) + ('date_generated', '=', fields.date.context_today( + self, cr, uid, context)), + ], context=context) if last_ids: last = 1 + max([x['daynumber'] for x in self.read( - cr, uid, last_ids, ['daynumber'], - context=context)]) + cr, uid, last_ids, ['daynumber'], context=context)] + ) return last _defaults = { diff --git a/account_banking_nl_clieop/migrations/6.1.0.63/post-fill-ir_model_id.py b/account_banking_nl_clieop/migrations/6.1.0.63/post-fill-ir_model_id.py index a0a2810b9..018f21816 100644 --- a/account_banking_nl_clieop/migrations/6.1.0.63/post-fill-ir_model_id.py +++ b/account_banking_nl_clieop/migrations/6.1.0.63/post-fill-ir_model_id.py @@ -4,8 +4,8 @@ # Copyright (C) 2011 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 +# 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, @@ -20,25 +20,27 @@ """ This script covers the migration of the payment wizards from old style to new style (osv_memory). It guarantees an easy upgrade for early adopters -of the 6.0 branch of this OpenERP module. Note that a migration from OpenERP +of the 6.0 branch of this OpenERP module. Note that a migration from OpenERP 5.0 to OpenERP 6.0 with respect to this module is not covered by this script. """ -__name__ = "payment.mode.type:: Add new style payment wizards to existing payment mode types" +__name__ = ("payment.mode.type:: Add new style payment wizards to existing " + "payment mode types") + def migrate(cr, version): - cr.execute ("UPDATE payment_mode_type" - " SET ir_model_id = data1.res_id" - " FROM ir_model_data data1," - " ir_model_data data2" - " WHERE data2.res_id = payment_mode_type.id" - " AND data1.module = 'account_banking_nl_clieop'" - " AND data1.model = 'ir.model'" - " AND data1.name = 'model_banking_export_clieop_wizard'" - " AND data2.module = 'account_banking_nl_clieop'" - " AND data2.model = 'payment.mode.type'" - " AND data2.name IN ('export_clieop_inc'," - " 'export_clieop_pay'," - " 'export_clieop_sal'" - " )" - ) + cr.execute("UPDATE payment_mode_type" + " SET ir_model_id = data1.res_id" + " FROM ir_model_data data1," + " ir_model_data data2" + " WHERE data2.res_id = payment_mode_type.id" + " AND data1.module = 'account_banking_nl_clieop'" + " AND data1.model = 'ir.model'" + " AND data1.name = 'model_banking_export_clieop_wizard'" + " AND data2.module = 'account_banking_nl_clieop'" + " AND data2.model = 'payment.mode.type'" + " AND data2.name IN ('export_clieop_inc'," + " 'export_clieop_pay'," + " 'export_clieop_sal'" + " )" + ) diff --git a/account_banking_nl_clieop/migrations/6.1.0.64/post-set-payment-order-type.py b/account_banking_nl_clieop/migrations/6.1.0.64/post-set-payment-order-type.py index 720573d61..edb6b257c 100644 --- a/account_banking_nl_clieop/migrations/6.1.0.64/post-set-payment-order-type.py +++ b/account_banking_nl_clieop/migrations/6.1.0.64/post-set-payment-order-type.py @@ -4,8 +4,8 @@ # Copyright (C) 2011 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 +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -18,16 +18,19 @@ # ############################################################################## -""" r64: introduction of the payment_mode_type in order to support of debit orders +"""r64: introduction of the payment_mode_type in order to support of debit +orders """ -__name__ = "payment.mode.type:: set payment_mode_type to 'debit' for Clieop incasso export" +__name__ = ("payment.mode.type:: set payment_mode_type to 'debit' for Clieop " + "incasso export") + def migrate(cr, version): - cr.execute ("UPDATE payment_mode_type" - " SET payment_order_type = 'debit'" - " FROM ir_model_data " - " WHERE res_id = payment_mode_type.id" - " AND module = 'account_banking_nl_clieop'" - " AND model = 'payment.mode.type'" - " AND ir_model_data.name = 'export_clieop_inc'" - ) + cr.execute("UPDATE payment_mode_type" + " SET payment_order_type = 'debit'" + " FROM ir_model_data " + " WHERE res_id = payment_mode_type.id" + " AND module = 'account_banking_nl_clieop'" + " AND model = 'payment.mode.type'" + " AND ir_model_data.name = 'export_clieop_inc'" + ) diff --git a/account_banking_nl_clieop/wizard/__init__.py b/account_banking_nl_clieop/wizard/__init__.py index 487cbd5c6..b8355511d 100644 --- a/account_banking_nl_clieop/wizard/__init__.py +++ b/account_banking_nl_clieop/wizard/__init__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -18,6 +18,5 @@ # along with this program. If not, see . # ############################################################################## -import export_clieop -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import export_clieop diff --git a/account_banking_nl_clieop/wizard/clieop.py b/account_banking_nl_clieop/wizard/clieop.py index 678301ff5..15eaf14ea 100644 --- a/account_banking_nl_clieop/wizard/clieop.py +++ b/account_banking_nl_clieop/wizard/clieop.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -26,7 +26,8 @@ __all__ = ['DirectDebitBatch', 'PaymentsBatch', 'DirectDebit', 'Payment', 'DirectDebitFile', 'PaymentsFile', 'SalaryPaymentsFile', 'SalaryPaymentOrder', 'PaymentOrder', 'DirectDebitOrder', 'OrdersFile', - ] + ] + class SWIFTField(record.Field): ''' @@ -37,27 +38,24 @@ class SWIFTField(record.Field): kwargs['cast'] = convert.to_swift super(SWIFTField, self).__init__(*args, **kwargs) - #def take(self, buffer): - # return convert.to_swift(super(SWIFTField, self).take(buffer)) - - #def format(self, value): - # return convert.to_swift(super(SWIFTField, self).format(value)) class SWIFTFieldNoLeadingWhitespace(SWIFTField): def format(self, value): return super(SWIFTFieldNoLeadingWhitespace, self).format( self.cast(value).lstrip()) + def eleven_test(s): ''' Dutch eleven-test for validating 9-long local bank account numbers. ''' r = 0 l = len(s) - for i,c in enumerate(s): + for i, c in enumerate(s): r += (l-i) * int(c) return (r % 11) == 0 + def chunk(str, length): ''' Split a string in equal sized substrings of length @@ -66,7 +64,8 @@ def chunk(str, length): yield str[:length] str = str[length:] -class HeaderRecord(record.Record): #{{{ + +class HeaderRecord(record.Record): '''ClieOp3 header record''' _fields = [ record.Filler('recordcode', 4, '0001'), @@ -84,7 +83,7 @@ class HeaderRecord(record.Record): #{{{ self.sender_id = id or '' self.file_id = '%02d%02d' % (self.creation_date.day, seqno) self.duplicatecode = duplicate and '2' or '1' -#}}} + class FooterRecord(record.Record): '''ClieOp3 footer record''' @@ -94,6 +93,7 @@ class FooterRecord(record.Record): record.Filler('filler', 45), ] + class BatchHeaderRecord(record.Record): '''Header record preceding new batches''' _fields = [ @@ -107,6 +107,7 @@ class BatchHeaderRecord(record.Record): record.Filler('filler', 10), ] + class BatchFooterRecord(record.Record): '''Closing record for batches''' _fields = [ @@ -118,6 +119,7 @@ class BatchFooterRecord(record.Record): record.Filler('filler', 10), ] + class FixedMessageRecord(record.Record): '''Fixed message''' _fields = [ @@ -127,6 +129,7 @@ class FixedMessageRecord(record.Record): record.Filler('filler', 13), ] + class SenderRecord(record.Record): '''Ordering party''' _fields = [ @@ -140,6 +143,7 @@ class SenderRecord(record.Record): record.Filler('filler', 2), ] + class TransactionRecord(record.Record): '''Transaction''' _fields = [ @@ -152,6 +156,7 @@ class TransactionRecord(record.Record): record.Filler('filler', 9), ] + class NamePayerRecord(record.Record): '''Name payer''' _fields = [ @@ -161,6 +166,7 @@ class NamePayerRecord(record.Record): record.Filler('filler', 10), ] + class PaymentReferenceRecord(record.Record): '''Payment reference''' _fields = [ @@ -170,6 +176,7 @@ class PaymentReferenceRecord(record.Record): record.Filler('filler', 29), ] + class DescriptionRecord(record.Record): '''Description''' _fields = [ @@ -179,6 +186,7 @@ class DescriptionRecord(record.Record): record.Filler('filler', 13), ] + class NameBeneficiaryRecord(record.Record): '''Name receiving party''' _fields = [ @@ -188,6 +196,7 @@ class NameBeneficiaryRecord(record.Record): record.Filler('filler', 10), ] + class OrderRecord(record.Record): '''Order details''' _fields = [ @@ -203,23 +212,28 @@ class OrderRecord(record.Record): record.Filler('currency', 3, 'EUR'), record.Field('testcode', 1), ] + def __init__(self, *args, **kwargs): super(OrderRecord, self).__init__(*args, **kwargs) self.batch_medium = 'DATACOM' self.name_transactioncode = self._transactioncode + class SalaryPaymentOrder(OrderRecord): '''Salary payment batch record''' _transactioncode = 'SALARIS' + class PaymentOrder(OrderRecord): '''Payment batch record''' _transactioncode = 'CREDBET' + class DirectDebitOrder(OrderRecord): '''Direct debit payments batch record''' _transactioncode = 'INCASSO' + class Optional(object): '''Auxilliary class to handle optional records''' def __init__(self, klass, max=1): @@ -233,7 +247,7 @@ class Optional(object): super(Optional, self).__setattr__(attr, value) else: if self._guts and len(self._guts) > self._max: - raise ValueError, 'Only %d lines are allowed' % self._max + raise ValueError('Only %d lines are allowed' % self._max) newitem = self._klass() setattr(newitem, attr, value) self._guts.append(newitem) @@ -259,6 +273,7 @@ class Optional(object): '''Make sure to adapt''' return self._guts.__iter__() + class OrdersFile(object): '''A payment orders file''' def __init__(self, *args, **kwargs): @@ -271,18 +286,19 @@ class OrdersFile(object): ''' return '\r\n'.join(self.orders) + class Transaction(object): '''Generic transaction class''' def __init__(self, type_=0, name=None, reference=None, messages=[], accountno_beneficiary=None, accountno_payer=None, - amount=0 - ): + amount=0): self.transaction = TransactionRecord() self.paymentreference = Optional(PaymentReferenceRecord) self.description = Optional(DescriptionRecord, 4) self.transaction.transactiontype = type_ # Remove Postbank account marker 'P' - self.transaction.accountno_beneficiary = accountno_beneficiary.replace('P', '0') + self.transaction.accountno_beneficiary = accountno_beneficiary.replace( + 'P', '0') self.transaction.accountno_payer = accountno_payer.replace('P', '0') self.transaction.amount = int(round(amount * 100)) if reference: @@ -290,8 +306,7 @@ class Transaction(object): # Allow long message lines to redistribute over multiple message # records for msg in chunk(''.join(messages), - self.description.length('description') - ): + self.description.length('description')): try: self.description.description = msg except ValueError: @@ -321,13 +336,14 @@ class DirectDebit(Transaction): items.append(str(description)) return '\r\n'.join(items) + class Payment(Transaction): '''Payment transaction''' def __init__(self, *args, **kwargs): reknr = kwargs['accountno_beneficiary'] if len(reknr.lstrip('0')) > 7: if not eleven_test(reknr): - raise ValueError, '%s is not a valid bank account' % reknr + raise ValueError('%s is not a valid bank account' % reknr) kwargs['type_'] = 5 self.name = NameBeneficiaryRecord() super(Payment, self).__init__(*args, **kwargs) @@ -346,6 +362,7 @@ class Payment(Transaction): items.append(str(self.name)) return '\r\n'.join(items) + class SalaryPayment(Payment): '''Salary Payment transaction''' def __init__(self, *args, **kwargs): @@ -353,14 +370,14 @@ class SalaryPayment(Payment): kwargs['type_'] = len(reknr.lstrip('0')) <= 7 and 3 or 8 super(SalaryPayment, self).__init__(*args, **kwargs) + class Batch(object): '''Generic batch class''' transactionclass = None def __init__(self, sender, rekeningnr, execution_date=None, test=True, messages=[], transactiongroup=None, - batch_tracer=1, batch_id='' - ): + batch_tracer=1, batch_id=''): self.header = BatchHeaderRecord() self.fixed_message = Optional(FixedMessageRecord, 4) self.sender = SenderRecord() @@ -386,18 +403,16 @@ class Batch(object): @property def total_amount(self): '''total amount transferred''' - return reduce(lambda x,y: x + int(y.transaction.amount), - self.transactions, 0 - ) + return reduce(lambda x, y: x + int(y.transaction.amount), + self.transactions, 0) @property def total_accountnos(self): '''check number on account numbers''' - return reduce(lambda x,y: - x + int(y.transaction.accountno_payer) + \ - int(y.transaction.accountno_beneficiary), - self.transactions, 0 - ) + return reduce(lambda x, y: + x + int(y.transaction.accountno_payer) + + int(y.transaction.accountno_beneficiary), + self.transactions, 0) @property def rawdata(self): @@ -423,18 +438,22 @@ class Batch(object): self.transactions.append(retval) return retval + class DirectDebitBatch(Batch): '''Direct Debig Payment batch''' transactionclass = DirectDebit + class PaymentsBatch(Batch): '''Payment batch''' transactionclass = Payment + class SalaryBatch(Batch): '''Salary payment class''' transactionclass = SalaryPayment + class ClieOpFile(object): '''The grand unifying class''' def __init__(self, identification='1', execution_date=None, @@ -461,7 +480,7 @@ class ClieOpFile(object): def batch(self, *args, **kwargs): '''Create batch''' kwargs['transactiongroup'] = self.transactiongroup - kwargs['batch_tracer'] = len(self.batches) +1 + kwargs['batch_tracer'] = len(self.batches) + 1 kwargs['execution_date'] = self._execution_date kwargs['test'] = self._test args = (self._name_sender, self._accno_sender) @@ -489,22 +508,22 @@ class ClieOpFile(object): retval.total_accountnos = total_accountnos return retval + class DirectDebitFile(ClieOpFile): '''Direct Debit Payments file''' transactiongroup = '10' batchclass = DirectDebitBatch orderclass = DirectDebitOrder + class PaymentsFile(ClieOpFile): '''Payments file''' transactiongroup = '00' batchclass = PaymentsBatch orderclass = PaymentOrder + class SalaryPaymentsFile(PaymentsFile): '''Salary Payments file''' batchclass = SalaryBatch orderclass = SalaryPaymentOrder - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/account_banking_nl_clieop/wizard/export_clieop.py b/account_banking_nl_clieop/wizard/export_clieop.py index 915c46bb6..95d86f8de 100644 --- a/account_banking_nl_clieop/wizard/export_clieop.py +++ b/account_banking_nl_clieop/wizard/export_clieop.py @@ -6,8 +6,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -21,7 +21,7 @@ ############################################################################## import base64 -from datetime import datetime, date, timedelta +from datetime import datetime, timedelta from openerp.osv import orm, fields from openerp.tools.translate import _ from openerp import netsvc @@ -29,14 +29,17 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT from openerp.addons.account_banking import sepa from openerp.addons.account_banking_nl_clieop.wizard import clieop + def strpdate(arg): '''shortcut''' return datetime.strptime(arg, DEFAULT_SERVER_DATE_FORMAT).date() + def strfdate(arg): '''shortcut''' return arg.strftime(DEFAULT_SERVER_DATE_FORMAT) + class banking_export_clieop_wizard(orm.TransientModel): _name = 'banking.export.clieop.wizard' _description = 'Client Opdrachten Export' @@ -67,10 +70,9 @@ class banking_export_clieop_wizard(orm.TransientModel): 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.' - ), + '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.'), ), 'test': fields.boolean( 'Test Run', @@ -80,9 +82,8 @@ class banking_export_clieop_wizard(orm.TransientModel): ), 'fixed_message': fields.char( 'Fixed Message', size=32, - help=('A fixed message to apply to all transactions in addition to ' - 'the individual messages.' - ), + help=('A fixed message to apply to all transactions in addition ' + 'to the individual messages.'), ), # file fields 'file_id': fields.many2one( @@ -90,7 +91,7 @@ class banking_export_clieop_wizard(orm.TransientModel): 'ClieOp File', readonly=True ), - # fields.related does not seem to support + # fields.related does not seem to support # fields of type selection 'testcode': fields.selection( [('T', _('Yes')), ('P', _('No'))], @@ -175,7 +176,9 @@ class banking_export_clieop_wizard(orm.TransientModel): Also mind that rates for batches are way higher than those for transactions. It pays to limit the number of batches. ''' - today = strpdate(fields.date.context_today(self, cr, uid, context=context)) + today = strpdate(fields.date.context_today( + self, cr, uid, context=context + )) payment_order_obj = self.pool.get('payment.order') # Payment order ids are provided in the context @@ -199,12 +202,14 @@ class banking_export_clieop_wizard(orm.TransientModel): elif payment_order.date_prefered == 'now': execution_date = today elif payment_order.date_prefered == 'due': - # Max processing date is 30 days past now, so limiting beyond that - # will catch too early payments + # Max processing date is 30 days past now, so limiting beyond + # that will catch too early payments max_date = execution_date = today + timedelta(days=31) for line in payment_order.line_ids: if line.move_line_id.date_maturity: - date_maturity = strpdate(line.move_line_id.date_maturity) + date_maturity = strpdate( + line.move_line_id.date_maturity + ) if date_maturity < execution_date: execution_date = date_maturity else: @@ -212,7 +217,8 @@ class banking_export_clieop_wizard(orm.TransientModel): if execution_date and execution_date >= max_date: raise orm.except_orm( _('Error'), - _('You can\'t create ClieOp orders more than 30 days in advance.') + _('You can\'t create ClieOp orders more than 30 days ' + 'in advance.') ) if len(runs) != 1: raise orm.except_orm( @@ -233,17 +239,19 @@ class banking_export_clieop_wizard(orm.TransientModel): ''' Wizard to actually create the ClieOp3 file ''' - payment_order_obj = self.pool.get('payment.order') clieop_export = self.browse(cr, uid, ids, context)[0] clieopfile = None for payment_order in clieop_export.payment_order_ids: if not clieopfile: # Just once: create clieop file - our_account_owner = payment_order.mode.bank_id.owner_name \ - or payment_order.mode.bank_id.partner_id.name + our_account_owner = ( + payment_order.mode.bank_id.owner_name + or payment_order.mode.bank_id.partner_id.name + ) if payment_order.mode.bank_id.state == 'iban': - our_account_nr = payment_order.mode.bank_id.acc_number_domestic + our_account_nr = ( + payment_order.mode.bank_id.acc_number_domestic) if not our_account_nr: our_account_nr = sepa.IBAN( payment_order.mode.bank_id.acc_number @@ -253,21 +261,22 @@ class banking_export_clieop_wizard(orm.TransientModel): if not our_account_nr: raise orm.except_orm( _('Error'), - _('Your bank account has to have a valid account number') + _('Your bank account has to have a valid account ' + 'number') ) - clieopfile = {'CLIEOPPAY': clieop.PaymentsFile, - 'CLIEOPINC': clieop.DirectDebitFile, - 'CLIEOPSAL': clieop.SalaryPaymentsFile, - }[clieop_export['batchtype']]( - identification = clieop_export['reference'], - execution_date = clieop_export['execution_date'], - name_sender = our_account_owner, - accountno_sender = our_account_nr, - seqno = self.pool.get( - 'banking.export.clieop').get_daynr( - cr, uid, context=context), - test = clieop_export['test'] - ) + clieopfile = { + 'CLIEOPPAY': clieop.PaymentsFile, + 'CLIEOPINC': clieop.DirectDebitFile, + 'CLIEOPSAL': clieop.SalaryPaymentsFile, + }[clieop_export['batchtype']]( + identification=clieop_export['reference'], + execution_date=clieop_export['execution_date'], + name_sender=our_account_owner, + accountno_sender=our_account_nr, + seqno=self.pool.get('banking.export.clieop').get_daynr( + cr, uid, context=context), + test=clieop_export['test'] + ) # ClieOp3 files can contain multiple batches, but we put all # orders into one single batch. Ratio behind this is that a @@ -282,8 +291,8 @@ class banking_export_clieop_wizard(orm.TransientModel): # The first payment order processed sets the reference of the # batch. batch = clieopfile.batch( - messages = messages, - batch_id = clieop_export['reference'] + messages=messages, + batch_id=clieop_export['reference'] ) for line in payment_order.line_ids: @@ -294,12 +303,13 @@ class banking_export_clieop_wizard(orm.TransientModel): _('There is insufficient information.\r\n' 'Both destination address and account ' 'number must be provided' - ) + ) ) kwargs = dict( - name = line.bank_id.owner_name or line.bank_id.partner_id.name, - amount = line.amount_currency, - reference = line.communication or None, + name=line.bank_id.owner_name + or line.bank_id.partner_id.name, + amount=line.amount_currency, + reference=line.communication or None, ) if line.communication2: kwargs['messages'] = [line.communication2] @@ -324,32 +334,32 @@ class banking_export_clieop_wizard(orm.TransientModel): else: kwargs['accountno_beneficiary'] = other_account_nr kwargs['accountno_payer'] = our_account_nr - transaction = batch.transaction(**kwargs) + batch.transaction(**kwargs) # Generate the specifics of this clieopfile order = clieopfile.order file_id = self.pool.get('banking.export.clieop').create( cr, uid, dict( - filetype = order.name_transactioncode, - identification = order.identification, - prefered_date = strfdate(order.preferred_execution_date), - total_amount = int(order.total_amount) / 100.0, - check_no_accounts = order.total_accountnos, - no_transactions = order.nr_posts, - testcode = order.testcode, - file = base64.encodestring(clieopfile.rawdata), - filename = 'Clieop03-{0}.txt'.format(order.identification), - daynumber = int(clieopfile.header.file_id[2:]), - payment_order_ids = [ - [6, 0, [x.id for x in clieop_export['payment_order_ids']]] - ], - ), context) - self.write(cr, uid, [ids[0]], dict( - filetype = order.name_transactioncode, - testcode = order.testcode, - file_id = file_id, - state = 'finish', + filetype=order.name_transactioncode, + identification=order.identification, + prefered_date=strfdate(order.preferred_execution_date), + total_amount=int(order.total_amount) / 100.0, + check_no_accounts=order.total_accountnos, + no_transactions=order.nr_posts, + testcode=order.testcode, + file=base64.encodestring(clieopfile.rawdata), + filename='Clieop03-{0}.txt'.format(order.identification), + daynumber=int(clieopfile.header.file_id[2:]), + payment_order_ids=[ + [6, 0, [x.id + for x in clieop_export['payment_order_ids']]]], ), context) + self.write(cr, uid, [ids[0]], dict( + filetype=order.name_transactioncode, + testcode=order.testcode, + file_id=file_id, + state='finish', + ), context) return { 'name': _('Client Opdrachten Export'), 'view_type': 'form', @@ -367,7 +377,9 @@ class banking_export_clieop_wizard(orm.TransientModel): Cancel the ClieOp: just drop the file ''' clieop_export = self.read(cr, uid, ids, ['file_id'], context)[0] - self.pool.get('banking.export.clieop').unlink(cr, uid, clieop_export['file_id'][0]) + self.pool.get('banking.export.clieop').unlink( + cr, uid, clieop_export['file_id'][0] + ) return {'type': 'ir.actions.act_window_close'} def save_clieop(self, cr, uid, ids, context): @@ -378,11 +390,12 @@ class banking_export_clieop_wizard(orm.TransientModel): cr, uid, ids, context)[0] if not clieop_export['test']: clieop_obj = self.pool.get('banking.export.clieop') - payment_order_obj = self.pool.get('payment.order') - clieop_file = clieop_obj.write( + clieop_obj.write( cr, uid, clieop_export['file_id'].id, {'state': 'sent'} ) wf_service = netsvc.LocalService('workflow') for order in clieop_export['payment_order_ids']: - wf_service.trg_validate(uid, 'payment.order', order.id, 'sent', cr) + wf_service.trg_validate( + uid, 'payment.order', order.id, 'sent', cr + ) return {'type': 'ir.actions.act_window_close'} From 2bf58e25bf710736b3a75b23f6ca03454f7d8954 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 14:02:50 -0400 Subject: [PATCH 20/29] PEP8 on account_banking_fi_patu --- account_banking_fi_patu/__init__.py | 7 +- account_banking_fi_patu/__openerp__.py | 5 +- account_banking_fi_patu/parser.py | 245 ++++++++++++++----------- account_banking_fi_patu/patu.py | 34 ++-- 4 files changed, 159 insertions(+), 132 deletions(-) diff --git a/account_banking_fi_patu/__init__.py b/account_banking_fi_patu/__init__.py index cb9c0843f..3d20640b5 100644 --- a/account_banking_fi_patu/__init__.py +++ b/account_banking_fi_patu/__init__.py @@ -12,8 +12,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -25,6 +25,5 @@ # along with this program. If not, see . # ############################################################################## -import patu -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import patu diff --git a/account_banking_fi_patu/__openerp__.py b/account_banking_fi_patu/__openerp__.py index 8f2f557b7..35443d4fa 100644 --- a/account_banking_fi_patu/__openerp__.py +++ b/account_banking_fi_patu/__openerp__.py @@ -11,8 +11,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,6 +24,7 @@ # along with this program. If not, see . # ############################################################################## + { 'name': 'Account Banking PATU module', 'version': '0.62', diff --git a/account_banking_fi_patu/parser.py b/account_banking_fi_patu/parser.py index d5754ba1c..5d5d0bd3b 100644 --- a/account_banking_fi_patu/parser.py +++ b/account_banking_fi_patu/parser.py @@ -1,7 +1,9 @@ #!/usr/bin/env python # encoding: utf-8 """Parser for PATU format files""" -import re, datetime +import re +import datetime + def fixchars(line): """Fix the characters mangled in the input @@ -20,107 +22,120 @@ def fixchars(line): class PatuParser(object): """Parse PATU lines in to structs""" - def __init__( self ): + def __init__(self): """ Initialize PATU parser """ recparse = dict() - recparse["00"] = "T(?P00)(?P\d{3})" \ - + "(?P\d{3})(?P\d{14})" \ - + "(?P\d{3})(?P\d{6})" \ - + "(?P\d{6})" \ - + "(?P\d{6})(?P\d{4})" \ - + "(?P.{17})(?P\d{6})" \ - + "(?P.{19})" \ - + "(?P\d{6})(?P.{3})" \ - + "(?P.{30})"\ - + "(?P\d{18})(?P.{35})" \ - + "(?P.{40})(?P.{40})" \ - + "(?P.{30})(?P.{30})" - recparse["10"] = "T(?P[18]0)(?P\d{3})" \ - + "(?P\d{6})" \ - + "(?P.{18})(?P\d{6})" \ - + "(?P\d{6})" \ - + "(?P\d{6})(?P\d)" \ - + "(?P.{3})(?P.{35})" \ - + "(?P.{19})(?P.)(?P.)" \ - + "(?P.{35})(?P.)" \ - + "(?P.{14})(?P.)" \ - + "(?P.{20})" \ - + "(?P.{8})(?P.)" - recparse["11"] = "T(?P[18]1)(?P\d{3})" \ - + "(?P.{2})" \ - + "(?:(?# Match specific info)" \ - + "(?<=00)(?P.{35})+" \ - + "|" \ - + "(?<=01)(?P\d{8})" \ - + "|" \ - + "(?<=02)(?P.{10})\s(?P.{15})\s" \ - + "(?P\d{6})" \ - + "|" \ - + "(?<=03)(?P.{19})\s(?P.{14})" \ - + "|" \ - + "(?<=04)(?P.{18})" \ - + "|" \ - + "(?<=05)(?P.{19})\s(?P.{3})\s" \ - + "(?P.{11})(?P.{6})" \ - + "|" \ - + "(?<=06)(?P.{35})(?P.{35})" \ - + "|" \ - + "(?<=07)(?P.{35})" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "(?P.{35})?" \ - + "|" \ - + "(?<=08)(?P\d{3})\s(?P.{31})" \ - + "|" \ - + "(?<=09)(?P.{35})" \ - + "|" \ - + "(?<=11)(?P.{35})(?P.{35})" \ - + "(?P.{35})(?P.{70})" \ - + "(?P.{70})(?P.{35})" \ - + "(?P.{70})" \ - + ")" - recparse["40"] = "T(?P40)(?P\d{3})" \ - + "(?P\d{6})(?P.{19})" \ - + "(?P.{19})" - recparse["50"] = "T(?P50)(?P\d{3})" \ - + "(?P\d)(?P\d{6})" \ - + "(?P\d{8})(?P.{19})" \ - + "(?P\d{8})(?P.{19})" - recparse["60"] = "T(?P60)(?P\d{3})" \ - + "(?P.{3})(?P01)" \ - + "(?P\d{6})-" \ - + "(?P\d{6})" \ - + "(?P.)(?P.{19})" \ - + "(?P.)(?P\d{7})" \ - + "(?P.)(?P.{19})" \ - + "(?P.)(?P\d{7})" \ - + "(?P.)(?P\d{7})" \ - + "(?P.)(?P.{19})" \ - + "(?P.)(?P.{35})" \ - + "(?P\d{7})" \ - + "(?P.)(?P.{35})" \ - + "(?P\d{7})" - recparse["70"] = "T(?P70)(?P\d{3})" \ - + "(?P\d{3})" \ - + "(?P.{80})" \ - + "(?P.{80})?" \ - + "(?P.{80})?" \ - + "(?P.{80})?" \ - + "(?P.{80})?" \ - + "(?P.{80})?" + recparse["00"] = ( + "T(?P00)(?P\d{3})" + "(?P\d{3})(?P\d{14})" + "(?P\d{3})(?P\d{6})" + "(?P\d{6})" + "(?P\d{6})(?P\d{4})" + "(?P.{17})(?P\d{6})" + "(?P.{19})" + "(?P\d{6})(?P.{3})" + "(?P.{30})" + "(?P\d{18})(?P.{35})" + "(?P.{40})(?P.{40})" + "(?P.{30})(?P.{30})" + ) + recparse["10"] = ( + "T(?P[18]0)(?P\d{3})" + "(?P\d{6})" + "(?P.{18})(?P\d{6})" + "(?P\d{6})" + "(?P\d{6})(?P\d)" + "(?P.{3})(?P.{35})" + "(?P.{19})(?P.)(?P.)" + "(?P.{35})(?P.)" + "(?P.{14})(?P.)" + "(?P.{20})" + "(?P.{8})(?P.)" + ) + recparse["11"] = ( + "T(?P[18]1)(?P\d{3})" + "(?P.{2})" + "(?:(?# Match specific info)" + "(?<=00)(?P.{35})+" + "|" + "(?<=01)(?P\d{8})" + "|" + "(?<=02)(?P.{10})\s(?P.{15})\s" + "(?P\d{6})" + "|" + "(?<=03)(?P.{19})\s(?P.{14})" + "|" + "(?<=04)(?P.{18})" + "|" + "(?<=05)(?P.{19})\s(?P.{3})\s" + "(?P.{11})(?P.{6})" + "|" + "(?<=06)(?P.{35})(?P.{35})" + "|" + "(?<=07)(?P.{35})" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "(?P.{35})?" + "|" + "(?<=08)(?P\d{3})\s(?P.{31})" + "|" + "(?<=09)(?P.{35})" + "|" + "(?<=11)(?P.{35})(?P.{35})" + "(?P.{35})(?P.{70})" + "(?P.{70})(?P.{35})" + "(?P.{70})" + ")" + ) + recparse["40"] = ( + "T(?P40)(?P\d{3})" + "(?P\d{6})(?P.{19})" + "(?P.{19})" + ) + recparse["50"] = ( + "T(?P50)(?P\d{3})" + "(?P\d)(?P\d{6})" + "(?P\d{8})(?P.{19})" + "(?P\d{8})(?P.{19})" + ) + recparse["60"] = ( + "T(?P60)(?P\d{3})" + "(?P.{3})(?P01)" + "(?P\d{6})-" + "(?P\d{6})" + "(?P.)(?P.{19})" + "(?P.)(?P\d{7})" + "(?P.)(?P.{19})" + "(?P.)(?P\d{7})" + "(?P.)(?P\d{7})" + "(?P.)(?P.{19})" + "(?P.)(?P.{35})" + "(?P\d{7})" + "(?P.)(?P.{35})" + "(?P\d{7})" + ) + recparse["70"] = ( + "T(?P70)(?P\d{3})" + "(?P\d{3})" + "(?P.{80})" + "(?P.{80})?" + "(?P.{80})?" + "(?P.{80})?" + "(?P.{80})?" + "(?P.{80})?" + ) for record in recparse: recparse[record] = re.compile(recparse[record]) self.recparse = recparse - def parse_record(self, line): """Docstring for parse_perus @@ -135,7 +150,7 @@ class PatuParser(object): if matchobj: break if not matchobj: - print " **** failed to match line '%s'" % (line) + print(" **** failed to match line '%s'" % (line)) return # Strip strings matchdict = matchobj.groupdict() @@ -146,7 +161,8 @@ class PatuParser(object): del matchdict[field] matchkeys = set(matchdict.keys()) - needstrip = set(["bankcontact1", "bankcontact2", "bankcontact3", + needstrip = set([ + "bankcontact1", "bankcontact2", "bankcontact3", "customerid", "accountowner", "accountname", "refnr", "formnr", "recipientname", "eventdesc", "recipientaccount", "message", "principalinfo1", "bankinfo1", "bankinfo2", "bankinfo3", @@ -158,30 +174,35 @@ class PatuParser(object): for field in matchkeys & needstrip: matchdict[field] = matchdict[field].strip() # Convert to int - needsint = set(["itemcount", "eventid", "record_len", + 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", + 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", + 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 matchdict.has_key("ibanswift"): - matchdict["iban"], matchdict["swift"] = \ - matchdict["ibanswift"].strip().split() + if "ibanswift" in matchdict: + matchdict["iban"], matchdict["swift"] = ( + matchdict["ibanswift"].strip().split() + ) # Convert date fields - needdate = set(["startdate", "enddate", "creationdate", "balancedate", + 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 @@ -191,17 +212,20 @@ class PatuParser(object): matchdict[field] = None continue - matchdict[field] = datetime.date(int("20" + datestring[0:2]), - int(datestring[2:4]), int(datestring[4:6])) + 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])) + matchdict[field] = datetime.time( + int(timestring[0:2]), + int(timestring[2:4])) return matchdict + def parse_file(filename): """Parse file with PATU format inside @@ -214,6 +238,7 @@ def parse_file(filename): for line in patufile: parser.parse_record(line) + def main(): """The main function, currently just calls a dummy filename @@ -223,5 +248,3 @@ def main(): if __name__ == '__main__': main() - - diff --git a/account_banking_fi_patu/patu.py b/account_banking_fi_patu/patu.py index 329f8c7a3..dadf2c2eb 100644 --- a/account_banking_fi_patu/patu.py +++ b/account_banking_fi_patu/patu.py @@ -6,8 +6,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -30,20 +30,23 @@ from 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"} + "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. @@ -63,19 +66,19 @@ class transaction(models.mem_bank_transaction): If eventcode is 730, the transaction was initiated by the bank and doesn't have a destination account. ''' - if self.eventcode and (self.eventcode == "720" or self.eventcode == - "710"): + 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 + 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 + or False return super(transaction, self).is_valid() + class statement(models.mem_bank_statement): ''' Implementation of bank_statement communication class of account_banking @@ -110,6 +113,7 @@ class statement(models.mem_bank_statement): return self.transactions.append(transaction(record)) + class parser(models.parser): code = 'FIPATU' name = _('PATU statement sheet') From 07729d6a80d451521f3a39d8862f156a11840225 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Aug 2014 14:05:45 -0400 Subject: [PATCH 21/29] PEP8 on account_banking_payment --- account_banking_payment/model/payment_mode.py | 4 ++-- account_banking_payment/model/payment_order_create.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/account_banking_payment/model/payment_mode.py b/account_banking_payment/model/payment_mode.py index 7a3e1be98..d45f56df9 100644 --- a/account_banking_payment/model/payment_mode.py +++ b/account_banking_payment/model/payment_mode.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -44,7 +44,7 @@ class payment_mode(orm.Model): 'a debit order of this mode'), ), 'payment_term_ids': fields.many2many( - 'account.payment.term', 'account_payment_order_terms_rel', + 'account.payment.term', 'account_payment_order_terms_rel', 'mode_id', 'term_id', 'Payment terms', help=('Limit selected invoices to invoices with these payment ' 'terms') diff --git a/account_banking_payment/model/payment_order_create.py b/account_banking_payment/model/payment_order_create.py index 7d071b44e..dd4f07fec 100644 --- a/account_banking_payment/model/payment_order_create.py +++ b/account_banking_payment/model/payment_order_create.py @@ -4,7 +4,7 @@ # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). # (C) 2014 ACSONE SA/NV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved From 1a6763368e1ed5375a2b6984a4b9a624a9f16a1c Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Tue, 2 Sep 2014 12:36:36 -0400 Subject: [PATCH 22/29] PEP8 on account_banking --- account_banking/__init__.py | 7 +- account_banking/__openerp__.py | 3 +- account_banking/account_banking.py | 258 +++++--- account_banking/banking_import_transaction.py | 607 ++++++++++-------- .../post-set-statement-line-state.py | 17 +- .../migrations/7.0.0.1/pre-migration.py | 3 +- .../migrations/7.0.0.3/pre-migration.py | 1 + .../migrations/7.0.0.4/pre-migration.py | 2 + account_banking/parsers/__init__.py | 6 +- account_banking/parsers/convert.py | 13 +- account_banking/parsers/models.py | 34 +- account_banking/record.py | 46 +- account_banking/res_bank.py | 4 +- account_banking/res_partner.py | 2 +- account_banking/sepa/iban.py | 66 +- account_banking/sepa/postalcode.py | 20 +- account_banking/struct.py | 8 +- account_banking/wizard/__init__.py | 11 +- account_banking/wizard/bank_import.py | 189 +++--- .../wizard/banking_transaction_wizard.py | 184 +++--- account_banking/wizard/banktools.py | 75 ++- account_banking/wizard/link_partner.py | 29 +- 22 files changed, 917 insertions(+), 668 deletions(-) diff --git a/account_banking/__init__.py b/account_banking/__init__.py index 1d7fc15bc..d7a19ee70 100644 --- a/account_banking/__init__.py +++ b/account_banking/__init__.py @@ -11,8 +11,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,6 +24,7 @@ # along with this program. If not, see . # ############################################################################## + import sepa import record import banking_import_transaction @@ -33,5 +34,3 @@ import wizard import res_partner import res_bank import res_partner_bank - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/__openerp__.py b/account_banking/__openerp__.py index bb2385407..b03ad1703 100644 --- a/account_banking/__openerp__.py +++ b/account_banking/__openerp__.py @@ -70,7 +70,8 @@ + IBAN accounts are the standard in the SEPA countries + local accounts are derived from SEPA (excluding Turkey) but are considered to be identical to the corresponding SEPA account. - + Banks are identified with either Country + Bank code + Branch code or BIC + + Banks are identified with either Country + Bank code + Branch code or + BIC + Each bank can have its own pace in introducing SEPA into their communication with their customers. + National online databases can be used to convert BBAN's to IBAN's. diff --git a/account_banking/account_banking.py b/account_banking/account_banking.py index 971df55ee..9aec2d8f8 100644 --- a/account_banking/account_banking.py +++ b/account_banking/account_banking.py @@ -3,7 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). -# +# # All other contributions are (C) by their respective contributors # # All Rights Reserved @@ -86,11 +86,11 @@ class account_banking_account_settings(orm.Model): string='Partner'), 'default_credit_account_id': fields.many2one( 'account.account', 'Default credit account', select=True, - help=('The account to use when an unexpected payment was signaled. ' - 'This can happen when a direct debit payment is cancelled ' + help=('The account to use when an unexpected payment was signaled.' + ' This can happen when a direct debit payment is cancelled ' 'by a customer, or when no matching payment can be found. ' - ' Mind that you can correct movements before confirming them.' - ), + 'Mind that you can correct movements before confirming them.' + ), required=True ), 'default_debit_account_id': fields.many2one( @@ -98,27 +98,27 @@ class account_banking_account_settings(orm.Model): select=True, required=True, help=('The account to use when an unexpected payment is received. ' 'This can be needed when a customer pays in advance or when ' - 'no matching invoice can be found. Mind that you can correct ' - 'movements before confirming them.' - ), + 'no matching invoice can be found. Mind that you can ' + 'correct movements before confirming them.' + ), ), 'costs_account_id': fields.many2one( 'account.account', 'Bank Costs Account', select=True, help=('The account to use when the bank invoices its own costs. ' 'Leave it blank to disable automatic invoice generation ' 'on bank costs.' - ), + ), ), 'invoice_journal_id': fields.many2one( - 'account.journal', 'Costs Journal', + '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.' - ), + ), ), } @@ -134,7 +134,7 @@ class account_banking_account_settings(orm.Model): 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) @@ -196,7 +196,7 @@ class account_banking_account_settings(orm.Model): values['journal_id'] = bank['journal_id'][0] return {'value': values} - def onchange_company_id ( + def onchange_company_id( self, cr, uid, ids, company_id=False, context=None): if not company_id: return {} @@ -229,37 +229,59 @@ class account_banking_imported_file(orm.Model): _description = __doc__ _rec_name = 'date' _columns = { - 'company_id': fields.many2one('res.company', 'Company', - select=True, readonly=True - ), - 'date': fields.datetime('Import Date', readonly=True, select=True, - states={'draft': [('readonly', False)]} - ), - 'format': fields.char('File Format', size=20, readonly=True, - states={'draft': [('readonly', False)]} - ), - 'file': fields.binary('Raw Data', readonly=True, - states={'draft': [('readonly', False)]} - ), - 'file_name': fields.char('File name', size=256), - 'log': fields.text('Import Log', readonly=True, - states={'draft': [('readonly', False)]} - ), - 'user_id': fields.many2one('res.users', 'Responsible User', - readonly=True, select=True, - states={'draft': [('readonly', False)]} - ), - 'state': fields.selection( - [('unfinished', 'Unfinished'), - ('error', 'Error'), - ('review', 'Review'), - ('ready', 'Finished'), - ], 'State', select=True, readonly=True + 'company_id': fields.many2one( + 'res.company', + 'Company', + select=True, + readonly=True, + ), + 'date': fields.datetime( + 'Import Date', + readonly=True, + select=True, + states={'draft': [('readonly', False)]}, + ), + 'format': fields.char( + 'File Format', + size=20, + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'file': fields.binary( + 'Raw Data', + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'file_name': fields.char('File name', size=256), + 'log': fields.text( + 'Import Log', + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'user_id': fields.many2one( + 'res.users', + 'Responsible User', + readonly=True, + select=True, + states={'draft': [('readonly', False)]}, + ), + 'state': fields.selection( + [ + ('unfinished', 'Unfinished'), + ('error', 'Error'), + ('review', 'Review'), + ('ready', 'Finished'), + ], + 'State', + select=True, + readonly=True, + ), + 'statement_ids': fields.one2many( + 'account.bank.statement', + 'banking_id', + 'Statements', + readonly=False, ), - 'statement_ids': fields.one2many('account.bank.statement', - 'banking_id', 'Statements', - readonly=False, - ), } _defaults = { 'date': fields.date.context_today, @@ -284,11 +306,17 @@ class account_bank_statement(orm.Model): _inherit = 'account.bank.statement' _columns = { - 'period_id': fields.many2one('account.period', 'Period', - required=False, readonly=True), - 'banking_id': fields.many2one('account.banking.imported.file', - 'Imported File', readonly=True, - ), + 'period_id': fields.many2one( + 'account.period', + 'Period', + required=False, + readonly=True, + ), + 'banking_id': fields.many2one( + 'account.banking.imported.file', + 'Imported File', + readonly=True, + ), } _defaults = { @@ -316,12 +344,12 @@ class account_bank_statement(orm.Model): 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']), + ['journal_id', 'period_id']), ] def _get_period(self, cr, uid, date=False, context=None): @@ -410,7 +438,7 @@ class account_bank_statement(orm.Model): account_move_obj.post( cr, uid, [st_line.voucher_id.move_id.id], context={}) else: - # Write stored reconcile_id and pay invoices through workflow + # 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( @@ -419,11 +447,12 @@ class account_bank_statement(orm.Model): ('account_id', '=', st_line.account_id.id)], context=context) account_move_line_obj.write(cr, uid, torec, { - (st_line.reconcile_id.line_partial_ids and - 'reconcile_partial_id' or 'reconcile_id'): - st_line.reconcile_id.id }, context=context) + (st_line.reconcile_id.line_partial_ids + and 'reconcile_partial_id' + or 'reconcile_id'): st_line.reconcile_id.id + }, context=context) for move_line in (st_line.reconcile_id.line_id or []) + ( - st_line.reconcile_id.line_partial_ids or []): + st_line.reconcile_id.line_partial_ids or []): netsvc.LocalService("workflow").trg_trigger( uid, 'account.move.line', move_line.id, cr) return res @@ -438,7 +467,7 @@ class account_bank_statement(orm.Model): if ids and isinstance(ids, (int, long)): ids = [ids] noname_ids = self.search( - cr, uid, [('id', 'in', ids),('name', '=', '/')], + cr, uid, [('id', 'in', ids), ('name', '=', '/')], context=context) for st in self.browse(cr, uid, noname_ids, context=context): if st.journal_id.sequence_id: @@ -451,7 +480,7 @@ class account_bank_statement(orm.Model): 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) @@ -464,7 +493,7 @@ class account_voucher(orm.Model): context = {} if not context.get('period_id') and context.get('move_line_ids'): move_line = self.pool.get('account.move.line').browse( - cr, uid , context.get('move_line_ids')[0], context=context) + cr, uid, context.get('move_line_ids')[0], context=context) return move_line.period_id.id return super(account_voucher, self)._get_period(cr, uid, context) @@ -498,8 +527,8 @@ class account_bank_statement_line(orm.Model): which is inaccessible from within this method. ''' res_users_obj = self.pool.get('res.users') - return res_users_obj.browse(cr, uid, uid, - context=context).company_id.currency_id.id + return res_users_obj.browse( + cr, uid, uid, context=context).company_id.currency_id.id def _get_invoice_id(self, cr, uid, ids, name, args, context=None): res = {} @@ -509,7 +538,7 @@ class account_bank_statement_line(orm.Model): 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 and st_line.import_transaction_id.move_line_id and [st_line.import_transaction_id.move_line_id] or []): if move_line.invoice: @@ -519,36 +548,70 @@ class account_bank_statement_line(orm.Model): _columns = { # Redefines. Todo: refactor away to view attrs - 'amount': fields.float('Amount', readonly=True, - digits_compute=dp.get_precision('Account'), - states={'draft': [('readonly', False)]}), - 'ref': fields.char('Ref.', size=32, readonly=True, - states={'draft': [('readonly', False)]}), - 'name': fields.char('Name', size=64, required=False, readonly=True, - states={'draft': [('readonly', False)]}), - 'date': fields.date('Date', required=True, readonly=True, - states={'draft': [('readonly', False)]}), - + 'amount': fields.float( + 'Amount', + readonly=True, + digits_compute=dp.get_precision('Account'), + states={'draft': [('readonly', False)]}, + ), + 'ref': fields.char( + 'Ref.', + size=32, + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'name': fields.char( + 'Name', + size=64, + required=False, + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'date': fields.date( + 'Date', + required=True, + readonly=True, + states={'draft': [('readonly', False)]}, + ), # New columns - 'trans': fields.char('Bank Transaction ID', size=15, required=False, - readonly=True, - states={'draft':[('readonly', False)]}, - ), - 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account', - required=False, readonly=True, - states={'draft':[('readonly', False)]}, - ), - 'period_id': fields.many2one('account.period', 'Period', required=True, - states={'confirmed': [('readonly', True)]}), - 'currency': fields.many2one('res.currency', 'Currency', required=True, - states={'confirmed': [('readonly', True)]}), + 'trans': fields.char( + 'Bank Transaction ID', + size=15, + required=False, + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'partner_bank_id': fields.many2one( + 'res.partner.bank', + 'Bank Account', + required=False, + readonly=True, + states={'draft': [('readonly', False)]}, + ), + 'period_id': fields.many2one( + 'account.period', + 'Period', + required=True, + states={'confirmed': [('readonly', True)]}, + ), + 'currency': fields.many2one( + 'res.currency', + 'Currency', + required=True, + states={'confirmed': [('readonly', True)]}, + ), 'reconcile_id': fields.many2one( - 'account.move.reconcile', 'Reconciliation', readonly=True - ), + 'account.move.reconcile', + 'Reconciliation', + readonly=True, + ), 'invoice_id': fields.function( - _get_invoice_id, method=True, string='Linked Invoice', - type='many2one', relation='account.invoice' - ), + _get_invoice_id, + method=True, + string='Linked Invoice', + type='many2one', + relation='account.invoice', + ), } _defaults = { @@ -577,9 +640,9 @@ class invoice(orm.Model): _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 + invoices that were paid with bank transfers which are being cancelled """ for invoice in self.read(cr, uid, ids, ['reconciled'], context): if invoice['reconciled']: @@ -592,22 +655,20 @@ class invoice(orm.Model): ''' return [('none', _('Free Reference')), ('structured', _('Structured Reference')), - ] + ] _columns = { 'reference_type': fields.selection(_get_reference_type, 'Reference Type', required=True - ) + ) } -invoice() - class account_move_line(orm.Model): _inherit = "account.move.line" 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 @@ -617,9 +678,6 @@ class account_move_line(orm.Model): if not ids: return total for line in self.read( - cr, uid, ids, ['debit', 'credit'], context=context): + cr, uid, ids, ['debit', 'credit'], context=context): total += (line['debit'] or 0.0) - (line['credit'] or 0.0) return total -account_move_line() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/banking_import_transaction.py b/account_banking/banking_import_transaction.py index c09a9c30b..abcfced01 100644 --- a/account_banking/banking_import_transaction.py +++ b/account_banking/banking_import_transaction.py @@ -30,7 +30,6 @@ from openerp.tools.translate import _ from openerp.addons.decimal_precision import decimal_precision as dp from openerp.addons.account_banking.parsers import models from openerp.addons.account_banking.parsers import convert -from openerp.addons.account_banking import sepa from openerp.addons.account_banking.wizard import banktools bt = models.mem_bank_transaction @@ -48,8 +47,9 @@ class banking_import_transaction(orm.Model): _description = 'Bank import transaction' _rec_name = 'transaction' - # This variable is used to match supplier invoices with an invoice date after - # the real payment date. This can occur with online transactions (web shops). + # This variable is used to match supplier invoices with an invoice date + # after the real payment date. This can occur with online transactions + # (web shops). # TODO: Convert this to a proper configuration variable payment_window = datetime.timedelta(days=10) @@ -65,7 +65,9 @@ class banking_import_transaction(orm.Model): amount = round(abs(trans.statement_line_id.amount), digits) # Make sure to be able to pinpoint our costs invoice for later # matching - reference = '%s.%s: %s' % (trans.statement, trans.transaction, trans.reference) + reference = '%s.%s: %s' % (trans.statement, + trans.transaction, + trans.reference) # search supplier invoice invoice_obj = self.pool.get('account.invoice') @@ -85,28 +87,29 @@ class banking_import_transaction(orm.Model): # create supplier invoice partner_obj = self.pool.get('res.partner') invoice_lines = [(0, 0, dict( - amount = 1, - price_unit = amount, - name = trans.message or trans.reference, - account_id = account_info.costs_account_id.id + amount=1, + price_unit=amount, + name=trans.message or trans.reference, + account_id=account_info.costs_account_id.id ))] invoice_address_id = partner_obj.address_get( cr, uid, [account_info.bank_partner_id.id], ['invoice'] ) invoice_id = invoice_obj.create(cr, uid, dict( - type = 'in_invoice', - company_id = account_info.company_id.id, - partner_id = account_info.bank_partner_id.id, - address_invoice_id = invoice_address_id['invoice'], - period_id = period_id, - journal_id = account_info.invoice_journal_id.id, - account_id = account_info.bank_partner_id.property_account_payable.id, - date_invoice = trans.execution_date, - reference_type = 'none', - reference = reference, - name = trans.reference or trans.message, - check_total = amount, - invoice_line = invoice_lines, + type='in_invoice', + company_id=account_info.company_id.id, + partner_id=account_info.bank_partner_id.id, + address_invoice_id=invoice_address_id['invoice'], + period_id=period_id, + journal_id=account_info.invoice_journal_id.id, + account_id=( + account_info.bank_partner_id.property_account_payable.id), + date_invoice=trans.execution_date, + reference_type='none', + reference=reference, + name=trans.reference or trans.message, + check_total=amount, + invoice_line=invoice_lines, )) invoice = invoice_obj.browse(cr, uid, invoice_id) # Create workflow @@ -129,8 +132,8 @@ class banking_import_transaction(orm.Model): Use the sales journal to check. Challenges we're facing: - 1. The sending or receiving party is not necessarily the same as the - partner the payment relates to. + 1. The sending or receiving party is not necessarily the same as + the partner the payment relates to. 2. References can be messed up during manual encoding and inexact matching can link the wrong invoices. 3. Amounts can or can not match the expected amount. @@ -138,8 +141,8 @@ class banking_import_transaction(orm.Model): .. There are countless more, but these we'll try to address. Assumptions for matching: - 1. There are no payments for invoices not sent. These are dealt with - later on. + 1. There are no payments for invoices not sent. These are dealt + with later on. 2. Debit amounts are either customer invoices or credited supplier invoices. 3. Credit amounts are either supplier invoices or credited customer @@ -152,8 +155,8 @@ class banking_import_transaction(orm.Model): 1. No match was made. No harm done. Proceed with manual matching as usual. 2. The wrong match was made. - Statements are encoded in draft. You will have the opportunity to - manually correct the wrong assumptions. + Statements are encoded in draft. You will have the opportunity + to manually correct the wrong assumptions. TODO: REVISE THIS DOC #Return values: @@ -170,8 +173,10 @@ class banking_import_transaction(orm.Model): ''' Return the eyecatcher for an invoice ''' - return invoice.type.startswith('in_') and invoice.name or \ - invoice.number + if invoice.type.startswith('in_'): + return invoice.name or invoice.number + else: + return invoice.number def has_id_match(invoice, ref, msg): ''' @@ -197,7 +202,8 @@ class banking_import_transaction(orm.Model): iname = invoice.name.upper() if iname in ref or iname in msg: return True - if invoice.supplier_invoice_number and len(invoice.supplier_invoice_number) > 2: + if (invoice.supplier_invoice_number + and len(invoice.supplier_invoice_number) > 2): supp_ref = invoice.supplier_invoice_number.upper() if supp_ref in ref or supp_ref in msg: return True @@ -214,8 +220,8 @@ class banking_import_transaction(orm.Model): # the interactive wizard return False - #'''Check if the move_line has been cached''' - #return move_line.id in linked_invoices + # '''Check if the move_line has been cached''' + # return move_line.id in linked_invoices def _cache(move_line, remaining=0.0): '''Cache the move_line''' @@ -228,11 +234,12 @@ class banking_import_transaction(orm.Model): def _sign(invoice): '''Return the direction of an invoice''' - return {'in_invoice': -1, - 'in_refund': 1, - 'out_invoice': 1, - 'out_refund': -1 - }[invoice.type] + return { + 'in_invoice': -1, + 'in_refund': 1, + 'out_invoice': 1, + 'out_refund': -1 + }[invoice.type] def is_zero(move_line, total): return self.pool.get('res.currency').is_zero( @@ -256,9 +263,9 @@ class banking_import_transaction(orm.Model): # Next on reference/invoice number. Mind that this uses the invoice # itself, as the move_line references have been fiddled with on invoice - # creation. This also enables us to search for the invoice number in the - # reference instead of the other way around, as most human interventions - # *add* text. + # creation. This also enables us to search for the invoice number in + # the reference instead of the other way around, as most human + # interventions *add* text. ref = trans.reference.upper() msg = trans.message.upper() if len(candidates) > 1 or not candidates: @@ -280,15 +287,15 @@ class banking_import_transaction(orm.Model): # partners. if not candidates and partner_ids: candidates = [ - x for x in move_lines - if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) - - trans.statement_line_id.amount) - and convert.str2date(x.date, '%Y-%m-%d') <= - (convert.str2date(trans.execution_date, '%Y-%m-%d') + - self.payment_window) - and (not _cached(x) or _remaining(x)) - and x.partner_id.id in partner_ids) - ] + x for x in move_lines + if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) - + trans.statement_line_id.amount) + and convert.str2date(x.date, '%Y-%m-%d') <= + (convert.str2date(trans.execution_date, '%Y-%m-%d') + + self.payment_window) + and (not _cached(x) or _remaining(x)) + and x.partner_id.id in partner_ids) + ] move_line = False @@ -297,13 +304,14 @@ class banking_import_transaction(orm.Model): # amounts expected and received. # # TODO: currency coercing - best = [x for x in candidates - if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) - - trans.statement_line_id.amount) - and convert.str2date(x.date, '%Y-%m-%d') <= - (convert.str2date(trans.execution_date, '%Y-%m-%d') + - self.payment_window)) - ] + best = [ + x for x in candidates + if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) - + trans.statement_line_id.amount) + and convert.str2date(x.date, '%Y-%m-%d') <= + (convert.str2date(trans.execution_date, '%Y-%m-%d') + + self.payment_window)) + ] if len(best) == 1: # Exact match move_line = best[0] @@ -317,21 +325,22 @@ class banking_import_transaction(orm.Model): elif len(candidates) > 1: # Before giving up, check cache for catching duplicate # transfers first - paid = [x for x in move_lines - if x.invoice and has_id_match(x.invoice, ref, msg) - and convert.str2date(x.invoice.date_invoice, '%Y-%m-%d') - <= convert.str2date(trans.execution_date, '%Y-%m-%d') - and (_cached(x) and not _remaining(x)) - ] + paid = [ + x for x in move_lines + if x.invoice and has_id_match(x.invoice, ref, msg) + and convert.str2date(x.invoice.date_invoice, '%Y-%m-%d') + <= convert.str2date(trans.execution_date, '%Y-%m-%d') + and (_cached(x) and not _remaining(x)) + ] if paid: log.append( _('Unable to link transaction id %(trans)s ' '(ref: %(ref)s) to invoice: ' 'invoice %(invoice)s was already paid') % { - 'trans': '%s.%s' % (trans.statement, trans.transaction), + 'trans': '%s.%s' % (trans.statement, + trans.transaction), 'ref': trans.reference, - 'invoice': eyecatcher(paid[0].invoice) - }) + 'invoice': eyecatcher(paid[0].invoice)}) else: # Multiple matches # TODO select best bank account in this case @@ -356,8 +365,8 @@ class banking_import_transaction(orm.Model): # Last partial payment will not flag invoice paid without # manual assistence # Stefan: disabled this here for the interactive method - # Handled this with proper handling of partial reconciliation - # and the workflow service + # Handled this with proper handling of partial + # reconciliation and the workflow service # invoice_obj = self.pool.get('account.invoice') # invoice_obj.write(cr, uid, [invoice.id], { # 'state': 'paid' @@ -369,7 +378,7 @@ class banking_import_transaction(orm.Model): account_ids = [ x.id for x in bank_account_ids if x.partner_id.id == move_line.partner_id.id - ] + ] return (trans, self._get_move_info( cr, uid, [move_line.id], @@ -396,20 +405,22 @@ class banking_import_transaction(orm.Model): _("Cannot link transaction %s with invoice") % transaction.statement_line_id.name, (transaction.invoice_ids and - (_("Please select one of the matches in transaction %s.%s") or - _("No match found for transaction %s.%s")) % ( - transaction.statement_line_id.statement_id.name, - transaction.statement_line_id.name + (_("Please select one of the matches in transaction " + "%s.%s") or + _("No match found for transaction %s.%s")) % ( + transaction.statement_line_id.statement_id.name, + transaction.statement_line_id.name ))) else: raise orm.except_orm( _("Cannot link transaction %s with accounting entry") % transaction.statement_line_id.name, (transaction.move_line_ids and - (_("Please select one of the matches in transaction %s.%s") or - _("No match found for transaction %s.%s")) % ( - transaction.statement_line_id.statement_id.name, - transaction.statement_line_id.name + (_("Please select one of the matches in transaction " + "%s.%s") or + _("No match found for transaction %s.%s")) % ( + transaction.statement_line_id.statement_id.name, + transaction.statement_line_id.name ))) st_line = transaction.statement_line_id @@ -458,9 +469,10 @@ class banking_import_transaction(orm.Model): # Define the voucher voucher = { 'journal_id': st_line.statement_id.journal_id.id, - 'partner_id': st_line.partner_id and st_line.partner_id.id or False, + 'partner_id': ( + st_line.partner_id and st_line.partner_id.id or False), 'company_id': st_line.company_id.id, - 'type':voucher_type, + 'type': voucher_type, 'account_id': account_id, 'amount': abs(st_line.amount), 'writeoff_amount': writeoff, @@ -470,12 +482,12 @@ class banking_import_transaction(orm.Model): 'date': st_line.date, 'date_due': st_line.date, 'period_id': period_id, - 'payment_rate_currency_id':to_curr_id, - } + 'payment_rate_currency_id': to_curr_id, + } # Define the voucher line vch_line = { - #'voucher_id': v_id, + # 'voucher_id': v_id, 'move_line_id': transaction.move_line_id.id, 'reconcile': True, 'amount': line_amount, @@ -490,7 +502,8 @@ class banking_import_transaction(orm.Model): {'voucher_id': voucher_id}, context=context) transaction.refresh() - def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None): + def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, + context=None): """ Legacy method. Allow for canceling bank statement lines that were confirmed using earlier versions of the interactive wizard branch. @@ -508,9 +521,14 @@ class banking_import_transaction(orm.Model): reconcile_obj = self.pool.get('account.move.reconcile') is_zero = lambda amount: self.pool.get('res.currency').is_zero( cr, uid, currency, amount) - move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context) - reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id - line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids] + move_lines = move_line_obj.browse(cr, uid, move_line_ids, + context=context) + reconcile = (move_lines[0].reconcile_id + or move_lines[0].reconcile_partial_id) + line_ids = [ + x.id + for x in reconcile.line_id or reconcile.line_partial_ids + ] for move_line_id in move_line_ids: line_ids.remove(move_line_id) if len(line_ids) > 1: @@ -522,16 +540,18 @@ class banking_import_transaction(orm.Model): line_ids = [] reconcile_obj.write( cr, uid, reconcile.id, - { 'line_partial_ids': [(6, 0, line_partial_ids)], - 'line_id': [(6, 0, line_ids)], - }, context=context) + {'line_partial_ids': [(6, 0, line_partial_ids)], + 'line_id': [(6, 0, line_ids)], + }, context=context) else: reconcile_obj.unlink(cr, uid, reconcile.id, context=context) for move_line in move_lines: if move_line.invoice: # reopening the invoice netsvc.LocalService('workflow').trg_validate( - uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr) + uid, 'account.invoice', move_line.invoice.id, 'undo_paid', + cr + ) return True def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None): @@ -550,8 +570,7 @@ class banking_import_transaction(orm.Model): context=context) return True - def _legacy_cancel_move( - self, cr, uid, transaction, context=None): + def _legacy_cancel_move(self, cr, uid, transaction, context=None): """ Legacy method to support upgrades from older installations of the interactive wizard branch. @@ -590,16 +609,15 @@ class banking_import_transaction(orm.Model): cr, uid, transaction.statement_line_id.id, {'reconcile_id': False}, context=context) - def _cancel_voucher( - self, cr, uid, transaction_id, context=None): + def _cancel_voucher(self, cr, uid, transaction_id, context=None): voucher_pool = self.pool.get('account.voucher') transaction = self.browse(cr, uid, transaction_id, context=context) st_line = transaction.statement_line_id if transaction.match_type: if st_line.voucher_id: # Although vouchers can be associated with statement lines - # in standard OpenERP, we consider ourselves owner of the voucher - # if the line has an associated transaction + # in standard OpenERP, we consider ourselves owner of the + # voucher if the line has an associated transaction # Upon canceling of the statement line/transaction, # we cancel and delete the vouchers. # Otherwise, the statement line will leave the voucher @@ -610,7 +628,8 @@ class banking_import_transaction(orm.Model): cr, uid, [st_line.voucher_id.id], context=context) voucher_pool.unlink( cr, uid, [st_line.voucher_id.id], context=context) - if transaction.move_line_id and transaction.move_line_id.invoice: + if (transaction.move_line_id + and transaction.move_line_id.invoice): # reopening the invoice netsvc.LocalService('workflow').trg_validate( uid, 'account.invoice', @@ -639,7 +658,9 @@ class banking_import_transaction(orm.Model): _("No method found to cancel this type")) self.cancel_map[transaction.match_type]( self, cr, uid, transaction.id, context) - self._legacy_clear_up_writeoff(cr, uid, transaction, context=context) + self._legacy_clear_up_writeoff( + cr, uid, transaction, context=context + ) return True confirm_map = { @@ -665,7 +686,7 @@ class banking_import_transaction(orm.Model): if transaction.match_type not in ('invoice', 'move', 'manual'): raise orm.except_orm( _("Cannot reconcile"), - _("Bank transaction %s: write off not implemented for " + + _("Bank transaction %s: write off not implemented for " "this match type.") % transaction.statement_line_id.name ) @@ -701,14 +722,14 @@ class banking_import_transaction(orm.Model): # due to float representation and rounding difficulties for trans in self.browse(cr, uid, ids, context=context): if self.pool.get('res.currency').is_zero( - cr, uid, - trans.statement_id.currency, - me['transferred_amount'] - trans.transferred_amount): + cr, uid, + trans.statement_id.currency, + me['transferred_amount'] - trans.transferred_amount): dupes.append(trans.id) if len(dupes) < 1: raise orm.except_orm(_('Cannot check for duplicate'), - _("Cannot check for duplicate. " - "I can't find myself.")) + _("Cannot check for duplicate. " + "I can't find myself.")) if len(dupes) > 1: self.write( cr, uid, res, {'duplicate': True}, context=context) @@ -723,7 +744,7 @@ class banking_import_transaction(orm.Model): pass def _get_move_info(self, cr, uid, move_line_ids, partner_bank_id=False, - partial=False, match_type = False): + partial=False, match_type=False, context=None): type_map = { 'out_invoice': 'customer', 'in_invoice': 'supplier', @@ -738,7 +759,9 @@ class banking_import_transaction(orm.Model): 'match_type': match_type, 'account_id': False, } - move_lines = self.pool.get('account.move.line').browse(cr, uid, move_line_ids) + move_lines = self.pool.get('account.move.line').browse( + cr, uid, move_line_ids, context=context + ) for move_line in move_lines: if move_line.partner_id: if retval['partner_id']: @@ -780,7 +803,7 @@ class banking_import_transaction(orm.Model): if move_lines and len(move_lines) == 1: retval['reference'] = move_lines[0].ref if retval['match_type'] == 'invoice': - retval['invoice_ids'] = list(set([x.invoice.id for x in move_lines])) + retval['invoice_ids'] = list(set(x.invoice.id for x in move_lines)) retval['type'] = type_map[move_lines[0].invoice.type] return retval @@ -790,14 +813,12 @@ class banking_import_transaction(orm.Model): vals['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])] vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])] vals['move_line_id'] = (move_info.get('move_line_ids', False) and - len(move_info['move_line_ids']) == 1 and - move_info['move_line_ids'][0] - ) + len(move_info['move_line_ids']) == 1 and + move_info['move_line_ids'][0]) if move_info['match_type'] == 'invoice': vals['invoice_id'] = (move_info.get('invoice_ids', False) and - len(move_info['invoice_ids']) == 1 and - move_info['invoice_ids'][0] - ) + len(move_info['invoice_ids']) == 1 and + move_info['invoice_ids'][0]) return vals def hook_match_payment(self, cr, uid, transaction, log, context=None): @@ -824,13 +845,13 @@ class banking_import_transaction(orm.Model): # Results if results is None: results = dict( - trans_loaded_cnt = 0, - trans_skipped_cnt = 0, - trans_matched_cnt = 0, - bank_costs_invoice_cnt = 0, - error_cnt = 0, - log = [], - ) + trans_loaded_cnt=0, + trans_skipped_cnt=0, + trans_matched_cnt=0, + bank_costs_invoice_cnt=0, + error_cnt=0, + log=[], + ) # Caching error_accounts = {} @@ -848,8 +869,9 @@ class banking_import_transaction(orm.Model): if has_payment: payment_line_ids = payment_line_obj.search( cr, uid, [ - ('order_id.state', '=', 'sent'), - ('date_done', '=', False)], context=context) + ('order_id.state', '=', 'sent'), + ('date_done', '=', False) + ], context=context) payment_lines = payment_line_obj.browse( cr, uid, payment_line_ids) @@ -885,25 +907,30 @@ class banking_import_transaction(orm.Model): # Get interesting journals once # Added type 'general' to capture fund transfers - journal_ids = journal_obj.search(cr, uid, [ - ('type', 'in', ('general', 'sale','purchase', - 'purchase_refund','sale_refund')), + journal_ids = journal_obj.search( + cr, uid, [ + ('type', 'in', ('general', 'sale', 'purchase', + 'purchase_refund', 'sale_refund')), ('company_id', '=', company.id), - ]) + ], + ) # Get all unreconciled moves - move_line_ids = move_line_obj.search(cr, uid, [ + move_line_ids = move_line_obj.search( + cr, uid, [ ('reconcile_id', '=', False), ('journal_id', 'in', journal_ids), ('account_id.reconcile', '=', True), ('date', '<=', transaction.execution_date), - ]) + ], + ) if move_line_ids: move_lines = move_line_obj.browse(cr, uid, move_line_ids) else: move_lines = [] # Create fallback currency code - currency_code = transaction.local_currency or company.currency_id.name + currency_code = (transaction.local_currency + or company.currency_id.name) # Check cache for account info/currency if transaction.local_account in info and \ @@ -917,7 +944,8 @@ class banking_import_transaction(orm.Model): ) if not account_info: results['log'].append( - _('Transaction found for unknown account %(bank_account)s') % + _('Transaction found for unknown account ' + '%(bank_account)s') % {'bank_account': transaction.local_account} ) error_accounts[transaction.local_account] = True @@ -929,7 +957,7 @@ class banking_import_transaction(orm.Model): results['log'].append( _('Transaction found for account %(bank_account)s, ' 'but no default journal was defined.' - ) % {'bank_account': transaction.local_account} + ) % {'bank_account': transaction.local_account} ) error_accounts[transaction.local_account] = True results['error_cnt'] += 1 @@ -941,12 +969,14 @@ class banking_import_transaction(orm.Model): currency_code = account_info.currency_id.name # Cache results - if not transaction.local_account in info: + if transaction.local_account not in info: info[transaction.local_account] = { currency_code: account_info } else: - info[transaction.local_account][currency_code] = account_info + info[transaction.local_account][currency_code] = ( + account_info + ) # Link accounting period period_id = banktools.get_period( @@ -965,7 +995,8 @@ class banking_import_transaction(orm.Model): _("Cannot perform match on a confirmed transction")) else: values = { - 'name': '%s.%s' % (transaction.statement, transaction.transaction), + 'name': '%s.%s' % (transaction.statement, + transaction.transaction), 'date': transaction.execution_date, 'amount': transaction.transferred_amount, 'statement_id': transaction.statement_id.id, @@ -979,7 +1010,9 @@ class banking_import_transaction(orm.Model): account_info.default_credit_account_id.id or account_info.default_debit_account_id.id), } - statement_line_id = statement_line_obj.create(cr, uid, values, context) + statement_line_id = statement_line_obj.create( + cr, uid, values, context + ) results['trans_loaded_cnt'] += 1 transaction.write({'statement_line_id': statement_line_id}) transaction.refresh() @@ -991,13 +1024,14 @@ class banking_import_transaction(orm.Model): and account_info.currency_id.name != transaction.local_currency: # TODO: convert currencies? results['log'].append( - _('transaction %(statement_id)s.%(transaction_id)s for account %(bank_account)s' - ' uses different currency than the defined bank journal.' - ) % { - 'bank_account': transactions.local_account, - 'statement_id': transaction.statement, - 'transaction_id': transaction.transaction, - } + _('transaction %(statement_id)s.%(transaction_id)s for ' + 'account %(bank_account)s uses different currency than ' + 'the defined bank journal.' + ) % { + 'bank_account': transactions.local_account, + 'statement_id': transaction.statement, + 'transaction_id': transaction.transaction, + } ) error_accounts[transaction.local_account] = True results['error_cnt'] += 1 @@ -1006,17 +1040,18 @@ class banking_import_transaction(orm.Model): continue # When bank costs are part of transaction itself, split it. - if transaction.type != bt.BANK_COSTS and transaction.provision_costs: + if (transaction.type != bt.BANK_COSTS + and transaction.provision_costs): # Create new transaction for bank costs cost_id = self.copy( cr, uid, transaction.id, dict( - type = bt.BANK_COSTS, - transaction = '%s-prov' % transaction.transaction, - transferred_amount = transaction.provision_costs, - remote_currency = transaction.provision_costs_currency, - message = transaction.provision_costs_description, - parent_id = transaction.id, + type=bt.BANK_COSTS, + transaction='%s-prov' % transaction.transaction, + transferred_amount=transaction.provision_costs, + remote_currency=transaction.provision_costs_currency, + message=transaction.provision_costs_description, + parent_id=transaction.id, ), context) injected.append(self.browse(cr, uid, cost_id, context)) @@ -1028,14 +1063,17 @@ class banking_import_transaction(orm.Model): self.write( cr, uid, transaction.id, dict( - transferred_amount = - transaction.transferred_amount - transaction.provision_costs, - provision_costs = False, - provision_costs_currency = False, - provision_costs_description = False, + transferred_amount=( + transaction.transferred_amount - + transaction.provision_costs), + provision_costs=False, + provision_costs_currency=False, + provision_costs_description=False, ), context=context) # rebrowse the current record after writing - transaction = self.browse(cr, uid, transaction.id, context=context) + transaction = self.browse( + cr, uid, transaction.id, context=context + ) # Match payment and direct debit orders move_info_payment = self.hook_match_payment( @@ -1088,7 +1126,8 @@ class banking_import_transaction(orm.Model): # Credit means payment... isn't it? if (not move_info - and transaction.statement_line_id.amount < 0 and payment_lines): + and transaction.statement_line_id.amount < 0 + and payment_lines): # Link open payment - if any # Note that _match_payment is defined in the # account_banking_payment module which should be installed @@ -1146,10 +1185,13 @@ class banking_import_transaction(orm.Model): values['type'] = move_info['type'] else: values['partner_id'] = values['partner_bank_id'] = False - if not values['partner_id'] and partner_ids and len(partner_ids) == 1: + if (not values['partner_id'] + and partner_ids + and len(partner_ids) == 1): values['partner_id'] = partner_ids[0] - if (not values['partner_bank_id'] and partner_banks and - len(partner_banks) == 1): + if (not values['partner_bank_id'] + and partner_banks + and len(partner_banks) == 1): values['partner_bank_id'] = partner_banks[0].id statement_line_obj.write( @@ -1158,7 +1200,7 @@ class banking_import_transaction(orm.Model): if not injected: i += 1 - #recompute statement end_balance for validation + # recompute statement end_balance for validation if imported_statement_ids: statement_obj.button_dummy( cr, uid, imported_statement_ids, context=context) @@ -1185,7 +1227,7 @@ class banking_import_transaction(orm.Model): res = dict([(x, False) for x in ids]) for transaction in self.browse(cr, uid, ids, context): if (transaction.statement_line_id.state == 'draft' and - not(transaction.move_currency_amount is False)): + not(transaction.move_currency_amount is False)): res[transaction.id] = ( transaction.move_currency_amount - transaction.statement_line_id.amount @@ -1214,22 +1256,32 @@ class banking_import_transaction(orm.Model): Write values in argument 'vals', but clear all match related values first """ - write_vals = (dict([(x, False) for x in [ + write_vals = ( + dict([ + (x, False) + for x in [ 'match_type', 'move_line_id', 'invoice_id', - ]] + - [(x, [(6, 0, [])]) for x in [ - 'move_line_ids', - 'invoice_ids', - ]])) + ] + ] + [ + (x, [(6, 0, [])]) + for x in [ + 'move_line_ids', + 'invoice_ids', + ] + ] + ) + ) write_vals.update(vals or {}) return self.write(cr, uid, ids, write_vals, context=context) def _get_move_amount(self, cr, uid, ids, name, args, context=None): """ - Need to get the residual amount on the move (invoice) in the bank statement currency. - This will be used to calculate the write-off amount (in statement currency). + Need to get the residual amount on the move (invoice) in the bank + statement currency. + This will be used to calculate the write-off amount + (in statement currency). """ if not ids: return {} @@ -1240,20 +1292,25 @@ class banking_import_transaction(orm.Model): for transaction in self.browse(cr, uid, ids, context): if transaction.move_line_id: - move_line_amount = transaction.move_line_id.amount_residual_currency + move_line_amount = ( + transaction.move_line_id.amount_residual_currency) + statement = transaction.statement_line_id.statement_id to_curr_id = ( - transaction.statement_line_id.statement_id.journal_id.currency - and transaction.statement_line_id.statement_id.journal_id.currency.id - or transaction.statement_line_id.statement_id.company_id.currency_id.id + statement.journal_id.currency + and statement.journal_id.currency.id + or statement.company_id.currency_id.id ) from_curr_id = ( transaction.move_line_id.currency_id and transaction.move_line_id.currency_id.id - or transaction.statement_line_id.statement_id.company_id.currency_id.id + or statement.company_id.currency_id.id ) if from_curr_id != to_curr_id: - amount_currency = stline_pool._convert_currency(cr, uid, from_curr_id, to_curr_id, move_line_amount, round=True, - date=transaction.statement_line_id.date, context=context) + amount_currency = stline_pool._convert_currency( + cr, uid, from_curr_id, to_curr_id, move_line_amount, + round=True, date=transaction.statement_line_id.date, + context=context + ) else: amount_currency = move_line_amount sign = 1 @@ -1261,7 +1318,8 @@ class banking_import_transaction(orm.Model): if transaction.move_line_id.amount_currency < 0: sign = -1 else: - if (transaction.move_line_id.debit - transaction.move_line_id.credit) < 0: + if (transaction.move_line_id.debit + - transaction.move_line_id.credit) < 0: sign = -1 res[transaction.id] = sign * amount_currency @@ -1274,13 +1332,15 @@ class banking_import_transaction(orm.Model): for this in self.browse(cr, uid, ids, context): if this.parent_id: this.parent_id.write( - {'transferred_amount': - this.parent_id.transferred_amount + \ - this.transferred_amount, - }) + { + 'transferred_amount': + this.parent_id.transferred_amount + + this.transferred_amount, + } + ) this.parent_id.refresh() return super(banking_import_transaction, self).unlink( - cr, uid, ids, context=context) + cr, uid, ids, context=context) column_map = { # used in bank_import.py, converting non-osv transactions @@ -1291,8 +1351,8 @@ class banking_import_transaction(orm.Model): _columns = { # start mem_bank_transaction atributes # see parsers/models.py - 'transaction': fields.char('transaction', size=16), # id - 'statement': fields.char('statement', size=16), # statement_id + 'transaction': fields.char('transaction', size=16), # id + 'statement': fields.char('statement', size=16), # statement_id 'type': fields.char('type', size=16), 'reference': fields.char('reference', size=1024), 'local_account': fields.char('local_account', size=24), @@ -1307,8 +1367,14 @@ class banking_import_transaction(orm.Model): 'remote_owner': fields.char('remote_owner', size=128), 'remote_owner_address': fields.char('remote_owner_address', size=256), 'remote_owner_city': fields.char('remote_owner_city', size=128), - 'remote_owner_postalcode': fields.char('remote_owner_postalcode', size=24), - 'remote_owner_country_code': fields.char('remote_owner_country_code', size=24), + 'remote_owner_postalcode': fields.char( + 'remote_owner_postalcode', + size=24, + ), + 'remote_owner_country_code': fields.char( + 'remote_owner_country_code', + size=24, + ), 'remote_owner_custno': fields.char('remote_owner_custno', size=24), 'remote_bank_bic': fields.char('remote_bank_bic', size=24), 'remote_bank_bei': fields.char('remote_bank_bei', size=24), @@ -1318,8 +1384,14 @@ class banking_import_transaction(orm.Model): 'remote_bank_duns': fields.char('remote_bank_duns', size=24), 'remote_bank_tax_id': fields.char('remote_bank_tax_id', size=24), 'provision_costs': fields.float('provision_costs', size=24), - 'provision_costs_currency': fields.char('provision_costs_currency', size=64), - 'provision_costs_description': fields.char('provision_costs_description', size=24), + 'provision_costs_currency': fields.char( + 'provision_costs_currency', + size=64, + ), + 'provision_costs_description': fields.char( + 'provision_costs_description', + size=24, + ), 'error_message': fields.char('error_message', size=1024), 'storno_retry': fields.boolean('storno_retry'), # end of mem_bank_transaction_fields @@ -1341,15 +1413,15 @@ class banking_import_transaction(orm.Model): 'banking.import.transaction', 'Split off from this transaction'), # match fields 'match_type': fields.selection([ - ('move','Move'), - ('invoice', 'Invoice'), - ('payment', 'Payment line'), - ('payment_order', 'Payment order'), - ('storno', 'Storno'), - ('manual', 'Manual'), - ('payment_manual', 'Payment line (manual)'), - ('payment_order_manual', 'Payment order (manual)'), - ], 'Match type'), + ('move', 'Move'), + ('invoice', 'Invoice'), + ('payment', 'Payment line'), + ('payment_order', 'Payment order'), + ('storno', 'Storno'), + ('manual', 'Manual'), + ('payment_manual', 'Payment line (manual)'), + ('payment_order_manual', 'Payment order (manual)'), + ], 'Match type'), 'match_multi': fields.function( _get_match_multi, method=True, string='Multi match', type='boolean'), @@ -1366,13 +1438,16 @@ class banking_import_transaction(orm.Model): 'residual': fields.function( _get_residual, method=True, string='Residual', type='float'), 'writeoff_account_id': fields.many2one( - 'account.account', 'Write-off account', - domain=[('type', '!=', 'view')]), - 'payment_option':fields.selection( + 'account.account', + 'Write-off account', + domain=[('type', '!=', 'view')] + ), + 'payment_option': fields.selection( [ ('without_writeoff', 'Keep Open'), ('with_writeoff', 'Reconcile Payment Balance') - ], 'Payment Difference', + ], + 'Payment Difference', required=True, help=("This field helps you to choose what you want to do with " "the eventual difference between the paid amount and the " @@ -1387,18 +1462,20 @@ class banking_import_transaction(orm.Model): 'writeoff_analytic_id': fields.many2one( 'account.analytic.account', 'Write off analytic account'), 'move_currency_amount': fields.function( - _get_move_amount, method=True, string='Match Amount', type='float'), - } + _get_move_amount, + method=True, + string='Match Amount', + type='float', + ), + } _defaults = { - 'company_id': lambda s,cr,uid,c: + 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( - cr, uid, 'bank.import.transaction', context=c), + cr, uid, 'bank.import.transaction', context=c), 'payment_option': 'without_writeoff', } -banking_import_transaction() - class account_bank_statement_line(orm.Model): _inherit = 'account.bank.statement.line' @@ -1436,7 +1513,7 @@ class account_bank_statement_line(orm.Model): 'match_type': fields.related( 'import_transaction_id', 'match_type', type='selection', selection=[ - ('move','Move'), + ('move', 'Move'), ('invoice', 'Invoice'), ('payment', 'Payment line'), ('payment_order', 'Payment order'), @@ -1444,13 +1521,15 @@ class account_bank_statement_line(orm.Model): ('manual', 'Manual'), ('payment_manual', 'Payment line (manual)'), ('payment_order_manual', 'Payment order (manual)'), - ], + ], string='Match type', readonly=True,), 'state': fields.selection( [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', readonly=True, required=True), - 'parent_id': fields.many2one('account.bank.statement.line', - 'Parent'), + 'parent_id': fields.many2one( + 'account.bank.statement.line', + 'Parent', + ), 'link_partner_ok': fields.function( _get_link_partner_ok, type='boolean', string='Can link partner'), @@ -1471,7 +1550,9 @@ class account_bank_statement_line(orm.Model): wizard_obj = self.pool.get('banking.transaction.wizard') res_id = wizard_obj.create( cr, uid, {'statement_line_id': ids[0]}, context=context) - res = wizard_obj.create_act_window(cr, uid, res_id, context=context) + res = wizard_obj.create_act_window( + cr, uid, res_id, context=context + ) return res def link_partner(self, cr, uid, ids, context=None): @@ -1499,8 +1580,8 @@ class account_bank_statement_line(orm.Model): {'partner_id': statement_line.partner_bank_id.partner_id.id}) return True - if (not statement_line.import_transaction_id or - not statement_line.import_transaction_id.remote_account): + if (not statement_line.import_transaction_id + or not statement_line.import_transaction_id.remote_account): raise orm.except_orm( _("Error"), _("No bank account available to link partner to")) @@ -1535,8 +1616,8 @@ class account_bank_statement_line(orm.Model): return wizard_obj.create_act_window(cr, uid, res_id, context=context) def _convert_currency( - self, cr, uid, from_curr_id, to_curr_id, from_amount, - round=False, date=None, context=None): + self, cr, uid, from_curr_id, to_curr_id, from_amount, + round=False, date=None, context=None): """Convert currency amount using the company rate on a specific date""" curr_obj = self.pool.get('res.currency') if context: @@ -1555,8 +1636,9 @@ class account_bank_statement_line(orm.Model): """ Create (or update) a voucher for each statement line, and then generate the moves by posting the voucher. - If a line does not have a move line against it, but has an account, then - generate a journal entry that moves the line amount to the specified account. + If a line does not have a move line against it, but has an account, + then generate a journal entry that moves the line amount to the + specified account. """ statement_pool = self.pool.get('account.bank.statement') obj_seq = self.pool.get('ir.sequence') @@ -1576,7 +1658,8 @@ class account_bank_statement_line(orm.Model): raise orm.except_orm( _('No Analytic Journal !'), _("You have to define an analytic journal on the '%s' " - "journal!") % (st_line.statement_id.journal_id.name,)) + "journal!") % st_line.statement_id.journal_id.name + ) if not st_line.amount: continue if not st_line.period_id: @@ -1594,10 +1677,16 @@ class account_bank_statement_line(orm.Model): if st.journal_id.sequence_id: period = st.period_id or st_line.period_id c = {'fiscalyear_id': period.fiscalyear_id.id} - st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c) + st_number = obj_seq.next_by_id( + cr, uid, st.journal_id.sequence_id.id, context=c + ) else: - st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement') - statement_pool.write(cr, uid, [st.id], {'name': st_number}, context=context) + st_number = obj_seq.next_by_code( + cr, uid, 'account.bank.statement' + ) + statement_pool.write( + cr, uid, [st.id], {'name': st_number}, context=context + ) if st_line.import_transaction_id: import_transaction_obj.confirm( @@ -1607,7 +1696,9 @@ class account_bank_statement_line(orm.Model): cr, uid, st_number, st_line, context) company_currency_id = st.journal_id.company_id.currency_id.id statement_pool.create_move_from_st_line( - cr, uid, st_line.id, company_currency_id, st_line_number, context) + cr, uid, st_line.id, company_currency_id, st_line_number, + context + ) self.write( cr, uid, st_line.id, {'state': 'confirmed'}, context) return True @@ -1626,15 +1717,17 @@ class account_bank_statement_line(orm.Model): if st_line.statement_id.state != 'draft': raise orm.except_orm( _("Cannot cancel bank transaction"), - _("The bank statement that this transaction belongs to has " - "already been confirmed")) + _("The bank statement that this transaction belongs to " + "has already been confirmed")) if st_line.import_transaction_id: # Cancel transaction immediately. # If it has voucher, this will clean up # the moves on the st_line. import_transaction_obj.cancel( - cr, uid, [st_line.import_transaction_id.id], context=context) + cr, uid, [st_line.import_transaction_id.id], + context=context + ) st_line.refresh() for line in st_line.move_ids: # We allow for people canceling and removing @@ -1650,7 +1743,6 @@ class account_bank_statement_line(orm.Model): cr, uid, set_draft_ids, {'state': 'draft'}, context=context) return True - def unlink(self, cr, uid, ids, context=None): """ Don't allow deletion of a confirmed statement line @@ -1667,15 +1759,15 @@ class account_bank_statement_line(orm.Model): ": '%s'") % line.name) if line.parent_id: line.parent_id.write( - { - 'amount': line.parent_id.amount + line.amount, - }) + { + 'amount': line.parent_id.amount + line.amount, + } + ) line.parent_id.refresh() return super(account_bank_statement_line, self).unlink( cr, uid, ids, context=context) - def create_instant_transaction( - self, cr, uid, ids, context=None): + def create_instant_transaction(self, cr, uid, ids, context=None): """ Check for existance of import transaction on the bank statement lines. Create instant items if appropriate. @@ -1696,8 +1788,7 @@ class account_bank_statement_line(orm.Model): context = {} localcontext = context.copy() localcontext['transaction_no_duplicate_search'] = True - for line in self.browse( - cr, uid, ids, context=context): + for line in self.browse(cr, uid, ids, context=context): if line.state != 'confirmed' and not line.import_transaction_id: res = import_transaction_pool.create( cr, uid, { @@ -1723,23 +1814,23 @@ class account_bank_statement_line(orm.Model): child_statement_ids = [] for this in self.browse(cr, uid, ids, context): transaction_data = transaction_pool.copy_data( - cr, uid, this.import_transaction_id.id) + cr, uid, this.import_transaction_id.id + ) transaction_data['transferred_amount'] = amount - transaction_data['message'] = ( - (transaction_data['message'] or '') + _(' (split)')) + transaction_data['message'] = ((transaction_data['message'] or '') + + _(' (split)')) transaction_data['parent_id'] = this.import_transaction_id.id transaction_id = transaction_pool.create( - cr, - uid, - transaction_data, - context=dict( - context, transaction_no_duplicate_search=True)) + cr, + uid, + transaction_data, + context=dict(context, transaction_no_duplicate_search=True) + ) - statement_line_data = self.copy_data( - cr, uid, this.id) + statement_line_data = self.copy_data(cr, uid, this.id) statement_line_data['amount'] = amount statement_line_data['name'] = ( - (statement_line_data['name'] or '') + _(' (split)')) + (statement_line_data['name'] or '') + _(' (split)')) statement_line_data['import_transaction_id'] = transaction_id statement_line_data['parent_id'] = this.id statement_line_id = self.create( @@ -1785,35 +1876,43 @@ class account_bank_statement(orm.Model): line_obj = self.pool.get('account.bank.statement.line') for st in self.browse(cr, uid, ids, context=context): j_type = st.journal_id.type - if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): + if not self.check_status_condition( + cr, uid, st.state, journal_type=j_type): continue - self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) + self.balance_check(cr, uid, st.id, journal_type=j_type, + context=context) if (not st.journal_id.default_credit_account_id) \ or (not st.journal_id.default_debit_account_id): - raise orm.except_orm(_('Configuration Error !'), - _('Please verify that an account is defined in the journal.')) + raise orm.except_orm( + _('Configuration Error !'), + _('Please verify that an account is defined in the ' + 'journal.') + ) # protect against misguided manual changes for line in st.move_line_ids: if line.state != 'valid': - raise orm.except_orm(_('Error !'), - _('The account entries lines are not in valid state.')) + raise orm.except_orm( + _('Error !'), + _('The account entries lines are not in valid state.') + ) - line_obj.confirm(cr, uid, [line.id for line in st.line_ids], context) + line_obj.confirm(cr, uid, [line.id for line in st.line_ids], + context) st.refresh() self.message_post( cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st.name,), context=context) - return self.write(cr, uid, ids, {'state':'confirm'}, context=context) + return self.write(cr, uid, ids, {'state': 'confirm'}, context=context) def button_cancel(self, cr, uid, ids, context=None): """ Do nothing but write the state. Delegate all actions to the statement line workflow instead. """ - self.write(cr, uid, ids, {'state':'draft'}, context=context) + self.write(cr, uid, ids, {'state': 'draft'}, context=context) def unlink(self, cr, uid, ids, context=None): """ @@ -1841,5 +1940,3 @@ class account_bank_statement(orm.Model): 'balance_end': fields.function( _end_balance, method=True, store=True, string='Balance'), } - -account_bank_statement() diff --git a/account_banking/migrations/6.1.0.1.81/post-set-statement-line-state.py b/account_banking/migrations/6.1.0.1.81/post-set-statement-line-state.py index 59d65aa34..d471cdb16 100644 --- a/account_banking/migrations/6.1.0.1.81/post-set-statement-line-state.py +++ b/account_banking/migrations/6.1.0.1.81/post-set-statement-line-state.py @@ -4,8 +4,8 @@ # Copyright (C) 2011 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 +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,10 +24,11 @@ __name__ = ("account.bank.statement.line:: set new field 'state' to " "confirmed for all statement lines belonging to confirmed " "statements") + def migrate(cr, version): - cr.execute ("UPDATE account_bank_statement_line as sl " - " SET state = 'confirmed'" - " FROM account_bank_statement as s " - " WHERE sl.statement_id = s.id " - " AND s.state = 'confirm' " - ) + cr.execute("UPDATE account_bank_statement_line as sl " + " SET state = 'confirmed'" + " FROM account_bank_statement as s " + " WHERE sl.statement_id = s.id " + " AND s.state = 'confirm' " + ) diff --git a/account_banking/migrations/7.0.0.1/pre-migration.py b/account_banking/migrations/7.0.0.1/pre-migration.py index e12284d0e..ef5656c66 100644 --- a/account_banking/migrations/7.0.0.1/pre-migration.py +++ b/account_banking/migrations/7.0.0.1/pre-migration.py @@ -19,6 +19,7 @@ # ############################################################################## + def migrate(cr, version): if not version: return @@ -26,7 +27,7 @@ def migrate(cr, version): # workflow state moved to another, new module cr.execute( """ - UPDATE ir_model_data + UPDATE ir_model_data SET module = 'account_banking_payment' WHERE name = 'trans_done_sent' AND module = 'account_direct_debit' diff --git a/account_banking/migrations/7.0.0.3/pre-migration.py b/account_banking/migrations/7.0.0.3/pre-migration.py index 0a1c80c6c..dab121c5d 100644 --- a/account_banking/migrations/7.0.0.3/pre-migration.py +++ b/account_banking/migrations/7.0.0.3/pre-migration.py @@ -19,6 +19,7 @@ # ############################################################################## + def migrate(cr, version): if not version: return diff --git a/account_banking/migrations/7.0.0.4/pre-migration.py b/account_banking/migrations/7.0.0.4/pre-migration.py index dfec20809..2abe042a6 100644 --- a/account_banking/migrations/7.0.0.4/pre-migration.py +++ b/account_banking/migrations/7.0.0.4/pre-migration.py @@ -19,6 +19,7 @@ # ############################################################################## + def table_exists(cr, table): """ Check whether a certain table or view exists """ cr.execute( @@ -26,6 +27,7 @@ def table_exists(cr, table): (table,)) return cr.fetchone()[0] == 1 + def migrate(cr, version): """ Migration script for semantic changes in account_banking_payment_export. diff --git a/account_banking/parsers/__init__.py b/account_banking/parsers/__init__.py index f79dea6c4..63d7ead96 100644 --- a/account_banking/parsers/__init__.py +++ b/account_banking/parsers/__init__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -19,6 +19,6 @@ # ############################################################################## -import models +from . import models # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/parsers/convert.py b/account_banking/parsers/convert.py index 8287f4144..2578a0582 100644 --- a/account_banking/parsers/convert.py +++ b/account_banking/parsers/convert.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -29,14 +29,17 @@ try: except AttributeError: from mx import DateTime as datetime + def str2date(datestr, format='%d/%m/%y'): '''Convert a string to a datatime object''' return datetime.strptime(datestr, format) + def date2str(date, format='%Y-%m-%d'): '''Convert a datetime object to a string''' return date.strftime(format) + def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'): ''' Convert a date in a string to another string, in a different @@ -44,7 +47,9 @@ def date2date(datestr, fromfmt='%d/%m/%y', tofmt='%Y-%m-%d'): ''' return date2str(str2date(datestr, fromfmt), tofmt) -_SWIFT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-?:().,'+ " +_SWIFT = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "/-?:().,'+ ") + def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']): ''' @@ -62,7 +67,7 @@ def to_swift(astr, schemes=['utf-8', 'latin-1', 'ascii']): s = [x in _SWIFT and x or ' ' for x in unicodedata.normalize('NFKD', astr).encode('ascii', 'ignore') - ] + ] return ''.join(s) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/parsers/models.py b/account_banking/parsers/models.py index 4e88ea66e..fbd72291f 100644 --- a/account_banking/parsers/models.py +++ b/account_banking/parsers/models.py @@ -22,6 +22,7 @@ import re from openerp.tools.translate import _ + class mem_bank_statement(object): ''' A mem_bank_statement is a real life projection of a bank statement paper @@ -34,9 +35,15 @@ class mem_bank_statement(object): ''' # Lock attributes to enable parsers to trigger non-conformity faults __slots__ = [ - 'start_balance','end_balance', 'date', 'local_account', - 'local_currency', 'id', 'transactions' + 'start_balance', + 'end_balance', + 'date', + 'local_account', + 'local_currency', + 'id', + 'transactions' ] + def __init__(self, *args, **kwargs): super(mem_bank_statement, self).__init__(*args, **kwargs) self.id = '' @@ -59,6 +66,7 @@ class mem_bank_statement(object): check += float(transaction.transferred_amount) return abs(check - float(self.end_balance)) < 0.0001 + class mem_bank_transaction(object): ''' A mem_bank_transaction is a real life copy of a bank transfer. Mapping to @@ -102,7 +110,7 @@ class mem_bank_transaction(object): # remote_currency 'transferred_amount', - # The actual amount transferred - + # The actual amount transferred - # negative means sent, positive means received # Most banks use the local_currency to express this amount, but there # may be exceptions I'm unaware of. @@ -126,7 +134,8 @@ class mem_bank_transaction(object): # The other parties postal code belonging to the address 'remote_owner_country_code', - # The other parties two letter ISO country code belonging to the previous + # The other parties two letter ISO country code belonging to the + # previous 'remote_owner_custno', # The other parties customer number @@ -175,7 +184,7 @@ class mem_bank_transaction(object): # An error message for interaction with the user # Only used when mem_transaction.valid returns False. 'error_message', - + # Storno attribute. When True, make the cancelled debit eligible for # a next direct debit run 'storno_retry', @@ -213,7 +222,7 @@ class mem_bank_transaction(object): # Will be selected for matching. # STORNO A failed or reversed attempt at direct debit. # Either due to an action on the payer's side - # or a failure observed by the bank (lack of + # or a failure observed by the bank (lack of # credit for instance) # # Perhaps more will follow. @@ -230,7 +239,7 @@ class mem_bank_transaction(object): DIRECT_DEBIT = 'DD' ORDER = 'DO' PAYMENT_BATCH = 'PB' - PAYMENT_TERMINAL = 'PT' + PAYMENT_TERMINAL = 'PT' PERIODIC_ORDER = 'PO' STORNO = 'ST' @@ -270,7 +279,7 @@ class mem_bank_transaction(object): if value in self.types: self.transfer_type = value else: - raise ValueError, _('Invalid value for transfer_type') + raise ValueError(_('Invalid value for transfer_type')) type = property(_get_type, _set_type) @@ -282,6 +291,7 @@ class mem_bank_transaction(object): return (self.execution_date and self.remote_account and self.transferred_amount and True) or False + class parser_type(type): ''' Meta annex factory class for house keeping and collecting parsers. @@ -314,11 +324,13 @@ class parser_type(type): keys.sort() return [(parsers[x].code, parsers[x].name) for x in keys] + def create_parser(code): if code in parser_type.parser_by_code: return parser_type.parser_by_code[code]() return None + class parser(object): ''' A parser delivers the interface for any parser object. Inherit from @@ -384,7 +396,7 @@ class parser(object): def parse(self, cr, data): ''' Parse data. - + data is a raw in memory file object. You have to split it in whatever chunks you see fit for parsing. It should return a list of mem_bank_statement objects. Every mem_bank_statement object @@ -400,7 +412,7 @@ class parser(object): be used as a prefix. Adding a tracer (day resolution) can create uniqueness. Adding unique statement ids can add to the robustness of your transaction numbering. - + Just mind that users can create random (file)containers with transactions in it. Try not to depend on order of appearance within these files. If in doubt: sort. @@ -408,5 +420,3 @@ class parser(object): raise NotImplementedError( _('This is a stub. Please implement your own.') ) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/record.py b/account_banking/record.py index 18486c020..54768e34b 100644 --- a/account_banking/record.py +++ b/account_banking/record.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -31,16 +31,19 @@ from datetime import datetime, date # Correct python2.4 issues try: datetime.strptime + def strpdate(str, format): return datetime.strptime(str, format).date() except AttributeError: import time + def strpdate(str, format): tm = time.strptime(str, format) return date(tm.tm_year, tm.tm_mon, tm.tm_mday) import unicodedata + class Field(object): '''Base Field class - fixed length left aligned string field in a record''' def __init__(self, name, length=1, fillchar=' ', cast=str): @@ -57,11 +60,14 @@ class Field(object): def take(self, buffer): offset = hasattr(self, 'offset') and self.offset or 0 - return self.cast(buffer[offset:offset + self.length].rstrip(self.fillchar)) + return self.cast(buffer[offset:offset + self.length].rstrip( + self.fillchar) + ) def __repr__(self): return '%s "%s"' % (self.__class__.__name__, self.name) + class Filler(Field): '''Constant value field''' def __init__(self, name, length=1, value=' '): @@ -73,9 +79,10 @@ class Filler(Field): def format(self, value): return super(Filler, self).format( - self.value * (self.length / len(self.value) +1) + self.value * (self.length / len(self.value) + 1) ) + class DateField(Field): '''Variable date field''' def __init__(self, name, format='%Y-%m-%d', auto=False, cast=str): @@ -98,6 +105,7 @@ class DateField(Field): return strpdate(value, self.dateformat) return self.auto and date.today() or None + class RightAlignedField(Field): '''Deviation of Field: right aligned''' def format(self, value): @@ -107,7 +115,10 @@ class RightAlignedField(Field): def take(self, buffer): offset = hasattr(self, 'offset') and self.offset or 0 - return self.cast(buffer[offset:offset + self.length].lstrip(self.fillchar)) + return self.cast(buffer[offset:offset + self.length].lstrip( + self.fillchar) + ) + class NumberField(RightAlignedField): '''Deviation of Field: left zero filled''' @@ -118,6 +129,7 @@ class NumberField(RightAlignedField): def format(self, value): return super(NumberField, self).format(self.cast(value or '')) + class RecordType(object): fields = [] @@ -130,7 +142,7 @@ class RecordType(object): offset += field.length def __len__(self): - return reduce(lambda x,y: x+y.length, self.fields, 0) + return reduce(lambda x, y: x + y.length, self.fields, 0) def __contains__(self, key): return any(lambda x, y=key: x.name == y, self.fields) @@ -139,7 +151,7 @@ class RecordType(object): for field in self.fields: if field.name == key: return field - raise KeyError, 'No such field: %s' % key + raise KeyError('No such field: %s' % key) def format(self, buffer): result = [] @@ -150,7 +162,8 @@ class RecordType(object): def take(self, buffer): return dict(zip([x.name for x in self.fields], [x.take(buffer) for x in self.fields] - )) + )) + class Record(object): _recordtype = None @@ -159,12 +172,12 @@ class Record(object): if hasattr(self, '_fields') and self._fields: self._recordtype = RecordType(self._fields) if not self._recordtype and not recordtype: - raise ValueError, 'No recordtype specified' + raise ValueError('No recordtype specified') if not self._recordtype: self._recordtype = recordtype() self._length = len(self._recordtype) self._value = value.ljust(self._length)[:self._length] - + def __len__(self): return self._length @@ -173,23 +186,24 @@ class Record(object): super(Record, self).__setattr__(attr, value) else: field = self._recordtype[attr] - self._value = self._value[:field.offset] + \ - field.format(value) + \ - self._value[field.offset + field.length:] + self._value = ( + self._value[:field.offset] + + field.format(value) + + self._value[field.offset + field.length:] + ) def __getattr__(self, attr): if attr.startswith('_'): 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') - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/res_bank.py b/account_banking/res_bank.py index a73033242..0e858c31c 100644 --- a/account_banking/res_bank.py +++ b/account_banking/res_bank.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright 2011 - 2014 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 @@ -25,7 +25,7 @@ class ResBank(orm.Model): def online_bank_info(self, cr, uid, bic, context=None): """ - API hook for legacy online lookup of BICs, + API hook for legacy online lookup of BICs, to be removed in OpenERP 8.0. """ return False, False diff --git a/account_banking/res_partner.py b/account_banking/res_partner.py index 4166b89d5..1e2970412 100644 --- a/account_banking/res_partner.py +++ b/account_banking/res_partner.py @@ -30,7 +30,7 @@ class ResPartner(orm.Model): 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. """ diff --git a/account_banking/sepa/iban.py b/account_banking/sepa/iban.py index ece173404..58b1ddeb9 100644 --- a/account_banking/sepa/iban.py +++ b/account_banking/sepa/iban.py @@ -44,6 +44,7 @@ __all__ = ['IBAN', 'BBAN'] + def modulo_97_base10(abuffer): ''' Calculate the modulo 97 value of a string in base10 @@ -55,6 +56,7 @@ def modulo_97_base10(abuffer): checksum %= 97 return checksum + def base36_to_base10str(abuffer): ''' Convert a base36 string value to a string of base10 digits. @@ -67,6 +69,7 @@ def base36_to_base10str(abuffer): result += digit return result + class BBANFormat(object): ''' A BBANFormat is an auxilliary class for IBAN. It represents the composition @@ -80,7 +83,7 @@ class BBANFormat(object): 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 @@ -95,7 +98,7 @@ class BBANFormat(object): leading-zero-stripped account numbers. Example: (NL) 'CCCCAAAAAAAAAA' - will convert 'INGB0001234567' into + will convert 'INGB0001234567' into bankcode 'INGB' and account '0001234567' bbanfmt: string of placeholders for the local bank account @@ -119,7 +122,7 @@ class BBANFormat(object): 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) @@ -147,7 +150,7 @@ class BBANFormat(object): else: prefix = '' return prefix + self.__extract__('A', iban) - + def BBAN(self, iban): ''' Format the BBAN part of the IBAN in iban following the local @@ -178,6 +181,7 @@ class BBANFormat(object): i += 1 return res + class IBAN(str): ''' A IBAN string represents a SEPA bank account number. This class provides @@ -272,7 +276,7 @@ class IBAN(str): if item.isalnum(): init += item elif item not in ' \t.-': - raise ValueError, 'Invalid chars found in IBAN number' + raise ValueError('Invalid chars found in IBAN number') return str.__new__(cls, init) def __init__(self, *args, **kwargs): @@ -287,8 +291,7 @@ class IBAN(str): @classmethod def create(cls, BIC=None, countrycode=None, BBAN=None, bankcode=None, - branchcode=None, account=None - ): + branchcode=None, account=None): ''' Create a IBAN number from a BBAN and a country code. Optionaly create a BBAN from BBAN components before generation. @@ -304,20 +307,17 @@ class IBAN(str): if countrycode: countrycode = countrycode.upper() else: - raise ValueError, \ - 'Either BIC or countrycode is required' + raise ValueError('Either BIC or countrycode is required') if countrycode not in cls.countries: - raise ValueError, \ - '%s is not a SEPA country' % countrycode + raise ValueError('%s is not a SEPA country' % countrycode) format = cls.BBAN_formats[countrycode] if BBAN: if len(BBAN) == len(format._iban): ibanno = cls(countrycode + '00' + BBAN) return cls(countrycode + ibanno.checksum + BBAN) - raise ValueError, \ - 'Insufficient data to generate IBAN' + raise ValueError('Insufficient data to generate IBAN') @property def valid(self): @@ -325,8 +325,10 @@ class IBAN(str): Check if the string + check digits deliver a valid checksum ''' _buffer = self[4:] + self[:4] - return self.countrycode in self.countries and \ - int(base36_to_base10str(_buffer)) % 97 == 1 + return ( + self.countrycode in self.countries + and int(base36_to_base10str(_buffer)) % 97 == 1 + ) def __repr__(self): ''' @@ -387,7 +389,7 @@ class IBAN(str): 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 @@ -421,22 +423,24 @@ class IBAN(str): ''' 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) + i = 0 + max_i = len(fmt._iban) while i < max_i: if fmt._iban[i] == element: - next = i +1 + next = i + 1 while next < max_i and fmt._iban[next] == element: next += 1 return next - i @@ -453,7 +457,10 @@ class BBAN(object): if countrycode.upper() in IBAN.countries: self._fmt = IBAN.BBAN_formats[countrycode.upper()] res = '' - i = 0; j = 0; max_i = len(self._fmt._bban); max_j = len(bban) + i = 0 + j = 0 + max_i = len(self._fmt._bban) + max_j = len(bban) while i < max_i and j < max_j: while bban[j] in ' \t' and j < max_j: j += 1 @@ -475,7 +482,7 @@ class BBAN(object): # 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 @@ -512,15 +519,16 @@ class BBAN(object): '''Simple check if BBAN is in the right format''' return self._bban and True or False + if __name__ == '__main__': import sys for arg in sys.argv[1:]: iban = IBAN(arg) - print 'IBAN:', iban - print 'country code:', iban.countrycode - print 'bank code:', iban.bankcode - print 'branch code:', iban.branchcode - print 'BBAN:', iban.BBAN - print 'localized BBAN:', iban.localized_BBAN - print 'check digits:', iban.checkdigits - print 'checksum:', iban.checksum + print('IBAN:', iban) + print('country code:', iban.countrycode) + print('bank code:', iban.bankcode) + print('branch code:', iban.branchcode) + print('BBAN:', iban.BBAN) + print('localized BBAN:', iban.localized_BBAN) + print('check digits:', iban.checkdigits) + print('checksum:', iban.checksum) diff --git a/account_banking/sepa/postalcode.py b/account_banking/sepa/postalcode.py index 1220c4ea4..c0b8bf81c 100644 --- a/account_banking/sepa/postalcode.py +++ b/account_banking/sepa/postalcode.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -27,6 +27,7 @@ import re __all__ = ['split', 'get', 'PostalCode'] + class PostalCode(object): ''' The PostalCode class is a wrapper around PostCodeFormat and an internal @@ -46,11 +47,11 @@ class PostalCode(object): ''' # Sort formats on length, longest first formats = [(len(x), x) for x in format.split('|')] - formats = [x[1] for x in sorted(formats, lambda x,y: -cmp(x,y))] - self.res = [re.compile(x.replace('#', '\\d').replace('@','[A-Z]')) + formats = [x[1] for x in sorted(formats, lambda x, y: -cmp(x, y))] + self.res = [re.compile(x.replace('#', '\\d').replace('@', '[A-Z]')) for x in formats - ] - + ] + def get(self, str_): ''' Return the postal code from the string str_ @@ -99,7 +100,8 @@ class PostalCode(object): 'IM': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA', 'IL': '#####', 'IT': '####', 'JM': '', 'JP': '###-####', 'JE': '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA', - 'JO': '#####', 'KZ': '######', 'KE': '#####', 'KI': '', 'KP': '###-###', + 'JO': '#####', 'KZ': '######', 'KE': '#####', 'KI': '', + 'KP': '###-###', 'KR': 'SEOUL ###-###', 'KW': '#####', 'KG': '######', 'LA': '#####', 'LV': 'LV-####', 'LB': '#### ####|####', 'LS': '###', 'LR': '####', 'LY': '', 'LI': '####', 'LT': 'LT-#####', 'LU': '####', 'MO': '', @@ -139,7 +141,7 @@ class PostalCode(object): country . Returns iso, postal code and the remaining part of . - + When iso is filled but postal code remains empty, no postal code could be found according to the rules of iso. @@ -155,14 +157,12 @@ class PostalCode(object): # Find optimum (= max length postalcode) when iso code is unknown all = {} - opt_iso = '' max_l = 0 for key in cls._formats.iterkeys(): i, p, c = cls.split(str_, key) l = len(p) if l > max_l: max_l = l - opt_iso = i if l in all: all[l].append((i, p, c)) else: diff --git a/account_banking/struct.py b/account_banking/struct.py index e47d5faf3..b5e27e57d 100644 --- a/account_banking/struct.py +++ b/account_banking/struct.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -18,6 +18,7 @@ # along with this program. If not, see . # ############################################################################## + ''' Define a struct class which behaves like a dict, but allows using object.attr alongside object['attr']. @@ -25,6 +26,7 @@ object.attr alongside object['attr']. __all__ = ['struct'] + class struct(dict): ''' Ease working with dicts. Allow dict.key alongside dict['key'] @@ -52,4 +54,4 @@ class struct(dict): else: fmt = '%*.*s%%s: %%s' % (indent, indent, '') for item in self.iteritems(): - print fmt % item + print(fmt % item) diff --git a/account_banking/wizard/__init__.py b/account_banking/wizard/__init__.py index 169e55e51..e2ed25a0f 100644 --- a/account_banking/wizard/__init__.py +++ b/account_banking/wizard/__init__.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -18,8 +18,7 @@ # along with this program. If not, see . # ############################################################################## -import bank_import -import banking_transaction_wizard -import link_partner -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import bank_import +from . import banking_transaction_wizard +from . import link_partner diff --git a/account_banking/wizard/bank_import.py b/account_banking/wizard/bank_import.py index c5caff7c5..5b73eaf72 100644 --- a/account_banking/wizard/bank_import.py +++ b/account_banking/wizard/bank_import.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -23,11 +23,13 @@ # Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes # Stefan Rijnhart (Therp): bugreport and bugfix # + ''' This module contains the business logic of the wizard account_banking_import. The parsing is done in the parser modules. Every parser module is required to use parser.models as a mean of communication with the business logic. ''' + import base64 import datetime from openerp.osv import orm, fields @@ -44,6 +46,7 @@ bt = models.mem_bank_transaction # the real payment date. This can occur with online transactions (web shops). payment_window = datetime.timedelta(days=10) + def parser_types(*args, **kwargs): '''Delay evaluation of parser types until start of wizard, to allow depending modules to initialize and add their parsers to the list @@ -57,18 +60,26 @@ class banking_import_line(orm.TransientModel): _columns = { 'name': fields.char('Name', size=64), 'date': fields.date('Date', readonly=True), - 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), + 'amount': fields.float( + 'Amount', + digits_compute=dp.get_precision('Account'), + ), 'statement_line_id': fields.many2one( 'account.bank.statement.line', 'Resulting statement line', readonly=True), 'type': fields.selection([ - ('supplier','Supplier'), - ('customer','Customer'), - ('general','General') + ('supplier', 'Supplier'), + ('customer', 'Customer'), + ('general', 'General') ], 'Type', required=True), 'partner_id': fields.many2one('res.partner', 'Partner'), - 'statement_id': fields.many2one('account.bank.statement', 'Statement', - select=True, required=True, ondelete='cascade'), + 'statement_id': fields.many2one( + 'account.bank.statement', + 'Statement', + select=True, + required=True, + ondelete='cascade', + ), 'ref': fields.char('Reference', size=32), 'note': fields.text('Notes'), 'period_id': fields.many2one('account.period', 'Period'), @@ -83,16 +94,19 @@ class banking_import_line(orm.TransientModel): 'account.invoice', 'banking_import_line_invoice_rel', 'line_id', 'invoice_id'), 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'), - 'transaction_type': fields.selection([ + 'transaction_type': fields.selection( + [ # TODO: payment terminal etc... ('invoice', 'Invoice payment'), ('storno', 'Canceled debit order'), ('bank_costs', 'Bank costs'), ('unknown', 'Unknown'), - ], 'Transaction type'), + ], + 'Transaction type', + ), 'duplicate': fields.boolean('Duplicate'), } - + class banking_import(orm.TransientModel): _name = 'account.banking.bank.import' @@ -119,7 +133,8 @@ class banking_import(orm.TransientModel): if not parser: raise orm.except_orm( _('ERROR!'), - _('Unable to import parser %(parser)s. Parser class not found.') % + _('Unable to import parser %(parser)s. Parser class not ' + 'found.') % {'parser': parser_code} ) @@ -133,16 +148,17 @@ class banking_import(orm.TransientModel): if any([x for x in statements if not x.is_valid()]): raise orm.except_orm( _('ERROR!'), - _('The imported statements appear to be invalid! Check your file.') + _('The imported statements appear to be invalid! Check your ' + 'file.') ) # Create the file now, as the statements need to be linked to it import_id = statement_file_obj.create(cr, uid, dict( - company_id = company.id, - file = statements_file, - file_name = banking_import.file_name, - state = 'unfinished', - format = parser.name, + company_id=company.id, + file=statements_file, + file_name=banking_import.file_name, + state='unfinished', + format=parser.name, )) bank_country_code = False @@ -151,14 +167,14 @@ class banking_import(orm.TransientModel): # Results results = struct( - stat_loaded_cnt = 0, - trans_loaded_cnt = 0, - stat_skipped_cnt = 0, - trans_skipped_cnt = 0, - trans_matched_cnt = 0, - bank_costs_invoice_cnt = 0, - error_cnt = 0, - log = [], + stat_loaded_cnt=0, + trans_loaded_cnt=0, + stat_skipped_cnt=0, + trans_skipped_cnt=0, + trans_matched_cnt=0, + bank_costs_invoice_cnt=0, + error_cnt=0, + log=[], ) # Caching @@ -175,7 +191,9 @@ class banking_import(orm.TransientModel): continue # Create fallback currency code - currency_code = statement.local_currency or company.currency_id.name + currency_code = ( + statement.local_currency or company.currency_id.name + ) # Check cache for account info/currency if statement.local_account in info and \ @@ -190,8 +208,10 @@ class banking_import(orm.TransientModel): ) if not account_info: results.log.append( - _('Statements found for unknown account %(bank_account)s') % - {'bank_account': statement.local_account} + _('Statements found for unknown account ' + '%(bank_account)s') % { + 'bank_account': statement.local_account + } ) error_accounts[statement.local_account] = True results.error_cnt += 1 @@ -200,7 +220,7 @@ class banking_import(orm.TransientModel): results.log.append( _('Statements found for account %(bank_account)s, ' 'but no default journal was defined.' - ) % {'bank_account': statement.local_account} + ) % {'bank_account': statement.local_account} ) error_accounts[statement.local_account] = True results.error_cnt += 1 @@ -210,7 +230,7 @@ class banking_import(orm.TransientModel): currency_code = account_info.currency_id.name # Cache results - if not statement.local_account in info: + if statement.local_account not in info: info[statement.local_account] = { currency_code: account_info } @@ -222,22 +242,22 @@ class banking_import(orm.TransientModel): and account_info.currency_id.name != statement.local_currency: # TODO: convert currencies? results.log.append( - _('Statement %(statement_id)s for account %(bank_account)s' + _('Statement %(statement_id)s for account %(bank_account)s' ' uses different currency than the defined bank journal.' - ) % { - 'bank_account': statement.local_account, - 'statement_id': statement.id - } + ) % { + 'bank_account': statement.local_account, + 'statement_id': statement.id + } ) error_accounts[statement.local_account] = True results.error_cnt += 1 continue # Check existence of previous statement - # Less well defined formats can resort to a + # Less well defined formats can resort to a # dynamically generated statement identification # (e.g. a datetime string of the moment of import) - # and have potential duplicates flagged by the + # and have potential duplicates flagged by the # matching procedure statement_ids = statement_obj.search(cr, uid, [ ('name', '=', statement.id), @@ -251,7 +271,8 @@ class banking_import(orm.TransientModel): ) continue - # Get the period for the statement (as bank statement object checks this) + # Get the period for the statement (as bank statement object + # checks this) period_ids = period_obj.search( cr, uid, [ ('company_id', '=', company.id), @@ -259,7 +280,7 @@ class banking_import(orm.TransientModel): ('date_stop', '>=', statement.date), ('special', '=', False), ], context=context) - + if not period_ids: results.log.append( _('No period found covering statement date %(date)s, ' @@ -272,17 +293,17 @@ class banking_import(orm.TransientModel): # Create the bank statement record statement_id = statement_obj.create(cr, uid, dict( - name = statement.id, - journal_id = account_info.journal_id.id, - date = convert.date2str(statement.date), - balance_start = statement.start_balance, - balance_end_real = statement.end_balance, - balance_end = statement.end_balance, - state = 'draft', - user_id = uid, - banking_id = import_id, - company_id = company.id, - period_id = period_ids[0], + name=statement.id, + journal_id=account_info.journal_id.id, + date=convert.date2str(statement.date), + balance_start=statement.start_balance, + balance_end_real=statement.end_balance, + balance_end=statement.end_balance, + state='draft', + user_id=uid, + banking_id=import_id, + company_id=company.id, + period_id=period_ids[0], )) imported_statement_ids.append(statement_id) @@ -294,7 +315,8 @@ class banking_import(orm.TransientModel): values = {} for attr in transaction.__slots__ + ['type']: if attr in import_transaction_obj.column_map: - values[import_transaction_obj.column_map[attr]] = eval('transaction.%s' % attr) + values[import_transaction_obj.column_map[attr]] = \ + eval('transaction.%s' % attr) elif attr in import_transaction_obj._columns: values[attr] = eval('transaction.%s' % attr) values['statement_id'] = statement_id @@ -305,35 +327,17 @@ class banking_import(orm.TransientModel): transaction_id = import_transaction_obj.create( cr, uid, values, context=context) transaction_ids.append(transaction_id) - + results.stat_loaded_cnt += 1 - import_transaction_obj.match(cr, uid, transaction_ids, results=results, context=context) - - #recompute statement end_balance for validation + import_transaction_obj.match( + cr, uid, transaction_ids, results=results, context=context + ) + + # recompute statement end_balance for validation statement_obj.button_dummy( cr, uid, imported_statement_ids, context=context) - - # Original code. Didn't take workflow logistics into account... - # - #cr.execute( - # "UPDATE payment_order o " - # "SET state = 'done', " - # "date_done = '%s' " - # "FROM payment_line l " - # "WHERE o.state = 'sent' " - # "AND o.id = l.order_id " - # "AND l.id NOT IN (" - # "SELECT DISTINCT id FROM payment_line " - # "WHERE date_done IS NULL " - # "AND id IN (%s)" - # ")" % ( - # time.strftime('%Y-%m-%d'), - # ','.join([str(x) for x in payment_line_ids]) - # ) - #) - report = [ '%s: %s' % (_('Total number of statements'), results.stat_skipped_cnt + results.stat_loaded_cnt), @@ -360,15 +364,18 @@ class banking_import(orm.TransientModel): text_log = '\n'.join(report + results.log) state = results.error_cnt and 'error' or 'ready' statement_file_obj.write(cr, uid, import_id, dict( - state = state, log = text_log, - ), context) + state=state, + log=text_log, + ), context) if not imported_statement_ids or not results.trans_loaded_cnt: # file state can be 'ready' while import state is 'error' state = 'error' self.write(cr, uid, [ids[0]], dict( - import_id = import_id, log = text_log, state = state, - statement_ids = [(6, 0, imported_statement_ids)], - ), context) + import_id=import_id, + log=text_log, + state=state, + statement_ids=[(6, 0, imported_statement_ids)], + ), context) return { 'name': (state == 'ready' and _('Review Bank Statements') or _('Error')), @@ -393,13 +400,15 @@ class banking_import(orm.TransientModel): ), 'file_name': fields.char('File name', size=256), 'file': fields.binary( - 'Statements File', required=True, - help = ('The Transactions File to import. Please note that while it is ' - 'perfectly safe to reload the same file multiple times or to load in ' - 'timeframe overlapping statements files, there are formats that may ' - 'introduce different sequencing, which may create double entries.\n\n' - 'To stay on the safe side, always load bank statements files using the ' - 'same format.'), + 'Statements File', + required=True, + help=('The Transactions File to import. Please note that while it ' + 'is perfectly safe to reload the same file multiple times ' + 'or to load in timeframe overlapping statements files, ' + 'there are formats that may introduce different ' + 'sequencing, which may create double entries.\n\n' + 'To stay on the safe side, always load bank statements ' + 'files using the same format.'), states={ 'ready': [('readonly', True)], 'error': [('readonly', True)], @@ -435,8 +444,8 @@ class banking_import(orm.TransientModel): _defaults = { 'state': 'init', - 'company': lambda s,cr,uid,c: + 'company': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( - cr, uid, 'bank.import.transaction', context=c), + cr, uid, 'bank.import.transaction', context=c), 'parser': _default_parser_type, } diff --git a/account_banking/wizard/banking_transaction_wizard.py b/account_banking/wizard/banking_transaction_wizard.py index 0941f88b2..dbcc7b886 100644 --- a/account_banking/wizard/banking_transaction_wizard.py +++ b/account_banking/wizard/banking_transaction_wizard.py @@ -7,8 +7,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -50,7 +50,7 @@ class banking_transaction_wizard(orm.TransientModel): return res def create_act_window(self, cr, uid, ids, nodestroy=True, context=None): - """ + """ Return a popup window for this model """ if isinstance(ids, (int, long)): @@ -78,10 +78,10 @@ class banking_transaction_wizard(orm.TransientModel): import_transaction_obj = self.pool.get('banking.import.transaction') trans_id = self.read( cr, uid, ids[0], ['import_transaction_id'], - context=context)['import_transaction_id'][0] # many2one tuple + context=context)['import_transaction_id'][0] # many2one tuple import_transaction_obj.match(cr, uid, [trans_id], context=context) return self.create_act_window(cr, uid, ids, context=None) - + def write(self, cr, uid, ids, vals, context=None): """ Implement a trigger to retrieve the corresponding move line @@ -121,22 +121,27 @@ class banking_transaction_wizard(orm.TransientModel): # Given the arity of the relation, there is are always # multiple possibilities but the move lines here are # prefiltered for having account_id.type payable/receivable - # and the regular invoice workflow should only come up with + # and the regular invoice workflow should only come up with # one of those only. for move_line in wiz.import_transaction_id.move_line_ids: if (move_line.invoice == wiz.import_transaction_id.invoice_id): transaction_obj.write( cr, uid, wiz.import_transaction_id.id, - { 'move_line_id': move_line.id, }, context=context) + {'move_line_id': move_line.id, }, + context=context + ) statement_line_obj.write( - cr, uid, wiz.import_transaction_id.statement_line_id.id, - { 'partner_id': move_line.partner_id.id or False, - 'account_id': move_line.account_id.id, - }, context=context) + cr, uid, + wiz.import_transaction_id.statement_line_id.id, + { + 'partner_id': ( + move_line.partner_id.id or False), + 'account_id': move_line.account_id.id, + }, context=context) found = True break - # Cannot match the invoice + # Cannot match the invoice if not found: orm.except_orm( _("No entry found for the selected invoice"), @@ -150,15 +155,16 @@ class banking_transaction_wizard(orm.TransientModel): # Rewrite *2many directive notation if manual_invoice_ids: manual_invoice_ids = ( - [i[1] for i in manual_invoice_ids if i[0]==4] + - [j for i in manual_invoice_ids if i[0]==6 for j in i[2]]) + [i[1] for i in manual_invoice_ids if i[0] == 4] + + [j for i in manual_invoice_ids if i[0] == 6 for j in i[2]]) if manual_move_line_ids: manual_move_line_ids = ( - [i[1] for i in manual_move_line_ids if i[0]==4] + - [j for i in manual_move_line_ids if i[0]==6 for j in i[2]]) + [i[1] for i in manual_move_line_ids if i[0] == 4] + + [j for i in manual_move_line_ids + if i[0] == 6 for j in i[2]]) for wiz in self.browse(cr, uid, ids, context=context): - #write can be called multiple times for the same values - #that doesn't hurt above, but it does here + # write can be called multiple times for the same values + # that doesn't hurt above, but it does here if wiz.match_type and ( len(manual_move_line_ids) > 1 or len(manual_invoice_ids) > 1): @@ -171,7 +177,8 @@ class banking_transaction_wizard(orm.TransientModel): found_move_line = False if invoice.move_id: for line in invoice.move_id.line_id: - if line.account_id.type in ('receivable', 'payable'): + if line.account_id.type in ('receivable', + 'payable'): todo.append((invoice.id, line.id)) found_move_line = True break @@ -181,12 +188,13 @@ class banking_transaction_wizard(orm.TransientModel): _("No entry found for the selected invoice. ")) for move_line_id in manual_move_line_ids: todo_entry = [False, move_line_id] - move_line=move_line_obj.read( - cr, - uid, - move_line_id, - ['invoice'], - context=context) + move_line = move_line_obj.read( + cr, + uid, + move_line_id, + ['invoice'], + context=context + ) if move_line['invoice']: todo_entry[0] = move_line['invoice'][0] todo.append(todo_entry) @@ -194,25 +202,27 @@ class banking_transaction_wizard(orm.TransientModel): while todo: todo_entry = todo.pop() move_line = move_line_obj.browse( - cr, uid, todo_entry[1], context) + cr, uid, todo_entry[1], context) transaction_id = wiz.import_transaction_id.id statement_line_id = wiz.statement_line_id.id if len(todo) > 0: statement_line_id = wiz.statement_line_id.split_off( - move_line.debit or -move_line.credit)[0] + move_line.debit or -move_line.credit)[0] transaction_id = statement_line_obj.browse( - cr, - uid, - statement_line_id, - context=context).import_transaction_id.id + cr, + uid, + statement_line_id, + context=context + ).import_transaction_id.id vals = { 'move_line_id': todo_entry[1], 'move_line_ids': [(6, 0, [todo_entry[1]])], 'invoice_id': todo_entry[0], - 'invoice_ids': [(6, 0, - [todo_entry[0]] if todo_entry[0] else [])], + 'invoice_ids': [ + (6, 0, [todo_entry[0]] if todo_entry[0] else []) + ], 'match_type': 'manual', } @@ -221,7 +231,7 @@ class banking_transaction_wizard(orm.TransientModel): st_line_vals = { 'account_id': move_line_obj.read( - cr, uid, todo_entry[1], + cr, uid, todo_entry[1], ['account_id'], context=context)['account_id'][0], } @@ -231,7 +241,7 @@ class banking_transaction_wizard(orm.TransientModel): ).partner_id.commercial_partner_id.id statement_line_obj.write( - cr, uid, statement_line_id, + cr, uid, statement_line_id, st_line_vals, context=context) return res @@ -255,22 +265,19 @@ class banking_transaction_wizard(orm.TransientModel): # Get the bank account setting record, to reset the account account_id = False journal_id = wiz.statement_line_id.statement_id.journal_id.id - setting_ids = settings_pool.find(cr, uid, journal_id, context=context) + setting_ids = settings_pool.find( + cr, uid, journal_id, context=context + ) # Restore partner id from the bank account or else reset partner_id = False if (wiz.statement_line_id.partner_bank_id and wiz.statement_line_id.partner_bank_id.partner_id): - partner_id = wiz.statement_line_id.partner_bank_id.partner_id.id + partner_id = ( + wiz.statement_line_id.partner_bank_id.partner_id.id + ) wiz.write({'partner_id': partner_id}) - # Select account type by parter customer or supplier, - # or default based on amount sign - if wiz.amount < 0: - account_type = 'payable' - else: - account_type = 'receivable' - bank_partner = False if partner_id: bank_partner = wiz.statement_line_id.partner_bank_id.partner_id @@ -295,13 +302,18 @@ class banking_transaction_wizard(orm.TransientModel): wiz.statement_line_id.write({'account_id': account_id}) if wiz.statement_line_id: - #delete splits causing an unsplit if this is a split - #transaction - statement_pool.unlink(cr, uid, - statement_pool.search(cr, uid, - [('parent_id', '=', wiz.statement_line_id.id)], - context=context), - context=context) + # delete splits causing an unsplit if this is a split + # transaction + statement_pool.unlink( + cr, + uid, + statement_pool.search( + cr, uid, + [('parent_id', '=', wiz.statement_line_id.id)], + context=context + ), + context=context + ) if wiz.import_transaction_id: wiz.import_transaction_id.clear_and_write() @@ -313,15 +325,15 @@ class banking_transaction_wizard(orm.TransientModel): ids = [ids] transaction_obj = self.pool.get('banking.import.transaction') for wiz in self.read( - cr, uid, ids, ['duplicate', 'import_transaction_id'], - context=context): + cr, uid, ids, ['duplicate', 'import_transaction_id'], + context=context): transaction_obj.write( - cr, uid, wiz['import_transaction_id'][0], + cr, uid, wiz['import_transaction_id'][0], {'duplicate': not wiz['duplicate']}, context=context) return self.create_act_window(cr, uid, ids, context=None) def button_done(self, cr, uid, ids, context=None): - return {'type': 'ir.actions.act_window_close'} + return {'type': 'ir.actions.act_window_close'} _columns = { 'name': fields.char('Name', size=64), @@ -349,22 +361,26 @@ class banking_transaction_wizard(orm.TransientModel): 'statement_line_id', 'parent_id', type='many2one', relation='account.bank.statement.line', readonly=True), 'import_transaction_id': fields.related( - 'statement_line_id', 'import_transaction_id', + 'statement_line_id', 'import_transaction_id', string="Import transaction", type='many2one', relation='banking.import.transaction'), 'residual': fields.related( - 'import_transaction_id', 'residual', type='float', + 'import_transaction_id', 'residual', type='float', string='Residual', readonly=True), 'writeoff_account_id': fields.related( 'import_transaction_id', 'writeoff_account_id', type='many2one', relation='account.account', string='Write-off account'), 'invoice_ids': fields.related( - 'import_transaction_id', 'invoice_ids', string="Matching invoices", + 'import_transaction_id', 'invoice_ids', string="Matching invoices", type='many2many', relation='account.invoice'), 'invoice_id': fields.related( - 'import_transaction_id', 'invoice_id', string="Invoice to reconcile", - type='many2one', relation='account.invoice'), + 'import_transaction_id', + 'invoice_id', + string="Invoice to reconcile", + type='many2one', + relation='account.invoice', + ), 'move_line_ids': fields.related( 'import_transaction_id', 'move_line_ids', string="Entry lines", type='many2many', relation='account.move.line'), @@ -372,15 +388,20 @@ class banking_transaction_wizard(orm.TransientModel): 'import_transaction_id', 'move_line_id', string="Entry line", type='many2one', relation='account.move.line'), 'duplicate': fields.related( - 'import_transaction_id', 'duplicate', string='Flagged as duplicate', - type='boolean'), + 'import_transaction_id', + 'duplicate', + string='Flagged as duplicate', + type='boolean', + ), 'match_multi': fields.related( - 'import_transaction_id', 'match_multi', + 'import_transaction_id', 'match_multi', type="boolean", string='Multiple matches'), 'match_type': fields.related( - 'import_transaction_id', 'match_type', type='selection', + 'import_transaction_id', + 'match_type', + type='selection', selection=[ - ('move','Move'), + ('move', 'Move'), ('invoice', 'Invoice'), ('payment', 'Payment line'), ('payment_order', 'Payment order'), @@ -388,8 +409,10 @@ class banking_transaction_wizard(orm.TransientModel): ('manual', 'Manual'), ('payment_manual', 'Payment line (manual)'), ('payment_order_manual', 'Payment order (manual)'), - ], - string='Match type', readonly=True), + ], + string='Match type', + readonly=True, + ), 'manual_invoice_ids': fields.many2many( 'account.invoice', 'banking_transaction_wizard_account_invoice_rel', @@ -401,8 +424,17 @@ class banking_transaction_wizard(orm.TransientModel): 'wizard_id', 'move_line_id', string='Or match one or more entries', domain=[('account_id.reconcile', '=', True), ('reconcile_id', '=', False)]), - 'payment_option': fields.related('import_transaction_id','payment_option', string='Payment Difference', type='selection', required=True, - selection=[('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')]), + 'payment_option': fields.related( + 'import_transaction_id', + 'payment_option', + string='Payment Difference', + type='selection', + required=True, + selection=[ + ('without_writeoff', 'Keep Open'), + ('with_writeoff', 'Reconcile Payment Balance') + ], + ), 'writeoff_analytic_id': fields.related( 'import_transaction_id', 'writeoff_analytic_id', type='many2one', relation='account.analytic.account', @@ -411,9 +443,11 @@ class banking_transaction_wizard(orm.TransientModel): 'statement_line_id', 'analytic_account_id', type='many2one', relation='account.analytic.account', string="Analytic Account"), - 'move_currency_amount': fields.related('import_transaction_id','move_currency_amount', - type='float', string='Match Currency Amount', readonly=True), - } - -banking_transaction_wizard() - + 'move_currency_amount': fields.related( + 'import_transaction_id', + 'move_currency_amount', + type='float', + string='Match Currency Amount', + readonly=True, + ), + } diff --git a/account_banking/wizard/banktools.py b/account_banking/wizard/banktools.py index 1fae20cfe..09f735689 100644 --- a/account_banking/wizard/banktools.py +++ b/account_banking/wizard/banktools.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,7 +24,7 @@ from openerp.addons.account_banking import sepa from openerp.addons.account_banking.struct import struct __all__ = [ - 'get_period', + 'get_period', 'get_bank_accounts', 'get_partner', 'get_country_id', @@ -32,6 +32,7 @@ __all__ = [ 'create_bank_account', ] + def get_period(pool, cr, uid, date, company, log=None): ''' Wrapper over account_period.find() to log exceptions of @@ -43,7 +44,7 @@ def get_period(pool, cr, uid, date, company, log=None): try: period_ids = pool.get('account.period').find( cr, uid, dt=date, context=context) - except Exception, e: + except Exception as e: if log is None: raise else: @@ -51,6 +52,7 @@ def get_period(pool, cr, uid, date, company, log=None): return False return period_ids[0] + def get_bank_accounts(pool, cr, uid, account_number, log, fail=False): ''' Get the bank account with account number account_number @@ -72,6 +74,7 @@ def get_bank_accounts(pool, cr, uid, account_number, log, fail=False): return [] return partner_bank_obj.browse(cr, uid, bank_account_ids) + def _has_attr(obj, attr): # Needed for dangling addresses and a weird exception scheme in # OpenERP's orm. @@ -80,6 +83,7 @@ def _has_attr(obj, attr): except KeyError: return False + def get_partner(pool, cr, uid, name, address, postal_code, city, country_id, log, context=None): ''' @@ -87,7 +91,7 @@ def get_partner(pool, cr, uid, name, address, postal_code, city, 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') @@ -115,7 +119,8 @@ def get_partner(pool, cr, uid, name, address, postal_code, city, key = name.lower() partners = [] for partner in partner_obj.read( - cr, uid, partner_search_ids, ['name', 'commercial_partner_id'], context=context): + cr, uid, partner_search_ids, ['name', 'commercial_partner_id'], + context=context): if (len(partner['name']) > 3 and partner['name'].lower() in key): partners.append(partner) partners.sort(key=lambda x: len(x['name']), reverse=True) @@ -126,6 +131,7 @@ def get_partner(pool, cr, uid, name, address, postal_code, city, 'name %(name)s') % {'name': name}) return partner_ids and partner_ids[0] or False + def get_company_bank_account(pool, cr, uid, account_number, currency, company, log): ''' @@ -139,16 +145,16 @@ def get_company_bank_account(pool, cr, uid, account_number, currency, return False elif len(bank_accounts) != 1: log.append( - _('More than one bank account was found with the same number %(account_no)s') - % dict(account_no = account_number) + _('More than one bank account was found with the same number ' + '%(account_no)s') % dict(account_no=account_number) ) return False if bank_accounts[0].partner_id.id != company.partner_id.id: log.append( _('Account %(account_no)s is not owned by %(partner)s') - % dict(account_no = account_number, - partner = company.partner_id.name, - )) + % dict(account_no=account_number, + partner=company.partner_id.name, + )) return False results.account = bank_accounts[0] bank_settings_obj = pool.get('account.banking.account.settings') @@ -189,8 +195,9 @@ def get_company_bank_account(pool, cr, uid, account_number, currency, return results + def get_or_create_bank(pool, cr, uid, bic, online=False, code=None, - name=None): + name=None, context=None): ''' Find or create the bank with the provided BIC code. When online, the SWIFT database will be consulted in order to @@ -231,38 +238,41 @@ def get_or_create_bank(pool, cr, uid, bic, online=False, code=None, bank_id = False if online: - info, address = bank_obj.online_bank_info(cr, uid, bic, context=context) + info, address = bank_obj.online_bank_info( + cr, uid, bic, context=context + ) if info: bank_id = bank_obj.create(cr, uid, dict( - code = info.code, - name = info.name, - street = address.street, - street2 = address.street2, - zip = address.zip, - city = address.city, - country = country_id, - bic = info.bic[:8], + code=info.code, + name=info.name, + street=address.street, + street2=address.street2, + zip=address.zip, + city=address.city, + country=country_id, + bic=info.bic[:8], )) else: info = struct(name=name, code=code) if not online or not bank_id: bank_id = bank_obj.create(cr, uid, dict( - code = info.code or 'UNKNOW', - name = info.name or _('Unknown Bank'), - country = country_id, - bic = bic, + code=info.code or 'UNKNOW', # FIXME: Typo? + name=info.name or _('Unknown Bank'), + country=country_id, + bic=bic, )) return bank_id, country_id + def get_country_id(pool, cr, uid, transaction, context=None): """ Derive a country id from the info on the transaction. - + :param transaction: browse record of a transaction - :returns: res.country id or False + :returns: res.country id or False """ - + country_code = False iban = sepa.IBAN(transaction.remote_account) if iban.valid: @@ -283,6 +293,7 @@ def get_country_id(pool, cr, uid, transaction, context=None): country_id = company.partner_id.country.id return country_id + def create_bank_account(pool, cr, uid, partner_id, account_number, holder_name, address, city, country_id, bic=False, @@ -291,9 +302,9 @@ def create_bank_account(pool, cr, uid, partner_id, Create a matching bank account with this holder for this partner. ''' values = struct( - partner_id = partner_id, - owner_name = holder_name, - country_id = country_id, + partner_id=partner_id, + owner_name=holder_name, + country_id=country_id, ) # Are we dealing with IBAN? @@ -325,5 +336,3 @@ def create_bank_account(pool, cr, uid, partner_id, # Create bank account and return return pool.get('res.partner.bank').create( cr, uid, values, context=context) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/wizard/link_partner.py b/account_banking/wizard/link_partner.py index 3a74bd6c2..391abb30c 100644 --- a/account_banking/wizard/link_partner.py +++ b/account_banking/wizard/link_partner.py @@ -24,6 +24,7 @@ from openerp.tools.translate import _ from openerp.addons.account_banking.wizard import banktools import ast + class link_partner(orm.TransientModel): _name = 'banking.link_partner' _description = 'Link partner' @@ -66,14 +67,14 @@ class link_partner(orm.TransientModel): '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 + Get default values from the transaction data on the statement line """ if vals and vals.get('statement_line_id'): @@ -86,7 +87,7 @@ class link_partner(orm.TransientModel): 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( @@ -124,17 +125,17 @@ class link_partner(orm.TransientModel): 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', + 'street', 'street2', 'zip', 'city', @@ -148,7 +149,7 @@ class link_partner(orm.TransientModel): 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') @@ -160,13 +161,13 @@ class link_partner(orm.TransientModel): wiz_read = self.read( cr, uid, ids[0], context=context, load='_classic_write') partner_vals = { - 'type': 'default', - } + 'type': 'default', + } self.update_partner_values( cr, uid, wiz_read, partner_vals, context=context) partner_id = self.pool.get('res.partner').create( cr, uid, partner_vals, context=context) - + partner_bank_id = banktools.create_bank_account( self.pool, cr, uid, partner_id, wiz.remote_account, wiz.name, @@ -185,10 +186,10 @@ class link_partner(orm.TransientModel): {'partner_bank_id': partner_bank_id, 'partner_id': partner_id}, context=context) - return {'type': 'ir.actions.act_window_close'} + 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)): @@ -205,5 +206,3 @@ class link_partner(orm.TransientModel): 'res_id': ids[0], 'nodestroy': nodestroy, } - - From ab0a6ce8f891bd8331dd02e8429a6af5fc0b4e1d Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 16:57:56 -0400 Subject: [PATCH 23/29] PEP8 on account_banking_nl_abnamro --- account_banking_nl_abnamro/__openerp__.py | 6 +- account_banking_nl_abnamro/abnamro.py | 83 +++++++++++++---------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/account_banking_nl_abnamro/__openerp__.py b/account_banking_nl_abnamro/__openerp__.py index 959d2669d..b8a63b49e 100644 --- a/account_banking_nl_abnamro/__openerp__.py +++ b/account_banking_nl_abnamro/__openerp__.py @@ -35,8 +35,8 @@ 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. - ''', +Imported bank transfers are organized in statements covering periods of one +week, even if the imported files cover a different period. +''', 'installable': True, } diff --git a/account_banking_nl_abnamro/abnamro.py b/account_banking_nl_abnamro/abnamro.py index 809f776f9..598326f1e 100644 --- a/account_banking_nl_abnamro/abnamro.py +++ b/account_banking_nl_abnamro/abnamro.py @@ -31,7 +31,6 @@ 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.addons.account_banking.sepa import postalcode from openerp.tools.translate import _ from openerp.osv import orm @@ -42,6 +41,7 @@ __all__ = ['parser'] bt = models.mem_bank_transaction + class transaction_message(object): ''' A auxiliary class to validate and coerce read values @@ -56,9 +56,10 @@ class transaction_message(object): 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)) + 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() @@ -72,23 +73,24 @@ class transaction_message(object): 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 + '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 + 'INTL': bt.ORDER, # international order + 'UNKN': bt.ORDER, # everything else 'SEPA': bt.ORDER, 'PAYB': bt.PAYMENT_BATCH, 'RETR': bt.STORNO, @@ -118,10 +120,10 @@ class transaction(models.mem_bank_transaction): 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 + '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 @@ -139,12 +141,11 @@ class transaction(models.mem_bank_transaction): res = [] while(len(line) > col * size): separation = (col + 1) * size - 1 - if line[col * size : separation].strip(): - part = line[col * size : separation] + 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] != ' '): + if (len(line) > separation and line[separation] != ' '): part += line[separation] res.append(part) col += 1 @@ -180,7 +181,7 @@ class transaction(models.mem_bank_transaction): end_index = start_index + 1 while end_index < items_len: key = '/'.join(items[start_index:end_index]) - if key in known_keys: + if key in known_keys: return (key, start_index, end_index) end_index += 1 start_index += 1 @@ -203,15 +204,16 @@ class transaction(models.mem_bank_transaction): 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])) + ( + (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 + # 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 @@ -233,12 +235,14 @@ class transaction(models.mem_bank_transaction): 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 '): + # 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 + # 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): @@ -251,9 +255,10 @@ class transaction(models.mem_bank_transaction): 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]) + (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)) @@ -263,7 +268,7 @@ class transaction(models.mem_bank_transaction): 'SEPA BATCH SALARIS': 'PAYB', 'SEPA TERUGBOEKING': 'RETR', }.get(sepa_type.upper(), 'SEPA') - self.remote_account = sepa_dict.get('IBAN',False) + 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', '') @@ -278,21 +283,24 @@ class transaction(models.mem_bank_transaction): 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 + 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.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 + # 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 @@ -317,12 +325,14 @@ class transaction(models.mem_bank_transaction): # but can be any numeric line really for field in fields[1:]: m = re.match( - "^\s*((BETALINGSKENM\.)|(ACCEPTGIRO))?\s*([0-9]+([ /][0-9]+)*)\s*$", + "^\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 @@ -335,7 +345,7 @@ class statement(models.mem_bank_statement): 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.start_balance = self.end_balance = 0 # msg.start_balance self.import_transaction(msg) def import_transaction(self, msg): @@ -346,6 +356,7 @@ class statement(models.mem_bank_statement): self.end_balance += trans.transferred_amount self.transactions.append(trans) + class parser(models.parser): code = 'ABNAM' country_code = 'NL' @@ -365,7 +376,7 @@ each file covers a period of two weeks. # 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): + for line in csv.reader(lines, delimiter='\t', quoting=csv.QUOTE_NONE): # Skip empty (last) lines if not line: continue @@ -381,5 +392,3 @@ each file covers a period of two weeks. stmnt = statement(msg) result.append(stmnt) return result - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 54039f126c233e3785ba9dda701e1acf2280f0cc Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 17:02:30 -0400 Subject: [PATCH 24/29] PEP8 on account_banking_mt940 --- account_banking_mt940/__openerp__.py | 16 ++++++++-------- account_banking_mt940/mt940.py | 21 ++++++++++++++------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/account_banking_mt940/__openerp__.py b/account_banking_mt940/__openerp__.py index 3a6ee25a3..c5eff3085 100644 --- a/account_banking_mt940/__openerp__.py +++ b/account_banking_mt940/__openerp__.py @@ -19,9 +19,9 @@ # ############################################################################## { - "name" : "MT940", - "version" : "1.0", - "author" : "Therp BV", + "name": "MT940", + "version": "1.0", + "author": "Therp BV", "complexity": "expert", "description": """ This addon provides a generic parser for MT940 files. Given that MT940 is a @@ -32,11 +32,11 @@ certain bank. See account_banking_nl_ing_mt940 for an example on how to use it. """, - "category" : "Dependency", - "depends" : [ + "category": "Dependency", + "depends": [ 'account_banking', ], - "data" : [ + "data": [ ], "js": [ ], @@ -47,7 +47,7 @@ See account_banking_nl_ing_mt940 for an example on how to use it. "auto_install": False, "installable": True, "application": False, - "external_dependencies" : { - 'python' : [], + "external_dependencies": { + 'python': [], }, } diff --git a/account_banking_mt940/mt940.py b/account_banking_mt940/mt940.py index c90de08a0..d425e3028 100644 --- a/account_banking_mt940/mt940.py +++ b/account_banking_mt940/mt940.py @@ -27,18 +27,23 @@ import re import datetime import logging try: - from openerp.addons.account_banking.parsers.models import\ - mem_bank_statement, mem_bank_transaction + from openerp.addons.account_banking.parsers.models import ( + mem_bank_statement, + mem_bank_transaction, + ) from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT except ImportError: - #this allows us to run this file standalone, see __main__ at the end + # this allows us to run this file standalone, see __main__ at the end + class mem_bank_statement: def __init__(self): self.transactions = [] + class mem_bank_transaction: pass DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d" + class MT940(object): '''Inherit this class in your account_banking.parsers.models.parser, define functions to handle the tags you need to handle and adjust static @@ -46,7 +51,7 @@ class MT940(object): Note that order matters: You need to do your_parser(MT940, parser), not the other way around! - + At least, you should override handle_tag_61 and handle_tag_86. Don't forget to call super. handle_tag_* functions receive the remainder of the the line (that is, @@ -59,7 +64,7 @@ class MT940(object): footer_regex = '^-}$' footer_regex = '^-XXX$' 'The line that denotes end of message, we need to create a new statement' - + tag_regex = '^:[0-9]{2}[A-Z]*:' 'The beginning of a record, should be anchored to beginning of the line' @@ -194,15 +199,17 @@ class MT940(object): banks occur''' pass -'utility functions' + def str2date(string, fmt='%y%m%d'): return datetime.datetime.strptime(string, fmt) + def str2float(string): return float(string.replace(',', '.')) -'testing' + def main(filename): + """testing""" parser = MT940() parser.parse(None, open(filename, 'r').read()) for statement in parser.statements: From c47bba08e247a889afa58ab12e40790a62074446 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 17:11:38 -0400 Subject: [PATCH 25/29] PEP8 on account_banking_iban_lookup --- account_banking_iban_lookup/online.py | 80 +++++++++++++++---------- account_banking_iban_lookup/urlagent.py | 28 ++++++--- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/account_banking_iban_lookup/online.py b/account_banking_iban_lookup/online.py index 48036ce46..aa1ba3622 100644 --- a/account_banking_iban_lookup/online.py +++ b/account_banking_iban_lookup/online.py @@ -23,10 +23,14 @@ This module provides online bank databases for conversion between BBAN and IBAN numbers and for consulting. ''' import re -import urllib, urllib2 +import urllib +import urllib2 from BeautifulSoup import BeautifulSoup from openerp.addons.account_banking.sepa import postalcode -from openerp.addons.account_banking_iban_lookup.urlagent import URLAgent, SoupForm +from openerp.addons.account_banking_iban_lookup.urlagent import ( + URLAgent, + SoupForm, +) from openerp.addons.account_banking.sepa.iban import IBAN from openerp.addons.account_banking.struct import struct @@ -38,6 +42,7 @@ __all__ = [ IBANlink_NL = 'http://www.ibannl.org/iban_check.php' IBANlink_BE = 'http://www.ibanbic.be/' + def get_iban_bic_NL(bank_acc): ''' Consult the Dutch online banking database to check both the account number @@ -51,14 +56,14 @@ def get_iban_bic_NL(bank_acc): if len(number) <= 7: iban = IBAN.create(BBAN='INGB' + number.rjust(10, '0'), countrycode='NL' - ) + ) return struct( - iban = iban.replace(' ',''), - account = iban.BBAN[4:], - bic = 'INGBNL2A', - code = 'INGBNL', - bank = 'ING Bank N.V.', - country_id = 'NL', + iban=iban.replace(' ', ''), + account=iban.BBAN[4:], + bic='INGBNL2A', + code='INGBNL', + bank='ING Bank N.V.', + country_id='NL', ) data = urllib.urlencode(dict(number=number, method='POST')) @@ -66,6 +71,7 @@ def get_iban_bic_NL(bank_acc): response = urllib2.urlopen(request) soup = BeautifulSoup(response) result = struct() + attr = None for _pass, td in enumerate(soup.findAll('td')): if _pass % 2 == 1: result[attr] = unicode(td.find('font').contents[0]) @@ -81,6 +87,7 @@ def get_iban_bic_NL(bank_acc): return result return None + def get_iban_bic_BE(bank_acc): ''' Consult the Belgian online database to check both account number and the @@ -88,7 +95,9 @@ def get_iban_bic_BE(bank_acc): in Belgium and will only convert Belgian local account numbers. ''' def contents(soup, attr): - return soup.find('input', {'id': 'textbox%s' % attr}).get('value').strip() + return soup.find('input', { + 'id': 'textbox%s' % attr + }).get('value').strip() if not bank_acc.strip(): return None @@ -121,6 +130,7 @@ def get_iban_bic_BE(bank_acc): result.code = result.bic[:6] return result + def BBAN_is_IBAN(bank_acc): ''' Intelligent copy, valid for SEPA members who switched to SEPA from old @@ -131,15 +141,16 @@ def BBAN_is_IBAN(bank_acc): else: iban_acc = IBAN(bank_acc) return struct( - iban = str(iban_acc), - account = str(bank_acc), - country_id = iban_acc.countrycode, - code = iban_acc.BIC_searchkey, + iban=str(iban_acc), + account=str(bank_acc), + country_id=iban_acc.countrycode, + code=iban_acc.BIC_searchkey, # Note: BIC can not be constructed here! - bic = False, - bank = False, + bic=False, + bank=False, ) + _account_info = { # TODO: Add more online data banks 'BA': BBAN_is_IBAN, @@ -153,6 +164,7 @@ _account_info = { 'SM': BBAN_is_IBAN, } + def account_info(iso, bank_acc): ''' Consult the online database for this country to obtain its @@ -165,9 +177,11 @@ def account_info(iso, bank_acc): return _account_info[iso](bank_acc) return False + bic_re = re.compile("[^']+'([^']*)'.*") SWIFTlink = 'http://www.swift.com/bsl/freequery.do' + def bank_info(bic): ''' Consult the free online SWIFT service to obtain the name and address of a @@ -177,7 +191,7 @@ def bank_info(bic): automated usage, so user like behavior is required. Update January 2012: Always return None, as the SWIFT page to retrieve the - information does no longer exist. + information does no longer exist. If demand exists, maybe bite the bullet and integrate with a paid web service such as http://www.iban-rechner.de. lp914922 additionally suggests to make online lookup optional. @@ -190,7 +204,7 @@ def bank_info(bic): for trsoup in soup('tr'): for stage, tdsoup in enumerate(trsoup('td')): if stage == 0: - attr = tdsoup.contents[0].strip().replace(' ','_') + attr = tdsoup.contents[0].strip().replace(' ', '_') elif stage == 2: if tdsoup.contents: retval[attr] = tdsoup.contents[0].strip() @@ -203,8 +217,8 @@ def bank_info(bic): request = agent.open(SWIFTlink) soup = BeautifulSoup(request) - # Parse request form. As this form is intertwined with a table, use the parent - # as root to search for form elements. + # Parse request form. As this form is intertwined with a table, use the + # parent as root to search for form elements. form = SoupForm(soup.find('form', {'id': 'frmFreeSearch1'}), parent=True) # Fill form fields @@ -221,7 +235,8 @@ def bank_info(bic): if not bic_button: return None, None - # Overwrite the location with 'any' ('XXX') to narrow the results to one or less. + # Overwrite the location with 'any' ('XXX') to narrow the results to one + # or less. # Assume this regexp will never fail... full_bic = bic_re.match(bic_button.get('href')).groups()[0][:8] + 'XXX' @@ -236,13 +251,13 @@ def bank_info(bic): soup = BeautifulSoup(response) # Now parse the results - tables = soup.find('div', {'id':'Middle'}).findAll('table') + tables = soup.find('div', {'id': 'Middle'}).findAll('table') if not tables: return None, None tablesoup = tables[2]('table') if not tablesoup: return None, None - + codes = harvest(tablesoup[0]) if not codes: return None, None @@ -253,9 +268,9 @@ def bank_info(bic): # banks world wide using the same name. # The concatenation with the two character country code is for most # national branches sufficient as a unique identifier. - code = full_bic[:6], - bic = full_bic, - name = codes.Institution_name, + code=full_bic[:6], + bic=full_bic, + name=codes.Institution_name, ) address = harvest(tablesoup[1]) @@ -264,14 +279,14 @@ def bank_info(bic): if not address.Zip_Code: if address.Location: iso, address.Zip_Code, address.Location = \ - postalcode.split(address.Location, full_bic[4:6]) + postalcode.split(address.Location, full_bic[4:6]) bankaddress = struct( - street = address.Address.title(), - city = address.Location.strip().title(), - zip = address.Zip_Code, - country = address.Country.title(), - country_id = full_bic[4:6], + street=address.Address.title(), + city=address.Location.strip().title(), + zip=address.Zip_Code, + country=address.Country.title(), + country_id=full_bic[4:6], ) if ' ' in bankaddress.street: bankaddress.street, bankaddress.street2 = [ @@ -281,4 +296,3 @@ def bank_info(bic): bankaddress.street2 = '' return bankinfo, bankaddress - diff --git a/account_banking_iban_lookup/urlagent.py b/account_banking_iban_lookup/urlagent.py index 404d6b9e1..4f77c933c 100644 --- a/account_banking_iban_lookup/urlagent.py +++ b/account_banking_iban_lookup/urlagent.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -28,7 +28,8 @@ import urllib __all__ = ['urlsplit', 'urljoin', 'pathbase', 'urlbase', 'SoupForm', 'URLAgent' - ] + ] + def urlsplit(url): ''' @@ -43,7 +44,8 @@ def urlsplit(url): host, path = urllib.splithost(url) return (scheme, host, path) -def urljoin(scheme, host, path, args = None): + +def urljoin(scheme, host, path, args=None): ''' Join scheme, host and path to a full URL. Optional: add urlencoded args. @@ -54,15 +56,17 @@ def urljoin(scheme, host, path, args = None): url += '?%s' % urllib.urlencode(args) return url + def pathbase(path): ''' Return the base for the path in order to satisfy relative paths. Helper function. ''' if path and '/' in path: - return path[:path.rfind('/') +1] + return path[:path.rfind('/') + 1] return path + def urlbase(url): ''' Return the base URL for url in order to satisfy relative paths. @@ -71,6 +75,7 @@ def urlbase(url): scheme, host, path = urlsplit(url) return urljoin(scheme, host, pathbase(path)) + class SoupForm(object): ''' A SoupForm is a representation of a HTML Form in BeautifulSoup terms. @@ -94,7 +99,7 @@ class SoupForm(object): if parent: self.soup = soup.parent - # Harvest input elements. + # Harvest input elements. self._args = {} for item in self.soup.findAll('input'): # Make sure to initialize to '' to avoid None strings to appear @@ -150,6 +155,7 @@ class SoupForm(object): args.update(self._extra_args) return args + class URLAgent(object): ''' Assistent object to ease HTTP(S) requests. @@ -160,8 +166,12 @@ class URLAgent(object): super(URLAgent, self).__init__(*args, **kwargs) self._extra_headers = {} self.headers = { - 'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.0.10) Gecko/2009042708 Fedora/3.0.10-1.fc9 Firefox/3.0.10', - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'User-Agent': ( + 'Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.0.10) ' + 'Gecko/2009042708 Fedora/3.0.10-1.fc9 Firefox/3.0.10'), + 'Accept': ( + 'text/html,application/xhtml+xml,application/xml;' + 'q=0.9,*/*;q=0.8'), 'Accept-Language': 'en-us;q=1.0', 'Accept-Charset': 'UTF-8,*', 'Cache-Control': 'max-age=0' @@ -193,7 +203,7 @@ class URLAgent(object): # Get and set cookies for next actions attributes = request.info() - if attributes.has_key('set-cookie'): + if 'set-cookie' in attributes: self.agent.addheader('Cookie', attributes['set-cookie']) # Add referer From b1019e999dd2864e17f36cda3820e9f38ad93f92 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 17:13:40 -0400 Subject: [PATCH 26/29] PEP8 on account_banking_fr_lcr --- account_banking_fr_lcr/__openerp__.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/account_banking_fr_lcr/__openerp__.py b/account_banking_fr_lcr/__openerp__.py index 631d1882e..11ca16fe3 100644 --- a/account_banking_fr_lcr/__openerp__.py +++ b/account_banking_fr_lcr/__openerp__.py @@ -43,11 +43,19 @@ French Letter of Change ======================= -This module adds support for French Letters of Change (in French : Lettre de Change Relevé aka LCR). This payment type is still in use in France and it is *not* replaced by SEPA one-off Direct Debits. With this module, you can generate a CFONB file to send to your bank. +This module adds support for French Letters of Change (in French : +Lettre de Change Relevé aka LCR). -This module uses the framework provided by the banking addons, cf https://launchpad.net/banking-addons +This payment type is still in use in France and it is *not* replaced by SEPA +one-off Direct Debits. -Please contact Alexis de Lattre from Akretion for any help or question about this module. - ''', +With this module, you can generate a CFONB file to send to your bank. + +This module uses the framework provided by the banking addons, +cf https://github.com/OCA/banking + +Please contact Alexis de Lattre from Akretion +for any help or question about this module. +''', 'active': False, } From 596304f48f5414c4227af34c3b6914421209c6b2 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 17:15:12 -0400 Subject: [PATCH 27/29] PEP8 on account_banking_camt --- account_banking_camt/camt.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/account_banking_camt/camt.py b/account_banking_camt/camt.py index b649c5f59..c64407b03 100644 --- a/account_banking_camt/camt.py +++ b/account_banking_camt/camt.py @@ -5,8 +5,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -26,6 +26,7 @@ from openerp.addons.account_banking.parsers.convert import str2date bt = models.mem_bank_transaction + class transaction(models.mem_bank_transaction): def __init__(self, values, *args, **kwargs): @@ -36,6 +37,7 @@ class transaction(models.mem_bank_transaction): def is_valid(self): return not self.error_message + class parser(models.parser): code = 'CAMT' country_code = 'NL' @@ -69,7 +71,7 @@ CAMT Format parser def find(self, node, expr): """ Like xpath(), but return first result if any or else False - + Return None to test nodes for being truesy """ result = node.xpath(expr, namespaces={'ns': self.ns[1:-1]}) @@ -82,19 +84,20 @@ CAMT Format parser :param node: BkToCstmrStmt/Stmt/Bal node :param balance type: one of 'OPBD', 'PRCD', 'ITBD', 'CLBD' """ - code_expr = './ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="%s"]/../../..' % balance_type + code_expr = ('./ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="%s"]/../../..' + % balance_type) return self.xpath(node, code_expr) - + def parse_amount(self, node): """ Parse an element that contains both Amount and CreditDebitIndicator - + :return: signed amount :returntype: float """ sign = -1 if node.find(self.ns + 'CdtDbtInd').text == 'DBIT' else 1 return sign * float(node.find(self.ns + 'Amt').text) - + def get_start_balance(self, node): """ Find the (only) balance node with code OpeningBalance, or @@ -240,7 +243,7 @@ CAMT Format parser structured = self.find( TxDtls, './ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref') if structured is None or not structured.text: - structured = self.find(TxDtls, './ns:Refs/ns:EndToEndId') + structured = self.find(TxDtls, './ns:Refs/ns:EndToEndId') if structured is not None: vals['reference'] = structured.text else: From c978f113066a6d995461edd8a788c2ebc98a277b Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 25 Aug 2014 17:19:13 -0400 Subject: [PATCH 28/29] PEP8 on account_bank_statement_tax --- .../model/account_bank_statement.py | 28 ++++++++++++------- .../model/account_bank_statement_line.py | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/account_bank_statement_tax/model/account_bank_statement.py b/account_bank_statement_tax/model/account_bank_statement.py index b6c940aed..59900d07c 100644 --- a/account_bank_statement_tax/model/account_bank_statement.py +++ b/account_bank_statement_tax/model/account_bank_statement.py @@ -36,7 +36,7 @@ class AccountBankStatement(orm.Model): @param defaults: dictionary of default move line values. Usually the same as the originating move line. - return one or more serialized tax move lines and a set of values to + return one or more serialized tax move lines and a set of values to update the originating move line with, containing the new amount. """ @@ -50,8 +50,8 @@ class AccountBankStatement(orm.Model): fiscal_position = ( st_line.partner_id.property_account_position - if st_line.partner_id and - st_line.partner_id.property_account_position + if st_line.partner_id + and st_line.partner_id.property_account_position else False) tax_ids = self.pool.get('account.fiscal.position').map_tax( cr, uid, fiscal_position, [st_line.tax_id]) @@ -66,25 +66,33 @@ class AccountBankStatement(orm.Model): update_move_line['tax_code_id'] = tax['base_code_id'] update_move_line['tax_amount'] = tax['base_sign'] * ( computed_taxes.get('total', 0.0)) - # As the tax is inclusive, we need to correct the amount on the - # original move line + # As the tax is inclusive, we need to correct the amount + # on the original move line amount = computed_taxes.get('total', 0.0) - update_move_line['credit'] = ((amount < 0) and -amount) or 0.0 - update_move_line['debit'] = ((amount > 0) and amount) or 0.0 + update_move_line['credit'] = ( + (amount < 0) and -amount) or 0.0 + update_move_line['debit'] = ( + (amount > 0) and amount) or 0.0 move_lines.append({ 'move_id': defaults['move_id'], - 'name': defaults.get('name', '') + ' ' + ustr(tax['name'] or ''), + 'name': ( + defaults.get('name', '') + + ' ' + ustr(tax['name'] or '')), 'date': defaults.get('date', False), 'partner_id': defaults.get('partner_id', False), 'ref': defaults.get('ref', False), 'statement_id': defaults.get('statement_id'), 'tax_code_id': tax['tax_code_id'], 'tax_amount': tax['tax_sign'] * tax.get('amount', 0.0), - 'account_id': tax.get('account_collected_id', defaults['account_id']), + 'account_id': ( + tax.get('account_collected_id', + defaults['account_id'])), 'credit': tax['amount'] < 0 and - tax['amount'] or 0.0, 'debit': tax['amount'] > 0 and tax['amount'] or 0.0, - 'account_id': tax.get('account_collected_id', defaults['account_id']), + 'account_id': ( + tax.get('account_collected_id', + defaults['account_id'])), }) return move_lines, update_move_line diff --git a/account_bank_statement_tax/model/account_bank_statement_line.py b/account_bank_statement_tax/model/account_bank_statement_line.py index 4d965cdef..f70f27b38 100644 --- a/account_bank_statement_tax/model/account_bank_statement_line.py +++ b/account_bank_statement_tax/model/account_bank_statement_line.py @@ -28,7 +28,7 @@ class AccountBankStatementLine(orm.Model): _columns = { 'tax_id': fields.many2one( 'account.tax', 'Tax', - domain=[('price_include','=', True)], + domain=[('price_include', '=', True)], help="Apply an (inclusive) tax from the bank statement line", ), } From 593866a6926d1b9e0ef1a2b0478dedf401fa50f7 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 8 Sep 2014 15:24:37 -0400 Subject: [PATCH 29/29] Misc flake8 --- account_banking_camt/__openerp__.py | 4 ++-- account_banking_nl_multibank/__init__.py | 7 +++---- account_banking_partner_journal_account/res_partner.py | 5 +++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/account_banking_camt/__openerp__.py b/account_banking_camt/__openerp__.py index e7950c991..73a87dcf1 100644 --- a/account_banking_camt/__openerp__.py +++ b/account_banking_camt/__openerp__.py @@ -4,8 +4,8 @@ # All Rights Reserved # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, diff --git a/account_banking_nl_multibank/__init__.py b/account_banking_nl_multibank/__init__.py index fa073aa3a..e924ae638 100644 --- a/account_banking_nl_multibank/__init__.py +++ b/account_banking_nl_multibank/__init__.py @@ -11,8 +11,8 @@ # garantees and support are strongly adviced to contract EduSense BV # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -24,6 +24,5 @@ # along with this program. If not, see . # ############################################################################## -import multibank -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import multibank diff --git a/account_banking_partner_journal_account/res_partner.py b/account_banking_partner_journal_account/res_partner.py index 04315f88b..d83d8af89 100644 --- a/account_banking_partner_journal_account/res_partner.py +++ b/account_banking_partner_journal_account/res_partner.py @@ -63,6 +63,7 @@ class ResPartner(orm.Model): res = super(ResPartner, self).def_journal_account_bank_incr( cr, uid, ids, context=context) for partner in self.browse(cr, uid, ids, context=context): - if partner.property_account_receivable_bank_id: - res[partner.id] = partner.property_account_receivable_bank_id.id + bank = partner.property_account_receivable_bank_id + if bank: + res[partner.id] = bank.id return res