diff --git a/account_banking_uk_hsbc/__init__.py b/account_banking_uk_hsbc/__init__.py new file mode 100644 index 000000000..b9c3e7a5e --- /dev/null +++ b/account_banking_uk_hsbc/__init__.py @@ -0,0 +1,25 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011 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 account_banking_uk_hsbc +import wizard +import hsbc_mt940 +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/__openerp__.py b/account_banking_uk_hsbc/__openerp__.py new file mode 100644 index 000000000..f1a2fc471 --- /dev/null +++ b/account_banking_uk_hsbc/__openerp__.py @@ -0,0 +1,50 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011 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': 'HSBC Account Banking', + 'version': '0.4', + 'license': 'AGPL-3', + 'author': 'credativ Ltd', + 'website': 'http://www.credativ.co.uk', + 'category': 'Account Banking', + 'depends': ['account_banking'], + 'init_xml': [], + 'update_xml': [ + 'account_banking_uk_hsbc.xml', + 'data/banking_export_hsbc.xml', + 'wizard/export_hsbc_view.xml', + ], + 'demo_xml': [], + 'description': ''' + Module to import HSBC format transation files (S.W.I.F.T MT940) and to export payments for HSBC.net (PAYMUL). + + Currently it is targetting UK market, due to country variances of the MT940 and PAYMUL. + + It is possible to extend this module to work with HSBC.net in other countries and potentially other banks. + + This module adds above import/export filter to the account_banking module. + All business logic is in account_banking module. + + Initial release of this module was co-sponsored by canonical. + ''', + 'active': False, + 'installable': True, +} diff --git a/account_banking_uk_hsbc/account_banking_uk_hsbc.py b/account_banking_uk_hsbc/account_banking_uk_hsbc.py new file mode 100644 index 000000000..77bc7b09b --- /dev/null +++ b/account_banking_uk_hsbc/account_banking_uk_hsbc.py @@ -0,0 +1,65 @@ +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# Copyright (C) 2011 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields +from datetime import date +from tools.translate import _ + +class hsbc_export(osv.osv): + '''HSBC Export''' + _name = 'banking.export.hsbc' + _description = __doc__ + _rec_name = 'execution_date' + + _columns = { + 'payment_order_ids': fields.many2many( + 'payment.order', + 'account_payment_order_hsbc_rel', + 'banking_export_hsbc_id', 'account_order_id', + 'Payment Orders', + readonly=True), + 'identification': + fields.char('Identification', size=15, readonly=True, select=True), + 'execution_date': + fields.date('Execution Date',readonly=True), + 'no_transactions': + fields.integer('Number of Transactions', readonly=True), + 'total_amount': + fields.float('Total Amount', readonly=True), + 'date_generated': + fields.datetime('Generation Date', readonly=True, select=True), + 'file': + fields.binary('HSBC File', readonly=True), + 'state': + fields.selection([ + ('draft', 'Draft'), + ('sent', 'Sent'), + ('done', 'Reconciled'), + ], 'State', readonly=True), + } + + _defaults = { + 'date_generated': lambda *a: date.today().strftime('%Y-%m-%d'), + 'state': lambda *a: 'draft', + } +hsbc_export() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/account_banking_uk_hsbc.xml b/account_banking_uk_hsbc/account_banking_uk_hsbc.xml new file mode 100644 index 000000000..02b382256 --- /dev/null +++ b/account_banking_uk_hsbc/account_banking_uk_hsbc.xml @@ -0,0 +1,85 @@ + + + + + + + + account.banking.export.hsbc.form + banking.export.hsbc + form + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + account.banking.export.hsbc.tree + banking.export.hsbc + tree + + + + + + + + + Generated HSBC files + ir.actions.act_window + banking.export.hsbc + form + tree,form + + + + + + + + +
+
diff --git a/account_banking_uk_hsbc/data/banking_export_hsbc.xml b/account_banking_uk_hsbc/data/banking_export_hsbc.xml new file mode 100644 index 000000000..76a6e3cb5 --- /dev/null +++ b/account_banking_uk_hsbc/data/banking_export_hsbc.xml @@ -0,0 +1,21 @@ + + + + + ACH or EZONE + not used + + + + + Faster Payment + not used + + + + + diff --git a/account_banking_uk_hsbc/hsbc_mt940.py b/account_banking_uk_hsbc/hsbc_mt940.py new file mode 100644 index 000000000..c72c5c493 --- /dev/null +++ b/account_banking_uk_hsbc/hsbc_mt940.py @@ -0,0 +1,161 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011 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 of HSBC data in Swift MT940 format +# + +from account_banking.parsers import models +from account_banking.parsers.convert import str2date +from tools.translate import _ +from mt940_parser import HSBCParser +import re + +bt = models.mem_bank_transaction + +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', + 'effective_date' : 'bookingdate', + 'local_currency' : 'currency', + 'transfer_type' : 'bookingcode', + 'reference' : 'custrefno', + 'message' : 'furtherinfo' + } + + type_map = { + 'TRF': bt.ORDER, + } + + def __init__(self, record, *args, **kwargs): + ''' + Transaction creation + ''' + super(transaction, self).__init__(*args, **kwargs) + for key, value in self.mapping.iteritems(): + if record.has_key(value): + setattr(self, key, record[value]) + + self.transferred_amount = record2float(record, 'amount') + + #print record.get('bookingcode') + if not self.is_valid(): + print "Invalid: %s" % record + def is_valid(self): + ''' + We don't have remote_account so override base + ''' + return (self.execution_date + and self.transferred_amount and True) or False + +class statement(models.mem_bank_statement): + ''' + Bank statement imported data + ''' + + def import_record(self, record): + def _transmission_number(): + self.id = record['transref'] + def _account_number(): + # The wizard doesn't check for sort code + self.local_account = record['sortcode'] + ' ' + record['accnum'].zfill(8) + def _statement_number(): + self.id = '-'.join([self.id, self.local_account, record['statementnr']]) + def _opening_balance(): + self.start_balance = record2float(record,'startingbalance') + self.local_currency = record['currencycode'] + def _closing_balance(): + self.end_balance = record2float(record, 'endingbalance') + self.date = record['bookingdate'] + def _transaction_new(): + self.transactions.append(transaction(record)) + def _transaction_info(): + self.transaction_info(record) + def _not_used(): + print "Didn't use record: %s" % (record,) + + rectypes = { + '20' : _transmission_number, + '25' : _account_number, + '28' : _statement_number, + '28C': _statement_number, + '60F': _opening_balance, + '62F': _closing_balance, + #'64' : _forward_available, + #'62M': _interim_balance, + '61' : _transaction_new, + '86' : _transaction_info, + } + + rectypes.get(record['recordid'], _not_used)() + + def transaction_info(self, record): + ''' + Add extra information to transaction + ''' + # Additional information for previous transaction + if len(self.transactions) < 1: + raise_error('Received additional information for non existent transaction', record) + + transaction = self.transactions[-1] + + transaction.id = ','.join([record[k] for k in ['infoline{0}'.format(i) for i in range(1,5)] if record.has_key(k)]) + +def raise_error(message, line): + raise osv.except_osv(_('Import error'), + 'Error in import:%s\n\n%s' % (message, line)) + +class parser_hsbc_mt940(models.parser): + code = 'HSBC-MT940' + name = _('HSBC Swift MT940 statement export') + country_code = 'GB' + doc = _('''\ + This format is available through + the HSBC web interface. + ''') + + def parse(self, data): + result = [] + parser = HSBCParser() + # Split into statements + statements = [st for st in re.split('[\r\n]*(?=:20:)', data)] + # Split by records + statement_list = [re.split('[\r\n ]*(?=:\d\d[\w]?:)', st) for st in statements] + + for statement_lines in statement_list: + stmnt = statement() + records = [parser.parse_record(record) for record in statement_lines] + [stmnt.import_record(r) for r in records if r is not None] + + + if stmnt.is_valid(): + result.append(stmnt) + else: + print "Invalid Statement:" + print 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 new file mode 100644 index 000000000..d4a6a2ba0 --- /dev/null +++ b/account_banking_uk_hsbc/mt940_parser.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011 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 . +# +############################################################################## + +""" +Parser for HSBC UK MT940 format files +Based on fi_patu's parser +""" +import re +from datetime import datetime + +class HSBCParser(object): + + def __init__( self ): + recparse = dict() + patterns = {'ebcdic': "\w/\?:\(\).,'+{} -"} + + # MT940 header + recparse["20"] = ":(?P20):(?P.{1,16})" + 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})" + + # Transaction + recparse["61"] = """\ +:(?P61):\ +(?P\d{6})(?P\d{4})?\ +(?PR?[CD])\ +(?P[A-Z])?\ +(?P[\d,]{1,15})\ +(?P[A-Z][A-Z0-9]{3})\ +(?P[%(ebcdic)s]{1,16})\ +(?://)\ +(?P[%(ebcdic)s]{1,16})?\ +(?:\n(?P[%(ebcdic)s]))?\ +""" % (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}))?" + + # 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 + """ + for matcher in self.recparse: + matchobj = self.recparse[matcher].match(line) + if matchobj: + break + if not matchobj: + print " **** failed to match line '%s'" % (line) + return + # Strip strings + matchdict = matchobj.groupdict() + + # Remove members set to None + matchdict=dict([(k,v) for k,v in matchdict.iteritems() if v]) + + matchkeys = set(matchdict.keys()) + needstrip = set(["transref", "accnum", "statementnr", "custrefno", + "bankref", "furtherinfo", "infoline1", "infoline2", "infoline3", + "infoline4", "infoline5", "startingbalance", "endingbalance"]) + for field in matchkeys & needstrip: + matchdict[field] = matchdict[field].strip() + + # Convert to float. Comma is decimal separator + needsfloat = set(["startingbalance", "endingbalance", "amount"]) + for field in matchkeys & needsfloat: + matchdict[field] = float(matchdict[field].replace(',','.')) + + # Convert date fields + needdate = set(["prevstmtdate", "valuedate", "bookingdate"]) + for field in matchkeys & needdate: + datestring = matchdict[field] + + post_check = False + if len(datestring) == 4 and field=="bookingdate" and matchdict.has_key("valuedate"): + # Get year from valuedate + datestring = matchdict['valuedate'].strftime('%y') + datestring + post_check = True + try: + matchdict[field] = datetime.strptime(datestring,'%y%m%d') + if post_check and matchdict[field] > matchdict["valuedate"]: + matchdict[field]=matchdict[field].replace(year=matchdict[field].year-1) + except ValueError: + matchdict[field] = None + + return matchdict + + def parse(self, data): + records = [] + # Some records are multiline + for line in data: + if len(line) <= 1: + continue + if line[0] == ':' and len(line) > 1: + records.append(line) + else: + records[-1] = '\n'.join([records[-1], line]) + + output = [] + for rec in records: + output.append(self.parse_record(rec)) + + return output + +def parse_file(filename): + hsbcfile = open(filename, "r") + p = HSBCParser().parse(hsbcfile.readlines()) + +def main(): + """The main function, currently just calls a dummy filename + + :returns: description + """ + parse_file("testfile") + +if __name__ == '__main__': + main() diff --git a/account_banking_uk_hsbc/wizard/__init__.py b/account_banking_uk_hsbc/wizard/__init__.py new file mode 100644 index 000000000..83ee32b16 --- /dev/null +++ b/account_banking_uk_hsbc/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# Copyright (C) 2011 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +import export_hsbc \ No newline at end of file diff --git a/account_banking_uk_hsbc/wizard/export_hsbc.py b/account_banking_uk_hsbc/wizard/export_hsbc.py new file mode 100644 index 000000000..227deea59 --- /dev/null +++ b/account_banking_uk_hsbc/wizard/export_hsbc.py @@ -0,0 +1,341 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# Copyright (C) 2011 credativ Ltd (). +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +import base64 +from datetime import datetime, date, timedelta +from osv import osv, fields +from tools.translate import _ +from decimal import Decimal +import paymul +import string +import random + +def strpdate(arg, format='%Y-%m-%d'): + '''shortcut''' + return datetime.strptime(arg, format).date() + +def strfdate(arg, format='%Y-%m-%d'): + '''shortcut''' + return arg.strftime(format) + +class banking_export_hsbc_wizard(osv.osv_memory): + _name = 'banking.export.hsbc.wizard' + _description = 'HSBC Export' + _columns = { + 'state': fields.selection( + [ + ('create', 'Create'), + ('finish', 'Finish') + ], + 'State', + readonly=True, + ), + 'test': fields.boolean(), + 'reference': fields.char( + 'Reference', size=35, + help=('The bank will use this reference in feedback communication ' + 'to refer to this run. 35 characters are available.' + ), + ), + 'execution_date_create': fields.date( + 'Execution Date', + help=('This is the date the file should be processed by the bank. ' + 'Don\'t choose a date beyond the nearest date in your ' + 'payments. The latest allowed date is 30 days from now.\n' + 'Please keep in mind that banks only execute on working days ' + 'and typically use a delay of two days between execution date ' + 'and effective transfer date.' + ), + ), + 'file_id': fields.many2one( + 'banking.export.hsbc', + 'hsbc File', + readonly=True + ), + 'file': fields.related( + 'file_id', 'file', type='binary', + readonly=True, + string='File', + ), + 'execution_date_finish': fields.related( + 'file_id', 'execution_date', type='date', + readonly=True, + string='Execution Date', + ), + 'total_amount': fields.related( + 'file_id', 'total_amount', + type='float', + string='Total Amount', + readonly=True, + ), + 'no_transactions': fields.integer( + 'Number of Transactions', + readonly=True, + ), + 'payment_order_ids': fields.many2many( + 'payment.order', 'rel_wiz_payorders', 'wizard_id', + 'payment_order_id', 'Payment Orders', + readonly=True, + ), + } + + def create(self, cursor, uid, wizard_data, context=None): + ''' + Retrieve a sane set of default values based on the payment orders + from the context. + ''' + + if not 'execution_date_create' in wizard_data: + po_ids = context.get('active_ids', []) + po_model = self.pool.get('payment.order') + pos = po_model.browse(cursor, uid, po_ids) + + execution_date = date.today() + + for po in pos: + if po.date_prefered == 'fixed' and po.date_planned: + execution_date = strpdate(po.date_planned) + elif po.date_prefered == 'due': + for line in po.line_ids: + if line.move_line_id.date_maturity: + date_maturity = strpdate(line.move_line_id.date_maturity) + if date_maturity < execution_date: + execution_date = date_maturity + + execution_date = max(execution_date, date.today()) + + # The default reference contains a /, which is invalid for PAYMUL + reference = pos[0].reference.replace('/', ' ') + + wizard_data.update({ + 'execution_date_create': strfdate(execution_date), + 'reference': reference, + 'payment_order_ids': [[6, 0, po_ids]], + 'state': 'create', + }) + + return super(banking_export_hsbc_wizard, self).create( + cursor, uid, wizard_data, context) + + def _create_account(self, oe_account): + currency = None # let the receiving bank select the currency from the batch + holder = oe_account.owner_name or oe_account.partner_id.name + + if oe_account.iban: + paymul_account = paymul.IBANAccount( + iban=oe_account.iban, + bic=oe_account.bank.bic, + holder=holder, + currency=currency, + ) + transaction_kwargs = { + 'charges': paymul.CHARGES_EACH_OWN, + } + elif oe_account.country_id.code == 'GB': + split = oe_account.acc_number.split(" ", 2) + if len(split) == 2: + sortcode, accountno = split + else: + raise osv.except_osv( + _('Error'), + "Invalid GB acccount number '%s'" % oe_account.acc_number) + paymul_account = paymul.UKAccount( + number=accountno, + sortcode=sortcode, + holder=holder, + currency=currency, + ) + transaction_kwargs = { + 'charges': paymul.CHARGES_PAYEE, + } + else: + raise osv.except_osv( + _('Error'), + _('%s: only UK accounts and IBAN are supported') % (holder) + ) + + return paymul_account, transaction_kwargs + + def _create_transaction(self, line): + # Check on missing partner of bank account (this can happen!) + if not line.bank_id or not line.bank_id.partner_id: + raise osv.except_osv( + _('Error'), + _('There is insufficient information.\r\n' + 'Both destination address and account ' + 'number must be provided' + ) + ) + + dest_account, transaction_kwargs = self._create_account(line.bank_id) + + means = {'ACH or EZONE': paymul.MEANS_ACH_OR_EZONE, + 'Faster Payment': paymul.MEANS_FASTER_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) + + try: + return paymul.Transaction( + amount=Decimal(str(line.amount_currency)), + currency=line.currency.name, + account=dest_account, + means=means, + name_address=line.info_partner, + customer_reference=line.name, + payment_reference=line.name, + **transaction_kwargs + ) + except ValueError as exc: + raise osv.except_osv( + _('Error'), + _('Transaction invalid: ') + str(exc) + ) + + def wizard_export(self, cursor, uid, wizard_data_ids, context): + ''' + Wizard to actually create the HSBC file + ''' + + wizard_data = self.browse(cursor, uid, wizard_data_ids, context)[0] + result_model = self.pool.get('banking.export.hsbc') + payment_orders = wizard_data.payment_order_ids + + + try: + src_account = self._create_account( + payment_orders[0].mode.bank_id, + )[0] + except ValueError as exc: + raise osv.except_osv( + _('Error'), + _('Source account invalid: ') + str(exc) + ) + + if not isinstance(src_account, paymul.UKAccount): + raise osv.except_osv( + _('Error'), + _("Your company's bank account has to have a valid UK " + "account number (not IBAN)" + str(type(src_account))) + ) + + transactions = [] + for po in payment_orders: + transactions += [self._create_transaction(l) for l in po.line_ids] + + try: + batch = paymul.Batch( + exec_date=strpdate(wizard_data.execution_date_create), + reference=wizard_data.reference, + debit_account=src_account, + name_address=payment_orders[0].line_ids[0].info_owner, + ) + batch.transactions = transactions + except ValueError as exc: + raise osv.except_osv( + _('Error'), + _('Batch invalid: ') + str(exc) + ) + + # Generate random identifier until an unused one is found + while True: + ref = ''.join(random.choice(string.ascii_uppercase + string.digits) + for x in range(15)) + + ids = result_model.search(cursor, uid, [ + ('identification', '=', ref) + ]) + + if not ids: + break + + message = paymul.Message(reference=ref) + message.batches.append(batch) + interchange = paymul.Interchange(client_id='CLIENTID', + reference=ref, + message=message) + + export_result = { + 'identification': interchange.reference, + 'execution_date': batch.exec_date, + 'total_amount': batch.amount(), + 'no_transactions': len(batch.transactions), + 'file': base64.encodestring(str(interchange)), + 'payment_order_ids': [ + [6, 0, [po.id for po in payment_orders]] + ], + } + file_id = result_model.create(cursor, uid, export_result, context) + + self.write(cursor, uid, [wizard_data_ids[0]], { + 'file_id': file_id, + 'no_transactions' : len(batch.transactions), + 'state': 'finish', + }, context) + + return { + 'name': _('HSBC Export'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': self._name, + 'domain': [], + 'context': dict(context, active_ids=wizard_data_ids), + 'type': 'ir.actions.act_window', + 'target': 'new', + 'res_id': wizard_data_ids[0] or False, + } + + def wizard_cancel(self, cursor, uid, ids, context): + ''' + Cancel the export: just drop the file + ''' + + wizard_data = self.browse(cursor, uid, ids, context)[0] + result_model = self.pool.get('banking.export.hsbc') + + try: + result_model.unlink(cursor, uid, wizard_data.file_id.id) + except AttributeError: + # file_id missing, wizard storage gone, server was restarted + pass + + return {'type': 'ir.actions.act_window_close'} + + def wizard_save(self, cursor, uid, ids, context): + ''' + Save the export: mark all payments in the file as 'sent' + ''' + + wizard_data = self.browse(cursor, uid, ids, context)[0] + result_model = self.pool.get('banking.export.hsbc') + po_model = self.pool.get('payment.order') + + result_model.write(cursor, uid, [wizard_data.file_id.id], + {'state':'sent'}) + + po_ids = [po.id for po in wizard_data.payment_order_ids] + po_model.action_sent(cursor, uid, po_ids) + + return {'type': 'ir.actions.act_window_close'} + +banking_export_hsbc_wizard() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking_uk_hsbc/wizard/export_hsbc_view.xml b/account_banking_uk_hsbc/wizard/export_hsbc_view.xml new file mode 100644 index 000000000..617080c61 --- /dev/null +++ b/account_banking_uk_hsbc/wizard/export_hsbc_view.xml @@ -0,0 +1,37 @@ + + + + + banking.export.hsbc.wizard.view + banking.export.hsbc.wizard + form + +
+ + + + + + + + + +