Initial adjustments for 8.0 repository

This commit is contained in:
Pedro M. Baeza
2014-09-10 12:19:20 +02:00
parent 54523f3bb0
commit a2e807668e
343 changed files with 37 additions and 34 deletions

View File

@@ -1,24 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import bank_import
from . import banking_transaction_wizard
from . import link_partner

View File

@@ -1,451 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# Many thanks to our contributors
#
# Kaspars Vilkens (KNdati): lenghty discussions, bugreports and bugfixes
# Stefan Rijnhart (Therp): bugreport and bugfix
#
'''
This module contains the business logic of the wizard account_banking_import.
The parsing is done in the parser modules. Every parser module is required to
use parser.models as a mean of communication with the business logic.
'''
import base64
import datetime
from openerp.osv import orm, fields
from openerp.tools.translate import _
from openerp.addons.account_banking.parsers import models
from openerp.addons.account_banking.parsers import convert
from openerp.addons.account_banking.struct import struct
from openerp.addons.account_banking.wizard import banktools
from openerp.addons.decimal_precision import decimal_precision as dp
bt = models.mem_bank_transaction
# This variable is used to match supplier invoices with an invoice date after
# the real payment date. This can occur with online transactions (web shops).
payment_window = datetime.timedelta(days=10)
def parser_types(*args, **kwargs):
'''Delay evaluation of parser types until start of wizard, to allow
depending modules to initialize and add their parsers to the list
'''
return models.parser_type.get_parser_types()
class banking_import_line(orm.TransientModel):
_name = 'banking.import.line'
_description = 'Bank import lines'
_columns = {
'name': fields.char('Name', size=64),
'date': fields.date('Date', readonly=True),
'amount': fields.float(
'Amount',
digits_compute=dp.get_precision('Account'),
),
'statement_line_id': fields.many2one(
'account.bank.statement.line',
'Resulting statement line', readonly=True),
'type': fields.selection([
('supplier', 'Supplier'),
('customer', 'Customer'),
('general', 'General')
], 'Type', required=True),
'partner_id': fields.many2one('res.partner', 'Partner'),
'statement_id': fields.many2one(
'account.bank.statement',
'Statement',
select=True,
required=True,
ondelete='cascade',
),
'ref': fields.char('Reference', size=32),
'note': fields.text('Notes'),
'period_id': fields.many2one('account.period', 'Period'),
'currency': fields.many2one('res.currency', 'Currency'),
'banking_import_id': fields.many2one(
'account.banking.bank.import', 'Bank import',
readonly=True, ondelete='cascade'),
'reconcile_id': fields.many2one(
'account.move.reconcile', 'Reconciliaton'),
'account_id': fields.many2one('account.account', 'Account'),
'invoice_ids': fields.many2many(
'account.invoice', 'banking_import_line_invoice_rel',
'line_id', 'invoice_id'),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
'transaction_type': fields.selection(
[
# TODO: payment terminal etc...
('invoice', 'Invoice payment'),
('storno', 'Canceled debit order'),
('bank_costs', 'Bank costs'),
('unknown', 'Unknown'),
],
'Transaction type',
),
'duplicate': fields.boolean('Duplicate'),
}
class banking_import(orm.TransientModel):
_name = 'account.banking.bank.import'
def import_statements_file(self, cr, uid, ids, context):
'''
Import bank statements / bank transactions file.
This method is a wrapper for the business logic on the transaction.
The parser modules represent the decoding logic.
'''
banking_import = self.browse(cr, uid, ids, context)[0]
statements_file = banking_import.file
data = base64.decodestring(statements_file)
user_obj = self.pool.get('res.user')
statement_obj = self.pool.get('account.bank.statement')
statement_file_obj = self.pool.get('account.banking.imported.file')
import_transaction_obj = self.pool.get('banking.import.transaction')
period_obj = self.pool.get('account.period')
# get the parser to parse the file
parser_code = banking_import.parser
parser = models.create_parser(parser_code)
if not parser:
raise orm.except_orm(
_('ERROR!'),
_('Unable to import parser %(parser)s. Parser class not '
'found.') %
{'parser': parser_code}
)
# Get the company
company = (banking_import.company or
user_obj.browse(cr, uid, uid, context).company_id)
# Parse the file
statements = parser.parse(cr, data)
if any([x for x in statements if not x.is_valid()]):
raise orm.except_orm(
_('ERROR!'),
_('The imported statements appear to be invalid! Check your '
'file.')
)
# Create the file now, as the statements need to be linked to it
import_id = statement_file_obj.create(cr, uid, dict(
company_id=company.id,
file=statements_file,
file_name=banking_import.file_name,
state='unfinished',
format=parser.name,
))
bank_country_code = False
if hasattr(parser, 'country_code'):
bank_country_code = parser.country_code
# Results
results = struct(
stat_loaded_cnt=0,
trans_loaded_cnt=0,
stat_skipped_cnt=0,
trans_skipped_cnt=0,
trans_matched_cnt=0,
bank_costs_invoice_cnt=0,
error_cnt=0,
log=[],
)
# Caching
error_accounts = {}
info = {}
imported_statement_ids = []
transaction_ids = []
for statement in statements:
if statement.local_account in error_accounts:
# Don't repeat messages
results.stat_skipped_cnt += 1
results.trans_skipped_cnt += len(statement.transactions)
continue
# Create fallback currency code
currency_code = (
statement.local_currency or company.currency_id.name
)
# Check cache for account info/currency
if statement.local_account in info and \
currency_code in info[statement.local_account]:
account_info = info[statement.local_account][currency_code]
else:
# Pull account info/currency
account_info = banktools.get_company_bank_account(
self.pool, cr, uid, statement.local_account,
statement.local_currency, company, results.log
)
if not account_info:
results.log.append(
_('Statements found for unknown account '
'%(bank_account)s') % {
'bank_account': statement.local_account
}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
continue
if 'journal_id' not in account_info.keys():
results.log.append(
_('Statements found for account %(bank_account)s, '
'but no default journal was defined.'
) % {'bank_account': statement.local_account}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
continue
# Get required currency code
currency_code = account_info.currency_id.name
# Cache results
if statement.local_account not in info:
info[statement.local_account] = {
currency_code: account_info
}
else:
info[statement.local_account][currency_code] = account_info
# Final check: no coercion of currencies!
if statement.local_currency \
and account_info.currency_id.name != statement.local_currency:
# TODO: convert currencies?
results.log.append(
_('Statement %(statement_id)s for account %(bank_account)s'
' uses different currency than the defined bank journal.'
) % {
'bank_account': statement.local_account,
'statement_id': statement.id
}
)
error_accounts[statement.local_account] = True
results.error_cnt += 1
continue
# Check existence of previous statement
# Less well defined formats can resort to a
# dynamically generated statement identification
# (e.g. a datetime string of the moment of import)
# and have potential duplicates flagged by the
# matching procedure
statement_ids = statement_obj.search(cr, uid, [
('name', '=', statement.id),
('date', '=', convert.date2str(statement.date)),
])
if statement_ids:
results.log.append(
_('Statement %(id)s known - skipped') % {
'id': statement.id
}
)
continue
# Get the period for the statement (as bank statement object
# checks this)
period_ids = period_obj.search(
cr, uid, [
('company_id', '=', company.id),
('date_start', '<=', statement.date),
('date_stop', '>=', statement.date),
('special', '=', False),
], context=context)
if not period_ids:
results.log.append(
_('No period found covering statement date %(date)s, '
'statement %(id)s skipped') % {
'date': statement.date,
'id': statement.id,
}
)
continue
# Create the bank statement record
statement_id = statement_obj.create(cr, uid, dict(
name=statement.id,
journal_id=account_info.journal_id.id,
date=convert.date2str(statement.date),
balance_start=statement.start_balance,
balance_end_real=statement.end_balance,
balance_end=statement.end_balance,
state='draft',
user_id=uid,
banking_id=import_id,
company_id=company.id,
period_id=period_ids[0],
))
imported_statement_ids.append(statement_id)
subno = 0
for transaction in statement.transactions:
subno += 1
if not transaction.id:
transaction.id = str(subno)
values = {}
for attr in transaction.__slots__ + ['type']:
if attr in import_transaction_obj.column_map:
values[import_transaction_obj.column_map[attr]] = \
eval('transaction.%s' % attr)
elif attr in import_transaction_obj._columns:
values[attr] = eval('transaction.%s' % attr)
values['statement_id'] = statement_id
values['bank_country_code'] = bank_country_code
values['local_account'] = statement.local_account
values['local_currency'] = statement.local_currency
transaction_id = import_transaction_obj.create(
cr, uid, values, context=context)
transaction_ids.append(transaction_id)
results.stat_loaded_cnt += 1
import_transaction_obj.match(
cr, uid, transaction_ids, results=results, context=context
)
# recompute statement end_balance for validation
statement_obj.button_dummy(
cr, uid, imported_statement_ids, context=context)
report = [
'%s: %s' % (_('Total number of statements'),
results.stat_skipped_cnt + results.stat_loaded_cnt),
'%s: %s' % (_('Total number of transactions'),
results.trans_skipped_cnt + results.trans_loaded_cnt),
'%s: %s' % (_('Number of errors found'),
results.error_cnt),
'%s: %s' % (_('Number of statements skipped due to errors'),
results.stat_skipped_cnt),
'%s: %s' % (_('Number of transactions skipped due to errors'),
results.trans_skipped_cnt),
'%s: %s' % (_('Number of statements loaded'),
results.stat_loaded_cnt),
'%s: %s' % (_('Number of transactions loaded'),
results.trans_loaded_cnt),
'%s: %s' % (_('Number of transactions matched'),
results.trans_matched_cnt),
'%s: %s' % (_('Number of bank costs invoices created'),
results.bank_costs_invoice_cnt),
'',
'%s:' % (_('Error report')),
'',
]
text_log = '\n'.join(report + results.log)
state = results.error_cnt and 'error' or 'ready'
statement_file_obj.write(cr, uid, import_id, dict(
state=state,
log=text_log,
), context)
if not imported_statement_ids or not results.trans_loaded_cnt:
# file state can be 'ready' while import state is 'error'
state = 'error'
self.write(cr, uid, [ids[0]], dict(
import_id=import_id,
log=text_log,
state=state,
statement_ids=[(6, 0, imported_statement_ids)],
), context)
return {
'name': (state == 'ready' and _('Review Bank Statements') or
_('Error')),
'view_type': 'form',
'view_mode': 'form',
'view_id': False,
'res_model': self._name,
'domain': [],
'context': dict(context, active_ids=ids),
'type': 'ir.actions.act_window',
'target': 'new',
'res_id': ids[0] or False,
}
_columns = {
'company': fields.many2one(
'res.company', 'Company', required=True,
states={
'ready': [('readonly', True)],
'error': [('readonly', True)],
},
),
'file_name': fields.char('File name', size=256),
'file': fields.binary(
'Statements File',
required=True,
help=('The Transactions File to import. Please note that while it '
'is perfectly safe to reload the same file multiple times '
'or to load in timeframe overlapping statements files, '
'there are formats that may introduce different '
'sequencing, which may create double entries.\n\n'
'To stay on the safe side, always load bank statements '
'files using the same format.'),
states={
'ready': [('readonly', True)],
'error': [('readonly', True)],
},
),
'parser': fields.selection(
parser_types, 'File Format', required=True,
states={
'ready': [('readonly', True)],
'error': [('readonly', True)],
},
),
'log': fields.text('Log', readonly=True),
'state': fields.selection(
[('init', 'init'),
('ready', 'ready'),
('error', 'error')
],
'State', readonly=True),
'import_id': fields.many2one(
'account.banking.imported.file', 'Import File'),
'statement_ids': fields.many2many(
'account.bank.statement', 'rel_wiz_statements', 'wizard_id',
'statement_id', 'Imported Bank Statements'),
'line_ids': fields.one2many(
'banking.import.line', 'banking_import_id', 'Transactions',
),
}
def _default_parser_type(self, cr, uid, context=None):
types = models.parser_type.get_parser_types()
return types and types[0][0] or False
_defaults = {
'state': 'init',
'company': lambda s, cr, uid, c:
s.pool.get('res.company')._company_default_get(
cr, uid, 'bank.import.transaction', context=c),
'parser': _default_parser_type,
}

View File

@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_banking_import" model="ir.ui.view">
<field name="name">account.banking.bank.import</field>
<field name="model">account.banking.bank.import</field>
<field name="arch" type="xml">
<form string="Import Bank Transactions File" version="7.0">
<group colspan="4" states="init,ready,error">
<separator colspan="4" string="Select the processing details:"/>
<field name="company" colspan="1"/>
<field name="file" filename="file_name"/>
<field name="file_name" invisible="1"/>
<newline />
<field name="parser"/>
<field name="state" invisible="1"/>
</group>
<notebook colspan="4">
<page attrs="{'invisible': [('state', '!=', 'review')]}" string="Transactions">
<field name="line_ids" colspan="4" nolabel="1">
<tree string="Transaction" colors="red:duplicate;blue:reconcile_id">
<field name="date"/>
<field name="amount"/>
<field name="ref"/>
<field name="partner_bank_id"/>
<field name="partner_id"/>
<field name="account_id"/>
<field name="reconcile_id"/>
<field name="duplicate"/>
</tree>
</field>
</page>
<page attrs="{'invisible': [('state', '=', 'init')]}" string="Log">
<field name="log" colspan="4" nolabel="1" width="500"/>
</page>
<page attrs="{'invisible': [('state', '!=', 'ready')]}" string="Statements">
<field name="statement_ids" colspan="4" nolabel="1"
attrs="{'invisible': [('state', '!=', 'ready')]}" />
</page>
</notebook>
<footer>
<div attrs="{'invisible': [('state', '!=', 'init')]}">
<button string="Import" class="oe_highlight"
states="init" name="import_statements_file"
type="object"/>
or
<button class="oe_link" special="cancel"
states="init" string="Cancel"/>
</div>
<button icon="gtk-close"
special="cancel"
string="Close"
states="ready,error"/>
<button icon="gtk-close"
name="cancel_statement_lines"
type="object"
string="Cancel"
states="review"/>
<button icon="gtk-ok"
name="create_statement_lines"
type="object"
string="Confirm"
states="review"/>
</footer>
</form>
</field>
</record>
<record id="wizard_account_banking_import_file" model="ir.actions.act_window">
<field name="name">Import Bank Statements File</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.banking.bank.import</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_banking_import"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@@ -1,453 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
# (C) 2011 Smile (<http://smile.fr>).
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
from openerp.tools.translate import _
"""
The banking transaction wizard is linked to a button in the statement line
tree view. It allows the user to undo the duplicate flag, select between
multiple matches or select a manual match.
"""
class banking_transaction_wizard(orm.TransientModel):
_name = 'banking.transaction.wizard'
_description = 'Match transaction'
def create(self, cr, uid, vals, context=None):
"""
Make sure that the statement line has an import transaction
"""
res = super(banking_transaction_wizard, self).create(
cr, uid, vals, context=context)
if res and vals.get('statement_line_id'):
line_pool = self.pool.get('account.bank.statement.line')
line_pool.create_instant_transaction(
cr, uid, vals['statement_line_id'], context=context)
return res
def create_act_window(self, cr, uid, ids, nodestroy=True, context=None):
"""
Return a popup window for this model
"""
if isinstance(ids, (int, long)):
ids = [ids]
return {
'name': self._description,
'view_type': 'form',
'view_mode': 'form',
'res_model': self._name,
'domain': [],
'context': context,
'type': 'ir.actions.act_window',
'target': 'new',
'res_id': ids[0],
'nodestroy': nodestroy,
}
def trigger_match(self, cr, uid, ids, context=None):
"""
Call the automatic matching routine for one or
more bank transactions
"""
if isinstance(ids, (int, long)):
ids = [ids]
import_transaction_obj = self.pool.get('banking.import.transaction')
trans_id = self.read(
cr, uid, ids[0], ['import_transaction_id'],
context=context)['import_transaction_id'][0] # many2one tuple
import_transaction_obj.match(cr, uid, [trans_id], context=context)
return self.create_act_window(cr, uid, ids, context=None)
def write(self, cr, uid, ids, vals, context=None):
"""
Implement a trigger to retrieve the corresponding move line
when the invoice_id changes
"""
statement_line_obj = self.pool.get('account.bank.statement.line')
transaction_obj = self.pool.get('banking.import.transaction')
if not vals or not ids:
return True
wiz = self.browse(cr, uid, ids[0], context=context)
# The following fields get never written
# they are just triggers for manual matching
# which populates regular fields on the transaction
manual_invoice_ids = vals.pop('manual_invoice_ids', [])
manual_move_line_ids = vals.pop('manual_move_line_ids', [])
res = super(banking_transaction_wizard, self).write(
cr, uid, ids, vals, context=context)
wiz.refresh()
# Process the logic of the written values
# An invoice is selected from multiple candidates
if vals and 'invoice_id' in vals:
if (wiz.import_transaction_id.match_type == 'invoice' and
wiz.import_transaction_id.invoice_id):
found = False
# the current value might apply
if (wiz.move_line_id and wiz.move_line_id.invoice and
wiz.move_line_id.invoice == wiz.invoice_id):
found = True
else:
# Otherwise, retrieve the move line for this invoice
# Given the arity of the relation, there is are always
# multiple possibilities but the move lines here are
# prefiltered for having account_id.type payable/receivable
# and the regular invoice workflow should only come up with
# one of those only.
for move_line in wiz.import_transaction_id.move_line_ids:
if (move_line.invoice ==
wiz.import_transaction_id.invoice_id):
transaction_obj.write(
cr, uid, wiz.import_transaction_id.id,
{'move_line_id': move_line.id, },
context=context
)
statement_line_obj.write(
cr, uid,
wiz.import_transaction_id.statement_line_id.id,
{
'partner_id': (
move_line.partner_id.id or False),
'account_id': move_line.account_id.id,
}, context=context)
found = True
break
# Cannot match the invoice
if not found:
orm.except_orm(
_("No entry found for the selected invoice"),
_("No entry found for the selected invoice. " +
"Try manual reconciliation."))
if manual_move_line_ids or manual_invoice_ids:
move_line_obj = self.pool.get('account.move.line')
invoice_obj = self.pool.get('account.invoice')
statement_line_obj = self.pool.get('account.bank.statement.line')
# Rewrite *2many directive notation
if manual_invoice_ids:
manual_invoice_ids = (
[i[1] for i in manual_invoice_ids if i[0] == 4] +
[j for i in manual_invoice_ids if i[0] == 6 for j in i[2]])
if manual_move_line_ids:
manual_move_line_ids = (
[i[1] for i in manual_move_line_ids if i[0] == 4] +
[j for i in manual_move_line_ids
if i[0] == 6 for j in i[2]])
for wiz in self.browse(cr, uid, ids, context=context):
# write can be called multiple times for the same values
# that doesn't hurt above, but it does here
if wiz.match_type and (
len(manual_move_line_ids) > 1 or
len(manual_invoice_ids) > 1):
continue
todo = []
for invoice in invoice_obj.browse(
cr, uid, manual_invoice_ids, context=context):
found_move_line = False
if invoice.move_id:
for line in invoice.move_id.line_id:
if line.account_id.type in ('receivable',
'payable'):
todo.append((invoice.id, line.id))
found_move_line = True
break
if not found_move_line:
raise orm.except_orm(
_("Cannot select for reconcilion"),
_("No entry found for the selected invoice. "))
for move_line_id in manual_move_line_ids:
todo_entry = [False, move_line_id]
move_line = move_line_obj.read(
cr,
uid,
move_line_id,
['invoice'],
context=context
)
if move_line['invoice']:
todo_entry[0] = move_line['invoice'][0]
todo.append(todo_entry)
while todo:
todo_entry = todo.pop()
move_line = move_line_obj.browse(
cr, uid, todo_entry[1], context)
transaction_id = wiz.import_transaction_id.id
statement_line_id = wiz.statement_line_id.id
if len(todo) > 0:
statement_line_id = wiz.statement_line_id.split_off(
move_line.debit or -move_line.credit)[0]
transaction_id = statement_line_obj.browse(
cr,
uid,
statement_line_id,
context=context
).import_transaction_id.id
vals = {
'move_line_id': todo_entry[1],
'move_line_ids': [(6, 0, [todo_entry[1]])],
'invoice_id': todo_entry[0],
'invoice_ids': [
(6, 0, [todo_entry[0]] if todo_entry[0] else [])
],
'match_type': 'manual',
}
transaction_obj.clear_and_write(
cr, uid, transaction_id, vals, context=context)
st_line_vals = {
'account_id': move_line_obj.read(
cr, uid, todo_entry[1],
['account_id'], context=context)['account_id'][0],
}
if todo_entry[0]:
st_line_vals['partner_id'] = invoice_obj.browse(
cr, uid, todo_entry[0], context=context
).partner_id.commercial_partner_id.id
statement_line_obj.write(
cr, uid, statement_line_id,
st_line_vals, context=context)
return res
def trigger_write(self, cr, uid, ids, context=None):
"""
Just a button that triggers a write.
"""
return self.create_act_window(cr, uid, ids, context=None)
def disable_match(self, cr, uid, ids, context=None):
"""
Clear manual and automatic match information
"""
settings_pool = self.pool.get('account.banking.account.settings')
statement_pool = self.pool.get('account.bank.statement.line')
if isinstance(ids, (int, long)):
ids = [ids]
for wiz in self.browse(cr, uid, ids, context=context):
# Get the bank account setting record, to reset the account
account_id = False
journal_id = wiz.statement_line_id.statement_id.journal_id.id
setting_ids = settings_pool.find(
cr, uid, journal_id, context=context
)
# Restore partner id from the bank account or else reset
partner_id = False
if (wiz.statement_line_id.partner_bank_id and
wiz.statement_line_id.partner_bank_id.partner_id):
partner_id = (
wiz.statement_line_id.partner_bank_id.partner_id.id
)
wiz.write({'partner_id': partner_id})
bank_partner = False
if partner_id:
bank_partner = wiz.statement_line_id.partner_bank_id.partner_id
if wiz.amount < 0:
if bank_partner:
account_id = bank_partner.\
def_journal_account_bank_decr()[bank_partner.id]
elif setting_ids:
account_id = settings_pool.browse(
cr, uid, setting_ids[0],
context=context).default_credit_account_id.id
else:
if bank_partner:
account_id = bank_partner.\
def_journal_account_bank_incr()[bank_partner.id]
elif setting_ids:
account_id = settings_pool.browse(
cr, uid, setting_ids[0],
context=context).default_debit_account_id.id
if account_id:
wiz.statement_line_id.write({'account_id': account_id})
if wiz.statement_line_id:
# delete splits causing an unsplit if this is a split
# transaction
statement_pool.unlink(
cr,
uid,
statement_pool.search(
cr, uid,
[('parent_id', '=', wiz.statement_line_id.id)],
context=context
),
context=context
)
if wiz.import_transaction_id:
wiz.import_transaction_id.clear_and_write()
return self.create_act_window(cr, uid, ids, context=None)
def reverse_duplicate(self, cr, uid, ids, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
transaction_obj = self.pool.get('banking.import.transaction')
for wiz in self.read(
cr, uid, ids, ['duplicate', 'import_transaction_id'],
context=context):
transaction_obj.write(
cr, uid, wiz['import_transaction_id'][0],
{'duplicate': not wiz['duplicate']}, context=context)
return self.create_act_window(cr, uid, ids, context=None)
def button_done(self, cr, uid, ids, context=None):
return {'type': 'ir.actions.act_window_close'}
_columns = {
'name': fields.char('Name', size=64),
'statement_line_id': fields.many2one(
'account.bank.statement.line', 'Statement line',
),
'amount': fields.related(
'statement_line_id', 'amount', type='float',
string="Amount", readonly=True),
'date': fields.related(
'statement_line_id', 'date', type='date',
string="Date", readonly=True),
'ref': fields.related(
'statement_line_id', 'ref', type='char', size=32,
string="Reference", readonly=True),
'message': fields.related(
'statement_line_id', 'import_transaction_id', 'message',
type='char', size=1024,
string="Message", readonly=True),
'partner_id': fields.related(
'statement_line_id', 'partner_id',
type='many2one', relation='res.partner',
string="Partner", readonly=True),
'statement_line_parent_id': fields.related(
'statement_line_id', 'parent_id', type='many2one',
relation='account.bank.statement.line', readonly=True),
'import_transaction_id': fields.related(
'statement_line_id', 'import_transaction_id',
string="Import transaction",
type='many2one', relation='banking.import.transaction'),
'residual': fields.related(
'import_transaction_id', 'residual', type='float',
string='Residual', readonly=True),
'writeoff_account_id': fields.related(
'import_transaction_id', 'writeoff_account_id',
type='many2one', relation='account.account',
string='Write-off account'),
'invoice_ids': fields.related(
'import_transaction_id', 'invoice_ids', string="Matching invoices",
type='many2many', relation='account.invoice'),
'invoice_id': fields.related(
'import_transaction_id',
'invoice_id',
string="Invoice to reconcile",
type='many2one',
relation='account.invoice',
),
'move_line_ids': fields.related(
'import_transaction_id', 'move_line_ids', string="Entry lines",
type='many2many', relation='account.move.line'),
'move_line_id': fields.related(
'import_transaction_id', 'move_line_id', string="Entry line",
type='many2one', relation='account.move.line'),
'duplicate': fields.related(
'import_transaction_id',
'duplicate',
string='Flagged as duplicate',
type='boolean',
),
'match_multi': fields.related(
'import_transaction_id', 'match_multi',
type="boolean", string='Multiple matches'),
'match_type': fields.related(
'import_transaction_id',
'match_type',
type='selection',
selection=[
('move', 'Move'),
('invoice', 'Invoice'),
('payment', 'Payment line'),
('payment_order', 'Payment order'),
('storno', 'Storno'),
('manual', 'Manual'),
('payment_manual', 'Payment line (manual)'),
('payment_order_manual', 'Payment order (manual)'),
],
string='Match type',
readonly=True,
),
'manual_invoice_ids': fields.many2many(
'account.invoice',
'banking_transaction_wizard_account_invoice_rel',
'wizard_id', 'invoice_id', string='Match one or more invoices',
domain=[('reconciled', '=', False)]),
'manual_move_line_ids': fields.many2many(
'account.move.line',
'banking_transaction_wizard_account_move_line_rel',
'wizard_id', 'move_line_id', string='Or match one or more entries',
domain=[('account_id.reconcile', '=', True),
('reconcile_id', '=', False)]),
'payment_option': fields.related(
'import_transaction_id',
'payment_option',
string='Payment Difference',
type='selection',
required=True,
selection=[
('without_writeoff', 'Keep Open'),
('with_writeoff', 'Reconcile Payment Balance')
],
),
'writeoff_analytic_id': fields.related(
'import_transaction_id', 'writeoff_analytic_id',
type='many2one', relation='account.analytic.account',
string='Write-off analytic account'),
'analytic_account_id': fields.related(
'statement_line_id', 'analytic_account_id',
type='many2one', relation='account.analytic.account',
string="Analytic Account"),
'move_currency_amount': fields.related(
'import_transaction_id',
'move_currency_amount',
type='float',
string='Match Currency Amount',
readonly=True,
),
}

View File

@@ -1,136 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="transaction_wizard_first">
<field name="name">transaction.wizard.first</field>
<field name="model">banking.transaction.wizard</field>
<field name="arch" type="xml">
<form string="Match transaction" version="7.0">
<!-- fields used for form logic -->
<field name="statement_line_parent_id" invisible="True"/>
<field name="invoice_ids" invisible="True"/>
<field name="move_line_ids" invisible="True"/>
<field name="match_multi" invisible="True"/>
<field name="duplicate" invisible="True"/>
<group colspan="2" col="2">
<group colspan="2" col="4">
<separator string="Transaction data" colspan="4"/>
<field name="partner_id"/>
<field name="date"/>
<field name="amount"/>
<field name="ref"/>
<field name="message" colspan="4"/>
</group>
<!-- (semi-) automatic matching and selection -->
<group colspan="2" col="4">
<separator string="Current match" colspan="4"/>
<field name="match_type"/>
<newline />
<field name="move_currency_amount" />
<newline />
<field name="residual"/>
<group attrs="{'invisible': [('match_multi', '=', False)]}" colspan="4" col="2">
<separator string="Multiple matches" colspan="2"/>
<label colspan="2" string="Multiple matches were found for this bank transfer. You must pick one of the matches or select a match manually below." />
</group>
</group>
</group>
<group>
<newline/>
<!-- show if we have an invoice type match (but the user may need to select from multiple options)
or whenever there is an invoice_id (e.g. in case of a manual match)
-->
<field name='invoice_id'
attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'invoice'),('invoice_id', '=', False)]}" colspan="2"
domain="[('id', 'in', invoice_ids[0][2])]"
/>
<!-- show if we have a move type match or a manual match without an invoice_id
-->
<field name='move_line_id'
attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'move'),('invoice_id', '=', False)]}" colspan="2"
domain="[('id', 'in', move_line_ids[0][2])]"
/>
<newline/>
<field colspan="2" name='analytic_account_id' />
<button colspan="1"
name="trigger_write"
type="object"
attrs="{'invisible': [('match_multi', '=', False)]}"
string="Select"/>
<newline/>
<!-- residual and write off -->
</group>
<notebook>
<!-- Duplicate flagging -->
<page string="Duplicate" attrs="{'invisible': [('duplicate', '=', False)]}">
<group colspan="2" col="2">
<label colspan="2" string="This bank transfer was marked as a duplicate. You can either confirm that this is not the case, or remove the bank transfer from the system."/>
<newline/>
<button colspan="1"
name="reverse_duplicate"
type="object"
string="Remove duplicate flag"/>
</group>
</page>
<!-- Redo automatic match -->
<page string="Match again">
<label string="You can let the system try to match this bank statement line again after you have made any changes in the database (for instance, add an invoice or a bank account)." colspan="2"/>
<newline/>
<button colspan="1"
name="trigger_match"
type="object"
string="Match again"/>
</page>
<!-- Manual selection -->
<page string="Manual match">
<separator string="Match one or more invoices" colspan="4"/>
<field name="manual_invoice_ids" colspan="4"
context="{'search_default_partner_id': partner_id}"
/>
<separator string="Or match one or more entries" colspan="4"/>
<field name="manual_move_line_ids" colspan="4"
context="{'search_default_partner_id': partner_id}"
/>
<button name="trigger_write"
type="object"
string="Match" />
</page>
<page string="Write-Off" attrs="{'invisible': [('match_type', '=', False)]}">
<group colspan="2" col="2">
<label string="Choose what you want to do with the eventual difference between the paid amount and the sum of allocated amounts. You can either choose to keep open this difference on the partner's account, or reconcile it with the payment." colspan="2"/>
<field name="payment_option" />
<field name="writeoff_account_id" attrs="{'required':[('payment_option','=','with_writeoff')],'invisible':[('payment_option','=','without_writeoff')]}" />
<field name="writeoff_analytic_id"
groups="analytic.group_analytic_accounting"
attrs="{'invisible':[('payment_option','=','without_writeoff')]}" />
<button colspan="1"
name="trigger_write"
type="object"
string="Set write-off account"/>
</group>
</page>
<page string="Disable reconciliation" attrs="{'invisible': [('match_type', '==', False)]}">
<group colspan="2" col="2">
<label string="You can disable the reconciliation of this bank transfer" colspan="2"/>
<newline/>
<button colspan="1"
name="disable_match"
type="object"
string="Disable reconciliation"/>
</group>
</page>
</notebook>
<footer>
<button icon="gtk-ok" string="Close" special="cancel"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>

View File

@@ -1,338 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.tools.translate import _
from openerp.addons.account_banking import sepa
from openerp.addons.account_banking.struct import struct
__all__ = [
'get_period',
'get_bank_accounts',
'get_partner',
'get_country_id',
'get_company_bank_account',
'create_bank_account',
]
def get_period(pool, cr, uid, date, company, log=None):
'''
Wrapper over account_period.find() to log exceptions of
missing periods instead of raising.
'''
context = {'account_period_prefer_normal': True}
if company:
context['company_id'] = company.id
try:
period_ids = pool.get('account.period').find(
cr, uid, dt=date, context=context)
except Exception as e:
if log is None:
raise
else:
log.append(e)
return False
return period_ids[0]
def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
'''
Get the bank account with account number account_number
'''
# No need to search for nothing
if not account_number:
return []
partner_bank_obj = pool.get('res.partner.bank')
bank_account_ids = partner_bank_obj.search(cr, uid, [
('acc_number', '=', account_number)
])
if not bank_account_ids:
if not fail:
log.append(
_('Bank account %(account_no)s was not found in the database')
% dict(account_no=account_number)
)
return []
return partner_bank_obj.browse(cr, uid, bank_account_ids)
def _has_attr(obj, attr):
# Needed for dangling addresses and a weird exception scheme in
# OpenERP's orm.
try:
return bool(getattr(obj, attr))
except KeyError:
return False
def get_partner(pool, cr, uid, name, address, postal_code, city,
country_id, log, context=None):
'''
Get the partner belonging to the account holders name <name>
If multiple partners are found with the same name, select the first and
add a warning to the import log.
TODO: revive the search by lines from the address argument
'''
partner_obj = pool.get('res.partner')
partner_ids = partner_obj.search(
cr, uid, [
'|', ('is_company', '=', True), ('parent_id', '=', False),
('name', 'ilike', name),
], context=context)
if not partner_ids:
# Try brute search on address and then match reverse
criteria = []
if country_id:
criteria.append(('country_id', '=', country_id))
if city:
criteria.append(('city', 'ilike', city))
if postal_code:
criteria.append(('zip', 'ilike', postal_code))
partner_search_ids = partner_obj.search(
cr, uid, criteria, context=context)
if (not partner_search_ids and country_id):
# Try again with country_id = False
criteria[0] = ('country_id', '=', False)
partner_search_ids = partner_obj.search(
cr, uid, criteria, context=context)
key = name.lower()
partners = []
for partner in partner_obj.read(
cr, uid, partner_search_ids, ['name', 'commercial_partner_id'],
context=context):
if (len(partner['name']) > 3 and partner['name'].lower() in key):
partners.append(partner)
partners.sort(key=lambda x: len(x['name']), reverse=True)
partner_ids = [x['commercial_partner_id'][0] for x in partners]
if len(partner_ids) > 1:
log.append(
_('More than one possible match found for partner with '
'name %(name)s') % {'name': name})
return partner_ids and partner_ids[0] or False
def get_company_bank_account(pool, cr, uid, account_number, currency,
company, log):
'''
Get the matching bank account for this company. Currency is the ISO code
for the requested currency.
'''
results = struct()
bank_accounts = get_bank_accounts(pool, cr, uid, account_number, log,
fail=True)
if not bank_accounts:
return False
elif len(bank_accounts) != 1:
log.append(
_('More than one bank account was found with the same number '
'%(account_no)s') % dict(account_no=account_number)
)
return False
if bank_accounts[0].partner_id.id != company.partner_id.id:
log.append(
_('Account %(account_no)s is not owned by %(partner)s')
% dict(account_no=account_number,
partner=company.partner_id.name,
))
return False
results.account = bank_accounts[0]
bank_settings_obj = pool.get('account.banking.account.settings')
criteria = [('partner_bank_id', '=', bank_accounts[0].id)]
# Find matching journal for currency
journal_obj = pool.get('account.journal')
journal_ids = journal_obj.search(cr, uid, [
('type', '=', 'bank'),
('currency.name', '=', currency or company.currency_id.name)
])
if currency == company.currency_id.name:
journal_ids_no_curr = journal_obj.search(cr, uid, [
('type', '=', 'bank'), ('currency', '=', False)
])
journal_ids.extend(journal_ids_no_curr)
if journal_ids:
criteria.append(('journal_id', 'in', journal_ids))
# Find bank account settings
bank_settings_ids = bank_settings_obj.search(cr, uid, criteria)
if bank_settings_ids:
settings = bank_settings_obj.browse(cr, uid, bank_settings_ids)[0]
results.company_id = company
results.journal_id = settings.journal_id
# Take currency from settings or from company
if settings.journal_id.currency.id:
results.currency_id = settings.journal_id.currency
else:
results.currency_id = company.currency_id
# Rest just copy/paste from settings. Why am I doing this?
results.default_debit_account_id = settings.default_debit_account_id
results.default_credit_account_id = settings.default_credit_account_id
results.costs_account_id = settings.costs_account_id
results.invoice_journal_id = settings.invoice_journal_id
results.bank_partner_id = settings.bank_partner_id
return results
def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
name=None, context=None):
'''
Find or create the bank with the provided BIC code.
When online, the SWIFT database will be consulted in order to
provide for missing information.
'''
# UPDATE: Free SWIFT databases are since 2/22/2010 hidden behind an
# image challenge/response interface.
bank_obj = pool.get('res.bank')
# Self generated key?
if len(bic) < 8:
# search key
bank_ids = bank_obj.search(
cr, uid, [
('bic', '=', bic[:6])
])
if not bank_ids:
bank_ids = bank_obj.search(
cr, uid, [
('bic', 'ilike', bic + '%')
])
else:
bank_ids = bank_obj.search(
cr, uid, [
('bic', '=', bic)
])
if bank_ids and len(bank_ids) == 1:
banks = bank_obj.browse(cr, uid, bank_ids)
return banks[0].id, banks[0].country.id
country_obj = pool.get('res.country')
country_ids = country_obj.search(
cr, uid, [('code', '=', bic[4:6])]
)
country_id = country_ids and country_ids[0] or False
bank_id = False
if online:
info, address = bank_obj.online_bank_info(
cr, uid, bic, context=context
)
if info:
bank_id = bank_obj.create(cr, uid, dict(
code=info.code,
name=info.name,
street=address.street,
street2=address.street2,
zip=address.zip,
city=address.city,
country=country_id,
bic=info.bic[:8],
))
else:
info = struct(name=name, code=code)
if not online or not bank_id:
bank_id = bank_obj.create(cr, uid, dict(
code=info.code or 'UNKNOW', # FIXME: Typo?
name=info.name or _('Unknown Bank'),
country=country_id,
bic=bic,
))
return bank_id, country_id
def get_country_id(pool, cr, uid, transaction, context=None):
"""
Derive a country id from the info on the transaction.
:param transaction: browse record of a transaction
:returns: res.country id or False
"""
country_code = False
iban = sepa.IBAN(transaction.remote_account)
if iban.valid:
country_code = iban.countrycode
elif transaction.remote_owner_country_code:
country_code = transaction.remote_owner_country_code
# fallback on the import parsers country code
elif transaction.bank_country_code:
country_code = transaction.bank_country_code
if country_code:
country_ids = pool.get('res.country').search(
cr, uid, [('code', '=', country_code.upper())],
context=context)
country_id = country_ids and country_ids[0] or False
if not country_id:
company = transaction.statement_line_id.company_id
if company.partner_id.country:
country_id = company.partner_id.country.id
return country_id
def create_bank_account(pool, cr, uid, partner_id,
account_number, holder_name, address, city,
country_id, bic=False,
context=None):
'''
Create a matching bank account with this holder for this partner.
'''
values = struct(
partner_id=partner_id,
owner_name=holder_name,
country_id=country_id,
)
# Are we dealing with IBAN?
iban = sepa.IBAN(account_number)
if iban.valid:
# Take as much info as possible from IBAN
values.state = 'iban'
values.acc_number = str(iban)
else:
# No, try to convert to IBAN
values.state = 'bank'
values.acc_number = account_number
if country_id:
country_code = pool.get('res.country').read(
cr, uid, country_id, ['code'], context=context)['code']
if country_code in sepa.IBAN.countries:
account_info = pool['res.partner.bank'].online_account_info(
cr, uid, country_code, values.acc_number, context=context)
if account_info:
values.acc_number = iban = account_info.iban
values.state = 'iban'
bic = account_info.bic
if bic:
values.bank = get_or_create_bank(pool, cr, uid, bic)[0]
values.bank_bic = bic
# Create bank account and return
return pool.get('res.partner.bank').create(
cr, uid, values, context=context)

View File

@@ -1,208 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
from openerp.tools.translate import _
from openerp.addons.account_banking.wizard import banktools
import ast
class link_partner(orm.TransientModel):
_name = 'banking.link_partner'
_description = 'Link partner'
_columns = {
'name': fields.char(
'Create partner with name', size=128, required=True),
'supplier': fields.boolean('Supplier'),
'customer': fields.boolean('Customer'),
'partner_id': fields.many2one(
'res.partner', 'or link existing partner',
domain=['|', ('is_company', '=', True),
('parent_id', '=', False)],
),
'statement_line_id': fields.many2one(
'account.bank.statement.line',
'Statement line', required=True),
'amount': fields.related(
'statement_line_id', 'amount', type='float',
string="Amount", readonly=True),
'ref': fields.related(
'statement_line_id', 'ref', type='char', size=32,
string="Reference", readonly=True),
'message': fields.related(
'statement_line_id', 'import_transaction_id', 'message',
type='char', size=1024,
string="Message", readonly=True),
'remote_account': fields.char(
'Account number', size=24, readonly=True),
# Partner values
'street': fields.char('Street', size=128),
'street2': fields.char('Street2', size=128),
'zip': fields.char('Zip', change_default=True, size=24),
'city': fields.char('City', size=128),
'state_id': fields.many2one("res.country.state", 'State'),
'country_id': fields.many2one('res.country', 'Country'),
'email': fields.char('Email', size=240),
'phone': fields.char('Phone', size=64),
'fax': fields.char('Fax', size=64),
'mobile': fields.char('Mobile', size=64),
'is_company': fields.boolean('Is a Company'),
}
_defaults = {
'is_company': True,
}
def create(self, cr, uid, vals, context=None):
"""
Get default values from the transaction data
on the statement line
"""
if vals and vals.get('statement_line_id'):
statement_line_obj = self.pool.get('account.bank.statement.line')
statement_line = statement_line_obj.browse(
cr, uid, vals['statement_line_id'], context=context)
transaction = statement_line.import_transaction_id
if statement_line.partner_bank_id:
raise orm.except_orm(
_('Error'),
_('Statement line is already linked to a bank account '))
if not(transaction
and transaction.remote_account):
raise orm.except_orm(
_('Error'),
_('No transaction data on statement line'))
if 'supplier' not in vals and statement_line.amount < 0:
vals['supplier'] = True
if 'customer' not in vals and statement_line.amount > 0:
vals['customer'] = True
address_list = []
try:
address_list = ast.literal_eval(
transaction.remote_owner_address or [])
except ValueError:
pass
if address_list and not vals.get('street'):
vals['street'] = address_list.pop(0)
if address_list and not vals.get('street2'):
vals['street2'] = address_list.pop(0)
if transaction.remote_owner_postalcode and not vals.get('zip'):
vals['zip'] = transaction.remote_owner_postalcode
if transaction.remote_owner_city and not vals.get('city'):
vals['city'] = transaction.remote_owner_city
if not vals.get('country_id'):
vals['country_id'] = banktools.get_country_id(
self.pool, cr, uid, transaction, context=context)
if not vals.get('name'):
vals['name'] = transaction.remote_owner
if not vals['name']:
vals['name'] = '/'
if not vals.get('remote_account'):
vals['remote_account'] = transaction.remote_account
return super(link_partner, self).create(
cr, uid, vals, context=context)
def update_partner_values(self, cr, uid, wizard, values, context=None):
"""
Updates the new partner values with the values from the wizard
:param wizard: read record of wizard (with load='_classic_write')
:param values: the dictionary of partner values that will be updated
"""
for field in ['is_company',
'name',
'street',
'street2',
'zip',
'city',
'country_id',
'state_id',
'phone',
'fax',
'mobile',
'email'
]:
if wizard[field]:
values[field] = wizard[field]
return True
def link_partner(self, cr, uid, ids, context=None):
statement_line_obj = self.pool.get(
'account.bank.statement.line')
wiz = self.browse(cr, uid, ids[0], context=context)
if wiz.partner_id:
partner_id = wiz.partner_id.id
else:
wiz_read = self.read(
cr, uid, ids[0], context=context, load='_classic_write')
partner_vals = {
'type': 'default',
}
self.update_partner_values(
cr, uid, wiz_read, partner_vals, context=context)
partner_id = self.pool.get('res.partner').create(
cr, uid, partner_vals, context=context)
partner_bank_id = banktools.create_bank_account(
self.pool, cr, uid, partner_id,
wiz.remote_account, wiz.name,
wiz.street, wiz.city,
wiz.country_id and wiz.country_id.id or False,
bic=wiz.statement_line_id.import_transaction_id.remote_bank_bic,
context=context)
statement_line_ids = statement_line_obj.search(
cr, uid,
[('import_transaction_id.remote_account', '=', wiz.remote_account),
('partner_bank_id', '=', False),
('state', '=', 'draft')], context=context)
statement_line_obj.write(
cr, uid, statement_line_ids,
{'partner_bank_id': partner_bank_id,
'partner_id': partner_id}, context=context)
return {'type': 'ir.actions.act_window_close'}
def create_act_window(self, cr, uid, ids, nodestroy=True, context=None):
"""
Return a popup window for this model
"""
if isinstance(ids, (int, long)):
ids = [ids]
return {
'name': self._description,
'view_type': 'form',
'view_mode': 'form',
'res_model': self._name,
'domain': [],
'context': context,
'type': 'ir.actions.act_window',
'target': 'new',
'res_id': ids[0],
'nodestroy': nodestroy,
}

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="link_partner_view">
<field name="name">Link partner wizard view</field>
<field name="type">form</field>
<field name="model">banking.link_partner</field>
<field name="arch" type="xml">
<form string="Link partner" version="7.0" >
<group colspan="4" col="6" string="Transaction data">
<field name="ref" />
<field name="amount" />
<field name="remote_account" />
<field name="message" colspan="6"/>
</group>
<group colspan="4" col="4" string="Create or link partner">
<field name="name"
attrs="{'readonly': [('partner_id', '!=', False)]}" />
<field name="partner_id"/>
</group>
<group colspan="2">
<field name="is_company" />
</group>
<group colspan="4"
string="Address"
attrs="{'invisible': [('partner_id', '!=', False)]}"
col="4">
<group colspan="2" col="2">
<field name="street"/>
<field name="street2"/>
<field name="zip"/>
<field name="city"/>
<field name="country_id"/>
<field name="state_id"/>
</group>
<group colspan="2" col="2">
<field name="phone"/>
<field name="fax"/>
<field name="mobile"/>
<field name="email" widget="email"/>
</group>
</group>
<footer>
<button string="Create partner"
name="link_partner" type="object"
class="oe_highlight"
attrs="{'invisible': [('partner_id', '!=', False)]}"
/>
<button string="Link existing partner"
class="oe_highlight"
name="link_partner" type="object"
attrs="{'invisible': [('partner_id', '==', False)]}"
/>
or
<button class="oe_link" string="Cancel" special="cancel" />
</footer>
</form>
</field>
</record>
</data>
</openerp>