diff --git a/account_banking/account_banking.py b/account_banking/account_banking.py index 7f68b1cca..e49212284 100644 --- a/account_banking/account_banking.py +++ b/account_banking/account_banking.py @@ -501,6 +501,7 @@ class account_bank_statement(osv.osv): 'period_id': period_id, # AB 'date': st_line.date, 'name': st_line_number, + 'ref': st_line.ref, }, context=context) account_bank_statement_line_obj.write(cr, uid, [st_line.id], { 'move_ids': [(4, move_id, False)] @@ -524,7 +525,6 @@ class account_bank_statement(osv.osv): val = { 'name': st_line.name, 'date': st_line.date, - 'ref': st_line.ref, 'move_id': move_id, 'partner_id': (((st_line.partner_id) and st_line.partner_id.id) or False), @@ -566,7 +566,6 @@ class account_bank_statement(osv.osv): account_move_line_obj.create(cr, uid, { 'name': st_line.name, 'date': st_line.date, - 'ref': st_line.ref, 'move_id': move_id, 'partner_id': (((st_line.partner_id) and st_line.partner_id.id) or False), diff --git a/account_banking/sepa/iban.py b/account_banking/sepa/iban.py index 6ed5d06c5..9e1c9b35a 100644 --- a/account_banking/sepa/iban.py +++ b/account_banking/sepa/iban.py @@ -190,7 +190,7 @@ class IBAN(str): BBAN_formats = { 'AL': BBANFormat('CCBBBBVAAAAAAAAAAAAAAAAAA', '%B%A'), 'AD': BBANFormat('CCCCBBBBAAAAAAAAAAAA', '%A'), - 'AT': BBANFormat('BBBBBAAAAAAAAAAA', '%A BLZ %C'), + 'AT': BBANFormat('BBBBBAAAAAAAAAAA', '%A BLZ %B'), 'BE': BBANFormat('CCCAAAAAAAVV', '%C-%A-%V'), 'BA': BBANFormat('BBBCCCAAAAAAAA', '%I'), 'BG': BBANFormat('BBBBCCCCAAAAAAAAAA', '%I'), @@ -214,7 +214,7 @@ class IBAN(str): 'GR': BBANFormat('BBBCCCCAAAAAAAAAAAAAAAA', '%B-%C-%A', nolz=True), 'HR': BBANFormat('BBBBBBBAAAAAAAAAA', '%B-%A'), 'HU': BBANFormat('BBBCCCCXAAAAAAAAAAAAAAAV', '%B%C%X %A%V'), - 'IE': BBANFormat('BBBBCCCCCCAAAAAAAAV', '%C %A%V'), + 'IE': BBANFormat('BBBBCCCCCCAAAAAAAA', '%C %A'), 'IL': BBANFormat('BBBCCCAAAAAAAAAAAAA', '%C%A'), # Iceland uses an extra identification number, split in two on # display. Coded here as %P%V. diff --git a/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml b/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml index fce8213d0..322fb4b42 100644 --- a/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml +++ b/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml @@ -7,7 +7,8 @@ SEPA Credit Transfer v04 pain.001.001.04 - + payment @@ -15,7 +16,8 @@ SEPA Credit Transfer v03 pain.001.001.03 - + payment @@ -23,7 +25,8 @@ SEPA Credit Transfer v02 pain.001.001.02 - + payment diff --git a/account_banking_sepa_credit_transfer/wizard/export_sepa.py b/account_banking_sepa_credit_transfer/wizard/export_sepa.py index 3033674aa..bb059c466 100644 --- a/account_banking_sepa_credit_transfer/wizard/export_sepa.py +++ b/account_banking_sepa_credit_transfer/wizard/export_sepa.py @@ -212,8 +212,9 @@ class banking_export_sepa_wizard(osv.osv_memory): debtor_account_iban.text = my_company_iban debtor_agent = etree.SubElement(payment_info, 'DbtrAgt') debtor_agent_institution = etree.SubElement(debtor_agent, 'FinInstnId') - debtor_agent_bic = etree.SubElement(debtor_agent_institution, bic_xml_tag) - debtor_agent_bic.text = my_company_bic + if my_company_bic: + debtor_agent_bic = etree.SubElement(debtor_agent_institution, bic_xml_tag) + debtor_agent_bic.text = my_company_bic charge_bearer = etree.SubElement(payment_info, 'ChrgBr') charge_bearer.text = sepa_export.charge_bearer @@ -239,10 +240,11 @@ class banking_export_sepa_wizard(osv.osv_memory): amount_control_sum += line.amount_currency creditor_agent = etree.SubElement(credit_transfer_transaction_info, 'CdtrAgt') creditor_agent_institution = etree.SubElement(creditor_agent, 'FinInstnId') - creditor_agent_bic = etree.SubElement(creditor_agent_institution, bic_xml_tag) if not line.bank_id: raise osv.except_osv(_('Error :'), _("Missing Bank Account on invoice '%s' (payment order line reference '%s').") %(line.ml_inv_ref.number, line.name)) - creditor_agent_bic.text = line.bank_id.bank.bic + if line.bank_id.bank.bic: + creditor_agent_bic = etree.SubElement(creditor_agent_institution, bic_xml_tag) + creditor_agent_bic.text = line.bank_id.bank.bic creditor = etree.SubElement(credit_transfer_transaction_info, 'Cdtr') creditor_name = etree.SubElement(creditor, 'Nm') creditor_name.text = self._limit_size(cr, uid, line.partner_id.name, name_maxsize, context=context) diff --git a/account_banking_uk_lloyds_corporate/__init__.py b/account_banking_uk_lloyds_corporate/__init__.py new file mode 100644 index 000000000..42f3e358b --- /dev/null +++ b/account_banking_uk_lloyds_corporate/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import lloydscorporate + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_lloyds_corporate/__openerp__.py b/account_banking_uk_lloyds_corporate/__openerp__.py new file mode 100644 index 000000000..a22592b96 --- /dev/null +++ b/account_banking_uk_lloyds_corporate/__openerp__.py @@ -0,0 +1,37 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + 'name': 'Account Banking Lloyds Corporate CSV import', + 'version': '1.0', + 'license': 'AGPL-3', + 'author': 'credativ Ltd', + 'website': 'http://www.credativ.co.uk', + 'category': 'Account Banking', + 'depends': ['account_banking'], + 'init_xml': [], + 'update_xml': [], + 'demo_xml': [], + 'description': ''' + Module to import bank statement CSV for Bank of Lloyds Corporate. + ''', + 'active': False, + 'installable': True, +} diff --git a/account_banking_uk_lloyds_corporate/lloydscorporate.py b/account_banking_uk_lloyds_corporate/lloydscorporate.py new file mode 100644 index 000000000..fcf845cdf --- /dev/null +++ b/account_banking_uk_lloyds_corporate/lloydscorporate.py @@ -0,0 +1,157 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +# Imports LLoyds Corporate format +# + +from account_banking.parsers import models, convert +from tools.translate import _ +import re +import osv +import logging +import csv +from StringIO import StringIO +from operator import itemgetter + +logger = logging.getLogger('lloydscorporate_csv_import') + +class CSVTransaction(models.mem_bank_transaction): + + mapping = { + 'execution_date' : 'date', + 'effective_date': 'date', + 'message' : 'description', + 'name' : 'description', # Use description as transaction name + 'balance' : 'Balance', # Store balance from line for calculating statement balances + } + + def __init__(self, record, *args, **kwargs): + ''' + Transaction creation + ''' + super(CSVTransaction, self).__init__(*args, **kwargs) + + # Parse date of format 01APR13 + record['date'] = convert.str2date(re.sub(r'\W*','',record['Date']), '%d%b%y') + + record['description'] = record['Narrative'].strip() + + # Mapping of simple items + for key, value in self.mapping.iteritems(): + if record.has_key(value): + setattr(self, key, record[value]) + + # Convert debit/credit to float amount + if len(record['Payments'].strip()): + self.transferred_amount = record['Payments'] and -float(record['Payments']) or 0.0 + else: + self.transferred_amount = record['Receipts'] and float(record['Receipts']) or 0.0 + + # Cheque - set reference + transfer_account = re.match(r'\w*\s\d{1,12}$', record['description']) + if transfer_account: + self.reference = transfer_account.group() + + if not self.is_valid(): + logger.info("Invalid: %s", record) + + def is_valid(self): + ''' + We don't have remote_account so override base + ''' + return (self.execution_date + and self.transferred_amount and True) or False + +class Statement(models.mem_bank_statement): + + def import_statement(self, record): + self.transactions.append(CSVTransaction(record)) + +def raise_error(message, line): + raise osv.osv.except_osv(_('Import error'), + 'Error in import:%s\n\n%s' % (message, line)) + +class parser(models.parser): + code = 'LLOYDSCORPORATE-CSV' + name = _('Lloyds Corporate CSV Statement IMPORT') + country_code = 'GB' + doc = _('''\ + This format is available through + the web interface. + ''') + + def parse(self, cr, data): + ''' Lloyds corporate CSV parser''' + + data = data.replace('\r','') + csv_header = data.split('\n')[0].replace('"', '').split(',') + header_list = ['Account', 'Date', 'Type', 'Narrative', 'Value Date', 'Payments', 'Receipts', 'Balance'] + result = [] + + #compare header list and process csv if equal + if cmp(csv_header,header_list) != 0: + logger.info("Invalid import Statement:") + logger.info("Expected Header: %s" %(str(header_list))) + logger.info("Header found: %s"%(str(csv_header))) + raise osv.osv.except_osv(_('Import error'), + 'Error in import:%s\n' % (_('Invalid file format'))) + + bankdata = StringIO(data) + lines = list(csv.DictReader(bankdata)) + stmnt = Statement() + # lines as they are imported + if len(lines): + #Store opening balance from first record + line = lines[0] + stmnt.start_balance = line['Balance'] + account_number = re.sub('\D', '', line['Account']) + + #Assuming if payment and receipts are both null then its opening balance + if not (line['Payments'] and line['Receipts']): + lines = lines[1:] + + #Skip records which do not contains transaction type + for line in lines[:-int(len(lines)-map(itemgetter('Type'), lines).index(''))]: + #create Statement lines from csv records + stmnt.import_statement(line) + + #Get statement Closing balance from CSV data list + try: + stmnt.end_balance = lines[map(itemgetter('Narrative'), lines).\ + index('Closing Ledger Balance')]['Balance'] + except ValueError: + raise osv.osv.except_osv(_('Closing Balance'), + _('Statement Closing Balance not found.')) + + + #GB account number format stored in ERP + stmnt.local_account = account_number[:6] +' '+ account_number[6:] + + # Take date of last line of statement + stmnt.date = stmnt.transactions[-1].effective_date + + statement_id = self.get_unique_statement_id( + cr, stmnt.date.strftime('%Yw%W')) + stmnt.id = statement_id + result.append(stmnt) + return result + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_lloyds_corporate/samplestatement.csv b/account_banking_uk_lloyds_corporate/samplestatement.csv new file mode 100644 index 000000000..ce8dc1a56 --- /dev/null +++ b/account_banking_uk_lloyds_corporate/samplestatement.csv @@ -0,0 +1,14 @@ +"Account","Date","Type","Narrative","Value Date","Payments","Receipts","Balance" +"210999-40010000 (GBP)",31MAY13,"","Opening Ledger Balance",,,,30000 +"210999-40010000 (GBP)",31MAY13,"BGC","AXELOR 56465463 BGC +5656546456 30/05","","",20000,50000 +"210999-40010000 (GBP)",31MAY13,"CR","ARGOS +INVOICES PAID","","",10000,60000 +"210999-40010000 (GBP)",31MAY13,"DR","DEBANHAMS +EUROS 307.70","",2000,"",58000 +"210999-40010000 (GBP)",31MAY13,"DR","HOTEL HILTON PARKLANE","",2000,"",56000 +"210999-40010000 (GBP)",31MAY13,"DR","TO 30999999999999 TFR","",6000,"",50000 +"210999-40010000 (GBP)",21JUN13,"","Value of Credits (96)","","",30000, +"210999-40010000 (GBP)",21JUN13,"","Value of Debits (43)","",10000,, +"210999-40010000 (GBP)",21JUN13,"","Closing Ledger Balance","","","",50000 +"210999-40010000 (GBP)",21JUN13,"","Closing Cleared Balance","","","",50000 diff --git a/account_direct_debit/model/account_payment.py b/account_direct_debit/model/account_payment.py index 0f6275f9b..aa69dec7c 100644 --- a/account_direct_debit/model/account_payment.py +++ b/account_direct_debit/model/account_payment.py @@ -153,7 +153,7 @@ class payment_order(osv.osv): move_id = account_move_obj.create(cr, uid, { 'journal_id': order.mode.transfer_journal_id.id, 'name': 'Debit order %s' % line.move_line_id.move_id.name, - 'reference': 'DEB%s' % line.move_line_id.move_id.name, + 'ref': 'DEB%s' % line.move_line_id.move_id.name, }, context=context) # TODO: take multicurrency into account