Migration to OpenERP 6.0

This commit is contained in:
Stefan Rijnhart
2011-04-26 22:41:31 +02:00
parent ad95efd7e4
commit 400bf0e41e
9 changed files with 450 additions and 398 deletions

View File

@@ -63,6 +63,7 @@ import sepa
from osv import osv, fields
from tools.translate import _
from wizard.banktools import get_or_create_bank
import decimal_precision as dp
import pooler
import netsvc
@@ -183,6 +184,49 @@ class account_banking_imported_file(osv.osv):
}
account_banking_imported_file()
class payment_mode_type(osv.osv):
_name= 'payment.mode.type'
_description= 'Payment Mode Type'
_columns= {
'name': fields.char(
'Name', size=64, required=True,
help='Payment Type'
),
'code': fields.char(
'Code', size=64, required=True,
help='Specify the Code for Payment Type'
),
}
payment_mode_type()
class payment_mode(osv.osv):
''' Restoring the payment type from version 5,
used to select the export wizard (if any) '''
_inherit = "payment.mode"
def suitable_bank_types(self, cr, uid, payment_code=None, context=None):
"""Return all bank types when no payment_code is given (which is
currently always the case when selecting invoices for payment orders.
See " t = None " line in
account_payment/wizard/account_payment_order.py.
TODO: find the logical error for this and file bug report accordingly
"""
if not payment_code:
cr.execute(""" SELECT DISTINCT state FROM res_partner_bank """)
return [x[0] for x in cr.fetchall()]
return super(payment_mode, self).suitable_bank_types(
cr, uid, payment_code, context)
_columns = {
'type': fields.many2one(
'payment.mode.type', 'Payment type',
help='Select the Payment Type for the Payment Mode.'
),
}
payment_mode()
class account_bank_statement(osv.osv):
'''
Extensions from account_bank_statement:
@@ -264,228 +308,139 @@ class account_bank_statement(osv.osv):
# '''
# return None
def button_confirm(self, cursor, uid, ids, context=None):
'''
Trigger function for button 'Confirm'
As this function completely replaces the old one in account, other
modules who wish to alter behavior of this function but want to
cooperate with account_banking, should move their functionality to
on_button_confirm(self, cursor, uid, ids, context=None)
and drop any calls to super() herein.
In order to allow usage with and without account_banking, one could
use
def on_button_confirm(...):
# Your code here
def button_confirm(...):
super(my_class, self).button_confirm(...)
self.on_button_confirm(...)
This way, code duplication is minimized.
'''
def create_move_from_st_line(self, cr, uid, st_line_id,
company_currency_id, st_line_number,
context=None):
# This is largely a copy of the original code in account
# Modifications are marked with AB
# As there is no valid inheritance mechanism for large actions, this
# is the only option to add functionality to existing actions.
# WARNING: when the original code changes, this trigger has to be
# updated in sync.
done = []
if context is None:
context = {}
res_currency_obj = self.pool.get('res.currency')
res_users_obj = self.pool.get('res.users')
account_move_obj = self.pool.get('account.move')
account_move_line_obj = self.pool.get('account.move.line')
account_bank_statement_line_obj = \
self.pool.get('account.bank.statement.line')
account_bank_statement_line_obj = self.pool.get(
'account.bank.statement.line')
st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id,
context=context)
st = st_line.statement_id
company_currency_id = res_users_obj.browse(cursor, uid, uid,
context=context).company_id.currency_id.id
context.update({'date': st_line.date})
period_id = self._get_period(
cr, uid, st_line.date, context=context) # AB
for st in self.browse(cursor, uid, ids, context):
if not st.state=='draft':
continue
move_id = account_move_obj.create(cr, uid, {
'journal_id': st.journal_id.id,
'period_id': period_id, # AB
'date': st_line.date,
'name': st_line_number,
}, context=context)
account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
'move_ids': [(4, move_id, False)]
})
# Calculate statement balance from the contained lines
end_bal = st.balance_end or 0.0
if not (abs(end_bal - st.balance_end_real) < 0.0001):
if st_line.amount >= 0:
account_id = st.journal_id.default_credit_account_id.id
else:
account_id = st.journal_id.default_debit_account_id.id
acc_cur = ((st_line.amount <= 0 and
st.journal_id.default_debit_account_id) or
st_line.account_id)
context.update({
'res.currency.compute.account': acc_cur,
})
amount = res_currency_obj.compute(cr, uid, st.currency.id,
company_currency_id, st_line.amount, context=context)
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),
'account_id': (st_line.account_id) and st_line.account_id.id,
'credit': ((amount>0) and amount) or 0.0,
'debit': ((amount<0) and -amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id, # AB
'currency_id': st.currency.id,
'analytic_account_id': (st_line.analytic_account_id and
st_line.analytic_account_id.id or
False),
}
if st.currency.id <> company_currency_id:
amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
st.currency.id, amount, context=context)
val['amount_currency'] = -amount_cur
if (st_line.account_id and st_line.account_id.currency_id and
st_line.account_id.currency_id.id <> company_currency_id):
val['currency_id'] = st_line.account_id.currency_id.id
amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
st_line.account_id.currency_id.id, amount, context=context)
val['amount_currency'] = -amount_cur
move_line_id = account_move_line_obj.create(
cr, uid, val, context=context)
torec = move_line_id
# Fill the secondary amount/currency
# if currency is not the same than the company
amount_currency = False
currency_id = False
if st.currency.id <> company_currency_id:
amount_currency = st_line.amount
currency_id = st.currency.id
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),
'account_id': account_id,
'credit': ((amount < 0) and -amount) or 0.0,
'debit': ((amount > 0) and amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id, # AB
'amount_currency': amount_currency,
'currency_id': currency_id,
}, context=context)
for line in account_move_line_obj.browse(cr, uid, [x.id for x in
account_move_obj.browse(cr, uid, move_id,
context=context).line_id],
context=context):
if line.state <> 'valid':
raise osv.except_osv(_('Error !'),
_('The statement balance is incorrect !\n') +
_('The expected balance (%.2f) is different '
'than the computed one. (%.2f)') % (
st.balance_end_real, st.balance_end
))
if (not st.journal_id.default_credit_account_id) \
or (not st.journal_id.default_debit_account_id):
raise osv.except_osv(_('Configration Error !'),
_('Please verify that an account is defined in the journal.'))
_('Journal Item "%s" is not valid') % line.name)
for line in st.move_line_ids:
if line.state != 'valid':
raise osv.except_osv(_('Error !'),
_('The account entries lines are not in valid state.'))
# Bank statements will not consider boolean on journal entry_posted
account_move_obj.post(cr, uid, [move_id], context=context)
"""
Account-banking:
- Write stored reconcile_id
- Pay invoices through workflow
"""
if st_line.reconcile_id:
account_move_line_obj.write(cr, uid, [torec], {
'reconcile_id': st_line.reconcile_id.id }, context=context)
for move_line in (st_line.reconcile_id.line_id or []) + (
st_line.reconcile_id.line_partial_ids or []):
netsvc.LocalService("workflow").trg_trigger(
uid, 'account.move.line', move_line.id, cr)
""" End account-banking """
for move in st.line_ids:
context.update({'date':move.date})
# Essence of the change is here...
period_id = self._get_period(cursor, uid, move.date, context=context)
move_id = account_move_obj.create(cursor, uid, {
'journal_id': st.journal_id.id,
# .. and here
'period_id': period_id,
'date': move.date,
}, context=context)
account_bank_statement_line_obj.write(cursor, uid, [move.id], {
'move_ids': [(4, move_id, False)]
})
if not move.amount:
continue
torec = []
if move.amount >= 0:
account_id = st.journal_id.default_credit_account_id.id
else:
account_id = st.journal_id.default_debit_account_id.id
acc_cur = ((move.amount<=0) and st.journal_id.default_debit_account_id) \
or move.account_id
amount = res_currency_obj.compute(cursor, uid, st.currency.id,
company_currency_id, move.amount, context=context,
account=acc_cur)
if move.reconcile_id and move.reconcile_id.line_new_ids:
for newline in move.reconcile_id.line_new_ids:
amount += newline.amount
val = {
'name': move.name,
'date': move.date,
'ref': move.ref,
'move_id': move_id,
'partner_id': ((move.partner_id) and move.partner_id.id) or False,
'account_id': (move.account_id) and move.account_id.id,
'credit': ((amount>0) and amount) or 0.0,
'debit': ((amount<0) and -amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id,
'currency_id': st.currency.id,
}
amount = res_currency_obj.compute(cursor, uid, st.currency.id,
company_currency_id, move.amount, context=context,
account=acc_cur)
if st.currency.id != company_currency_id:
amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
st.currency.id, amount, context=context,
account=acc_cur)
val['amount_currency'] = -amount_cur
if move.account_id and move.account_id.currency_id and move.account_id.currency_id.id != company_currency_id:
val['currency_id'] = move.account_id.currency_id.id
amount_cur = res_currency_obj.compute(cursor, uid, company_currency_id,
move.account_id.currency_id.id, amount, context=context,
account=acc_cur)
val['amount_currency'] = -amount_cur
torec.append(account_move_line_obj.create(cursor, uid, val , context=context))
if move.reconcile_id and move.reconcile_id.line_new_ids:
for newline in move.reconcile_id.line_new_ids:
account_move_line_obj.create(cursor, uid, {
'name': newline.name or move.name,
'date': move.date,
'ref': move.ref,
'move_id': move_id,
'partner_id': ((move.partner_id) and move.partner_id.id) or False,
'account_id': (newline.account_id) and newline.account_id.id,
'debit': newline.amount>0 and newline.amount or 0.0,
'credit': newline.amount<0 and -newline.amount or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id,
}, context=context)
# Fill the secondary amount/currency
# if currency is not the same than the company
amount_currency = False
currency_id = False
if st.currency.id <> company_currency_id:
amount_currency = move.amount
currency_id = st.currency.id
account_move_line_obj.create(cursor, uid, {
'name': move.name,
'date': move.date,
'ref': move.ref,
'move_id': move_id,
'partner_id': ((move.partner_id) and move.partner_id.id) or False,
'account_id': account_id,
'credit': ((amount < 0) and -amount) or 0.0,
'debit': ((amount > 0) and amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id,
'amount_currency': amount_currency,
'currency_id': currency_id,
}, context=context)
for line in account_move_line_obj.browse(cursor, uid, [x.id for x in
account_move_obj.browse(cursor, uid, move_id, context=context).line_id
], context=context):
if line.state != 'valid':
raise osv.except_osv(
_('Error !'),
_('Account move line "%s" is not valid')
% line.name
)
if move.reconcile_id and move.reconcile_id.line_ids:
## Search if move has already a partial reconciliation
previous_partial = False
for line_reconcile_move in move.reconcile_id.line_ids:
if line_reconcile_move.reconcile_partial_id:
previous_partial = True
break
##
torec += map(lambda x: x.id, move.reconcile_id.line_ids)
#try:
if abs(move.reconcile_amount-move.amount)<0.0001:
writeoff_acc_id = False
#There should only be one write-off account!
for entry in move.reconcile_id.line_new_ids:
writeoff_acc_id = entry.account_id.id
break
## If we have already a partial reconciliation
## We need to make a partial reconciliation
## To add this amount to previous paid amount
if previous_partial:
account_move_line_obj.reconcile_partial(cr, uid, torec, 'statement', context)
## If it's the first reconciliation, we do a full reconciliation as regular
else:
account_move_line_obj.reconcile(
cursor, uid, torec, 'statement',
writeoff_acc_id=writeoff_acc_id,
writeoff_period_id=st.period_id.id,
writeoff_journal_id=st.journal_id.id,
context=context
)
else:
account_move_line_obj.reconcile_partial(
cursor, uid, torec, 'statement', context
)
if st.journal_id.entry_posted:
account_move_obj.write(cursor, uid, [move_id], {'state':'posted'})
done.append(st.id)
self.write(cursor, uid, done, {'state':'confirm'}, context=context)
# Be nice to other modules as well, relay button_confirm calls to
# on_button_confirm calls.
for other in self._abf_others:
if hasattr(other, 'on_button_confirm'):
other.on_button_confirm(self, cursor, uid, ids, context=context)
return True
return move_id
account_bank_statement()
@@ -563,9 +518,23 @@ class account_bank_statement_line(osv.osv):
# res[line.id] = 0.0
# return res
def _get_invoice_id(self, cr, uid, ids, name, args, context=None):
res = {}
for st_line in self.browse(cr, uid, ids, context):
res[st_line.id] = False
for move_line in (st_line.reconcile_id and
(st_line.reconcile_id.line_id or []) +
(st_line.reconcile_id.line_partial_ids or []) or
[]):
if move_line.invoice:
res[st_line.id] = move_line.invoice.id
continue
return res
_columns = {
# Redefines
'amount': fields.float('Amount', readonly=True,
'amount': fields.float('Amount', readonly=True,
digits_compute=dp.get_precision('Account'),
states={'draft': [('readonly', False)]}),
'ref': fields.char('Ref.', size=32, readonly=True,
states={'draft': [('readonly', False)]}),
@@ -595,6 +564,13 @@ class account_bank_statement_line(osv.osv):
required=False,
states={'confirm': [('readonly', True)]},
),
'reconcile_id': fields.many2one(
'account.move.reconcile', 'Reconciliation', readonly=True
),
'invoice_id': fields.function(
_get_invoice_id, method=True, string='Linked Invoice',
type='many2one', relation='account.invoice'
),
}
_defaults = {
@@ -603,57 +579,8 @@ class account_bank_statement_line(osv.osv):
'currency': _get_currency,
}
def onchange_partner_id(self, cursor, uid, line_id, partner_id, type,
currency_id, context=None
):
'''
Find default accounts when encoding statements by hand
'''
if not partner_id:
return {}
result = {}
if not currency_id:
users_obj = self.pool.get('res.users')
currency_id = users_obj.browse(
cursor, uid, uid, context=context
).company_id.currency_id.id
result['currency_id'] = currency_id
partner_obj = self.pool.get('res.partner')
partner = partner_obj.browse(cursor, uid, partner_id, context=context)
if partner.supplier and not partner.customer:
if partner.property_account_payable.id:
result['account_id'] = partner.property_account_payable.id
result['type'] = 'supplier'
elif partner.customer and not partner.supplier:
if partner.property_account_receivable.id:
result['account_id'] = partner.property_account_receivable.id
result['type'] = 'customer'
return result and {'value': result} or {}
account_bank_statement_line()
class payment_type(osv.osv):
'''
Make description field translatable #, add country context
'''
_inherit = 'payment.type'
_columns = {
'name': fields.char('Name', size=64, required=True, translate=True,
help='Payment Type'
),
#'country_id': fields.many2one('res.country', 'Country',
# required=False,
# help='Use this to limit this type to a specific country'
# ),
}
#_defaults = {
# 'country_id': lambda *a: False,
#}
payment_type()
class payment_line(osv.osv):
'''
Add extra export_state and date_done fields; make destination bank account
@@ -813,8 +740,42 @@ class payment_order(osv.osv):
Enable extra states for payment exports
'''
_inherit = 'payment.order'
def _get_id_proxy(self, cr, uid, ids, name, args, context=None):
return dict([(id, id) for id in ids])
_columns = {
'date_planned': fields.date(
#
# 'id_proxy' is simply a reference to the resource's id
# for the following reason:
#
# The GTK client 6.0 lacks necessary support for old style wizards.
# It does not pass the resource's id if the wizard is called from
# a button on a form.
#
# As a workaround, we pass the payment order id in the context
# Evaluating 'id' in the context in the webclient on a form
# in readonly mode dies with an error "Invalid Syntax", because 'id'
# evaluates to "<built-in function id>" and the resource's field
# values are not passed to eval in readonly mode at all.
# See /addons/openerp/static/javascript/form.js line 308
#
# Evaluating any other variable in the webclient on a form in
# readonly mode fails silently. That is actually ok, because the
# webclient still supports passing the resource id when an old style
# wizard is called.
#
# Therefore, if we want to pass the id in the context safely we have to
# pass it under a different name.
#
'id_proxy': fields.function(
_get_id_proxy, method=True, string='Copy ID', type='integer',
store={
'payment.order': (
lambda self,cr,uid,ids,c=None:ids, ['id'], 10)
}
),
'date_scheduled': fields.date(
'Scheduled date if fixed',
states={
'sent': [('readonly', True)],
@@ -883,6 +844,33 @@ class payment_order(osv.osv):
),
}
def launch_wizard(self, cr, uid, ids, context=None):
"""
Search for a wizard to launch according to the type.
If type is manual. just confirm the order.
Previously (pre-v6) in account_payment/wizard/wizard_pay.py
"""
result = {}
obj_model = self.pool.get('ir.model.data')
order = self.browse(cr, uid, ids[0], context)
t = order.mode and order.mode.type.code or 'manual'
res_id = False
if t != 'manual':
gw = self.get_wizard(t)
if gw:
module, wizard = gw
wiz_id = obj_model._get_id(cr, uid, module, wizard)
if wiz_id:
res_id = obj_model.read(
cr, uid, [wiz_id], ['res_id'])[0]['res_id']
if res_id:
result = self.pool.get('ir.actions.wizard').read(
cr, uid, [res_id])[0]
else:
self.action_sent(cr, uid, ids, context)
result['nodestroy'] = True
return result
def _write_payment_lines(self, cursor, uid, ids, **kwargs):
'''
ORM method for setting attributes of corresponding payment.line objects.
@@ -890,6 +878,8 @@ class payment_order(osv.osv):
to the absence of filters on writes and hence the requirement to
filter on the client(=OpenERP server) side.
'''
if isinstance(ids, (int, long)):
ids = [ids]
payment_line_obj = self.pool.get('payment.line')
line_ids = payment_line_obj.search(
cursor, uid, [
@@ -911,7 +901,6 @@ class payment_order(osv.osv):
Set both self and payment lines to state 'sent'.
'''
self._write_payment_lines(cursor, uid, ids, export_state='sent')
self.write(cursor, uid, ids, {'state': 'rejected'})
wf_service = netsvc.LocalService('workflow')
for id in ids:
wf_service.trg_validate(uid, 'payment.order', id, 'sent', cursor)
@@ -922,17 +911,17 @@ class payment_order(osv.osv):
Set both self and payment lines to state 'rejected'.
'''
self._write_payment_lines(cursor, uid, ids, export_state='rejected')
self.write(cursor, uid, ids, {'state': 'rejected'})
wf_service = netsvc.LocalService('workflow')
for id in ids:
wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cursor)
wf_service.trg_validate(
uid, 'payment.order', id, 'rejected', cursor)
return True
def set_done(self, cursor, uid, id, *args):
'''
Extend standard transition to update children as well.
'''
self._write_payment_lines(cursor, uid, [id],
self._write_payment_lines(cursor, uid, id,
export_state='done',
date_done=time.strftime('%Y-%m-%d')
)
@@ -1188,7 +1177,7 @@ class res_partner_bank(osv.osv):
elif partner_id:
partner_obj = self.pool.get('res.partner')
country = partner_obj.browse(cursor, uid, partner_id).country
country_ids = [country.id]
country_ids = country and [country.id] or []
# 4. Without any of the above, take the country from the company of
# the handling user
if not country_ids:
@@ -1197,12 +1186,15 @@ class res_partner_bank(osv.osv):
country = user.address_id.country_id
country_ids = [country.id]
else:
# Ok, tried everything, give up and leave it to the user
return warning(_('Insufficient data'),
_('Insufficient data to select online '
'conversion database')
)
if (user.company_id and user.company_id.partner_id and
user.company_id.partner_id.country):
country_ids = [user.company_id.partner_id.country.id]
else:
# Ok, tried everything, give up and leave it to the user
return warning(_('Insufficient data'),
_('Insufficient country information to '
'select online conversion database')
)
result = {'value': values}
# Complete data with online database when available
if country.code in sepa.IBAN.countries:
@@ -1218,17 +1210,17 @@ class res_partner_bank(osv.osv):
info.bic or iban_acc.BIC_searchkey,
code = info.code, name = info.bank
)
values['country_id'] = country_id or \
country_ids and country_ids[0] or \
False
values['country_id'] = (
country_id or country_ids and country_ids[0] or
False)
values['bank'] = bank_id or False
else:
info = None
if info is None:
result.update(warning(
_('Invalid data'),
_('The account number appears to be invalid for %(country)s')
% {'country': country.name}
_('Could not verify the account number\'s validity '
'for %(country)s') % {'country': country.name}
))
except NotImplementedError:
if country.code in sepa.IBAN.countries:
@@ -1239,8 +1231,8 @@ class res_partner_bank(osv.osv):
values['acc_number'] = acc_number
result.update(warning(
_('Invalid format'),
_('The account number has the wrong format for %(country)s')
% {'country': country.name}
_('The account number has the wrong format for '
'%(country)s') % {'country': country.name}
))
else:
values['acc_number'] = acc_number

View File

@@ -42,7 +42,7 @@
<field name="company_id" />
<separator string="Bank Account Details" colspan="4" />
<field name="partner_bank_id" /> <!-- Needs domain for used companies /-->
<field name="journal_id" domain="[('type','=','cash')]" />
<field name="journal_id" domain="[('type','=','bank')]" />
<separator string="Default Accounts for Unknown Movements" colspan="4" />
<field name="default_credit_account_id" />
<field name="default_debit_account_id" />
@@ -61,7 +61,7 @@
<tree string="Default Import Settings for Bank Account">
<field name="company_id" />
<field name="partner_bank_id" /> <!-- Needs domain for used companies /-->
<field name="journal_id" domain="[('type','=','cash')]" />
<field name="journal_id" domain="[('type','=','bank')]" />
</tree>
</field>
</record>
@@ -170,7 +170,15 @@
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="period_id" position="replace"/>
<data>
<field name="period_id" position="replace"/>
<xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='name']" position="replace">
<field name="name" required="1"/>
</xpath>
<xpath expr="/form/notebook/page[@string='Transaction']/field/form/field[@name='name']" position="replace">
<field name="name" required="1"/>
</xpath>
</data>
</field>
</record>
<record id="view_banking_bank_statement_form_2" model="ir.ui.view">
@@ -179,7 +187,7 @@
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page[@string='Entry encoding']/field/tree/field[@name='type']" position="after">
<xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='ref']" position="after">
<field name="period_id"/>
</xpath>
</field>
@@ -190,7 +198,7 @@
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page[@string='Entry encoding']/field/form/field[@name='type']" position="after">
<xpath expr="/form/notebook/page[@string='Transaction']/field/form/field[@name='ref']" position="after">
<field name="period_id"/>
</xpath>
</field>
@@ -235,9 +243,19 @@
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='partner_id']" position="after">
<field name="partner_bank_id"/>
</xpath>
<data>
<xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='partner_id']" position="after">
<field name="partner_bank_id"/>
</xpath>
<xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<field name="invoice_id"/>
<field name="reconcile_id"/>
</xpath>
<xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='amount']" position="after">
<field name="invoice_id"/>
<field name="reconcile_id"/>
</xpath>
</data>
</field>
</record>
<record id="view_banking_bank_statement_form_6" model="ir.ui.view">
@@ -252,33 +270,31 @@
</field>
</record>
<!-- Reset trigger on button_confirm to the trigger code in this module -->
<record id="view_banking_bank_statement_form_4" model="ir.ui.view">
<field name="name">account.bank.statement.form.banking-4</field>
<field name="inherit_id" ref="account.view_bank_statement_form" />
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<button name="button_confirm" position="replace">
<button name="button_confirm" states="draft" string="Confirm" type="object"/>
</button>
</field>
</record>
<!-- Make buttons on payment order sensitive for extra states,
restore wizard functionality when making payments
-->
<!-- Make buttons on payment order sensitive for extra states -->
<record id="view_banking_payment_order_form_1" model="ir.ui.view">
<field name="name">account.payment.order.form.banking-1</field>
<field name="inherit_id" ref="account_payment.view_payment_order_form" />
<field name="model">payment.order</field>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/button[@string='Select Invoices to Pay']"
position="replace">
<button name="%(account_payment.wizard_populate_payment)s"
colspan="2" type="action" states="draft,open"
string="Select Invoices to Pay"
/>
</xpath>
<data>
<xpath expr="/form/group/button[@string='Select Invoices to Pay']"
position="replace">
<button colspan="2" name="%(account_payment.action_create_payment_order)s"
string="Select Invoices to Pay" type="action" states="draft,open"
icon="gtk-find"
/>
</xpath>
<xpath expr="/form/group/button[@string='Make Payments']"
position="replace">
<field name="id_proxy" invisible="1"/>
<button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute" context="{'payment_order_id': id_proxy}"/>
<newline/>
</xpath>
</data>
</field>
</record>
@@ -336,7 +352,7 @@
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='bank_ids']/tree/field[@name='acc_number']" position="replace">
<field name="acc_number" on_change="onchange_acc_number(acc_number, parent.id, country_id)" />
<field name="acc_number" on_change="onchange_acc_number(acc_number, parent.id, country_id)" select="1" />
</xpath>
</field>
</record>
@@ -354,5 +370,30 @@
</field>
</record>
<!-- Insert payment_mode.type -->
<record id="view_payment_mode_form_inherit" model="ir.ui.view">
<field name="name">payment.mode.form.inherit</field>
<field name="model">payment.mode</field>
<field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="type"/>
</field>
</field>
</record>
<record id="view_payment_mode_tree_inherit" model="ir.ui.view">
<field name="name">payment.mode.tree.inherit</field>
<field name="model">payment.mode</field>
<field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
<field name="type">tree</field>
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="type"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -23,12 +23,5 @@
<field eval="False" name="required"/>
<field eval="False" name="readonly"/>
</record>
<!-- Add manual bank transfer as default payment option -->
<record model="payment.type" id="account_banking.manual_bank_tranfer">
<field name="name">Manual Bank Transfer</field>
<field name="code">BANKMAN</field>
<field name="suitable_bank_types"
eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
</record>
</data>
</openerp>

View File

@@ -198,7 +198,7 @@ class IBAN(str):
'CS': BBANFormat('BBBAAAAAAAAAAAAAVV', '%B-%A-%V'),
'CY': BBANFormat('BBBCCCCCAAAAAAAAAAAAAAAA', '%B%C%A'),
'CZ': BBANFormat('BBBBPPPPPPAAAAAAAAAA', '%B-%P/%A'),
'DE': BBANFormat('BBBBBBBBAAAAAAAAAAV', '%A%V BLZ %B'),
'DE': BBANFormat('BBBBBBBBAAAAAAAAAA', '%A BLZ %B'),
'DK': BBANFormat('CCCCAAAAAAAAAV', '%C %A%V'),
'EE': BBANFormat('BBCCAAAAAAAAAAAV', '%A%V'),
'ES': BBANFormat('BBBBCCCCWVAAAAAAAAAA', '%B%C%W%V%A'),

View File

@@ -126,15 +126,19 @@ def BBAN_is_IBAN(bank_acc):
Intelligent copy, valid for SEPA members who switched to SEPA from old
standards before SEPA actually started.
'''
iban_acc = False
if isinstance(bank_acc, IBAN):
iban_acc = bank_acc
else:
iban_acc = IBAN(bank_acc)
return struct(
iban = iban_acc,
account = str(bank_acc),
country_id = iban_acc.countrycode,
code = iban_acc.BIC_searchkey
code = iban_acc.BIC_searchkey,
# Note: BIC can not be constructed here!
bic = False,
bank = False,
)
_account_info = {

View File

@@ -41,6 +41,7 @@ from account_banking.parsers.convert import *
from account_banking.struct import struct
from account_banking import sepa
from banktools import *
import decimal_precision as dp
bt = models.mem_bank_transaction
@@ -118,7 +119,7 @@ class banking_import(wizard.interface):
def _get_move_info(self, cursor, uid, move_line, partner_bank_id=False,
partial=False):
reconcile_obj = self.pool.get('account.bank.statement.reconcile')
reconcile_obj = self.pool.get('account.move.reconcile')
type_map = {
'out_invoice': 'customer',
'in_invoice': 'supplier',
@@ -137,7 +138,10 @@ class banking_import(wizard.interface):
if partial:
move_line.reconcile_partial_id = reconcile_obj.create(
cursor, uid, {'line_partial_ids': [(4, 0, [move_line.id])]}
cursor, uid, {
'type': 'auto',
'line_partial_ids': [(4, 0, [move_line.id])]
}
)
else:
if move_line.reconcile_partial_id:
@@ -148,6 +152,7 @@ class banking_import(wizard.interface):
partial_ids = []
move_line.reconcile_id = reconcile_obj.create(
cursor, uid, {
'type': 'auto',
'line_ids': [
(4, x, False) for x in [move_line.id] + partial_ids
],
@@ -167,13 +172,14 @@ class banking_import(wizard.interface):
'''
# TODO: Not sure what side effects are created when payments are done
# for credited customer invoices, which will be matched later on too.
digits = int(config['price_accuracy'])
candidates = [x for x in payment_lines
if x.communication == trans.reference
and round(x.amount, digits) == -round(trans.transferred_amount, digits)
and trans.remote_account in (x.bank_id.acc_number,
x.bank_id.iban)
]
digits = dp.get_precision('Account')(cursor)[1]
candidates = [x for x in payment_lines if (
x.communication == trans.reference and
round(x.amount, digits) == -round(
trans.transferred_amount, digits) and
trans.remote_account in (x.bank_id.acc_number,
x.bank_id.iban)
)]
if len(candidates) == 1:
candidate = candidates[0]
# Check cache to prevent multiple matching of a single payment
@@ -285,7 +291,7 @@ class banking_import(wizard.interface):
'out_refund': -1
}[invoice.type]
digits = int(config['price_accuracy'])
digits = dp.get_precision('Account')(cursor)[1]
partial = False
# Search invoice on partner
@@ -460,7 +466,7 @@ class banking_import(wizard.interface):
if not account_info.costs_account_id:
return []
digits = int(config['price_accuracy'])
digits = dp.get_precision('Account')(cursor)[1]
amount = round(abs(trans.transferred_amount), digits)
# Make sure to be able to pinpoint our costs invoice for later
# matching
@@ -507,19 +513,14 @@ class banking_import(wizard.interface):
check_total = amount,
invoice_line = invoice_lines,
))
invoice = invoice_obj.browse(cursor, uid, invoice_id)
# Set number
invoice.action_number(cursor, uid, [invoice_id])
# Create moves
invoice.action_move_create(cursor, uid, [invoice_id])
# Create workflow
invoice_obj.button_compute(cursor, uid, [invoice_id],
{'type': 'in_invoice'}, set_total=True)
wf_service = netsvc.LocalService('workflow')
res = wf_service.trg_create(uid, 'account.invoice', invoice.id,
cursor)
# Move to state 'open'
wf_service.trg_validate(uid, 'account.invoice', invoice.id,
wf_service.trg_validate(uid, 'account.invoice', invoice_id,
'invoice_open', cursor)
invoice = invoice_obj.browse(cursor, uid, invoice_id)
# return move_lines to mix with the rest
return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
@@ -544,7 +545,7 @@ class banking_import(wizard.interface):
statement_line_obj = self.pool.get('account.bank.statement.line')
statement_file_obj = self.pool.get('account.banking.imported.file')
#account_obj = self.pool.get('account.account')
#payment_order_obj = self.pool.get('payment.order')
payment_order_obj = self.pool.get('payment.order')
currency_obj = self.pool.get('res.currency')
# get the parser to parse the file
@@ -567,7 +568,6 @@ class banking_import(wizard.interface):
# Parse the file
statements = parser.parse(data)
if any([x for x in statements if not x.is_valid()]):
raise wizard.except_wizard(
_('ERROR!'),
@@ -646,7 +646,7 @@ class banking_import(wizard.interface):
continue
# Create fallback currency code
currency_code = statement.local_currency or company.currency_id.code
currency_code = statement.local_currency or company.currency_id.name
# Check cache for account info/currency
if statement.local_account in info and \
@@ -678,7 +678,7 @@ class banking_import(wizard.interface):
continue
# Get required currency code
currency_code = account_info.currency_id.code
currency_code = account_info.currency_id.name
# Cache results
if not statement.local_account in info:
@@ -690,7 +690,7 @@ class banking_import(wizard.interface):
# Final check: no coercion of currencies!
if statement.local_currency \
and account_info.currency_id.code != 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'
@@ -730,8 +730,8 @@ class banking_import(wizard.interface):
))
imported_statement_ids.append(statement_id)
# move each transaction to the right period and try to match it with an
# invoice or payment
# move each transaction to the right period and try to match it
# with an invoice or payment
subno = 0
injected = []
i = 0
@@ -743,8 +743,8 @@ class banking_import(wizard.interface):
transaction = injected.pop(0)
else:
transaction = statement.transactions[i]
# Keep a tracer for identification of order in a statement in case
# of missing transaction ids.
# Keep a tracer for identification of order in a statement
# in case of missing transaction ids.
subno += 1
# Link accounting period
@@ -753,6 +753,7 @@ class banking_import(wizard.interface):
results.log)
if not period_id:
results.trans_skipped_cnt += 1
i += 1
continue
# When bank costs are part of transaction itself, split it.
@@ -797,15 +798,16 @@ class banking_import(wizard.interface):
if partner_banks:
partner_ids = [x.partner_id.id for x in partner_banks]
elif transaction.remote_owner:
iban = sepa.IBAN(transaction.remote_account)
if iban.valid:
country_code = iban.country_code
iban = None
country_code = None
if transaction.remote_account:
iban = sepa.IBAN(transaction.remote_account)
if iban and iban.valid:
country_code = iban.countrycode
elif transaction.remote_owner_country_code:
country_code = transaction.remote_owner_country_code
elif hasattr(parser, 'country_code') and parser.country_code:
country_code = parser.country_code
else:
country_code = None
partner_id = get_or_create_partner(
self.pool, cursor, uid, transaction.remote_owner,
transaction.remote_owner_address,
@@ -922,18 +924,18 @@ class banking_import(wizard.interface):
"AND id IN (%s)"
")" % (','.join([str(x) for x in payment_line_ids]))
)
order_ids = cursor.fetchall()
order_ids = [x[0] for x in cursor.fetchall()]
if order_ids:
# Use workflow logics for the orders. Recode logic from
# account_payment, in order to increase efficiency.
payment_order_obj.set_done(cursor, uid, order_ids,
{'state': 'done'}
)
)
wf_service = netsvc.LocalService('workflow')
for id in order_ids:
wf_service.trg_validate(uid, 'payment.order', id, 'done',
cursor
)
)
# Original code. Didn't take workflow logistics into account...
#

View File

@@ -147,27 +147,30 @@ def get_or_create_partner(pool, cursor, uid, name, address, postal_code, city,
filter.append(('zip', 'ilike', postal_code))
address_ids = address_obj.search(cursor, uid, filter)
key = name.lower()
partner_ids = [x.partner_id.id
partner_ids = list(set([x.partner_id.id
for x in address_obj.browse(cursor, uid, address_ids)
# Beware for dangling addresses
if _has_attr(x.partner_id, 'name') and
x.partner_id.name.lower() in key
]
]))
if not partner_ids:
if (not country_code) or not country_id:
country_id = pool.get('res.user').browse(cursor, uid, uid)\
.company_id.partner_id.country.id
partner_id = partner_obj.create(cursor, uid, dict(
name=name, active=True, comment='Generated from Bank Statements Import',
address=[(0,0,{
'street': address and address[0] or '',
'street2': len(address) > 1 and address[1] or '',
'city': city,
'zip': postal_code or '',
'country_id': country_id,
})],
))
user = pool.get('res.user').browse(cursor, uid, uid)
country_id = (user.company_id and user.company_id.partner_id and
user.company_id.partner_id.country and
user.company_id.partner_id.country.id or False)
partner_id = partner_obj.create(
cursor, uid, dict(
name=name, active=True,
comment='Generated from Bank Statements Import',
address=[(0,0,{
'street': address and address[0] or '',
'street2': len(address) > 1 and address[1] or '',
'city': city,
'zip': postal_code or '',
'country_id': country_id,
})],)
)
elif len(partner_ids) > 1:
log.append(
_('More then one possible match found for partner with name %(name)s')
@@ -209,12 +212,12 @@ def get_company_bank_account(pool, cursor, uid, account_number, currency,
# Find matching journal for currency
journal_obj = pool.get('account.journal')
journal_ids = journal_obj.search(cursor, uid, [
('type', '=', 'cash'),
('currency', '=', currency or company.currency_id.code)
('type', '=', 'bank'),
('currency', '=', currency or company.currency_id.name)
])
if not journal_ids and currency == company.currency_id.code:
if not journal_ids and currency == company.currency_id.name:
journal_ids = journal_obj.search(cursor, uid, [
('type', '=', 'cash'), ('currency', '=', False)
('type', '=', 'bank'), ('currency', '=', False)
])
if journal_ids:
criteria.append(('journal_id', 'in', journal_ids))
@@ -295,9 +298,9 @@ def get_or_create_bank(pool, cursor, uid, bic, online=False, code=None,
else:
info = struct(name=name, code=code)
if info.code and ((not online) or not bank_id):
if not online or not bank_id:
bank_id = bank_obj.create(cursor, uid, dict(
code = info.code,
code = info.code or 'UNKNOW',
name = info.name or _('Unknown Bank'),
country = country_id,
bic = bic,
@@ -334,12 +337,18 @@ def create_bank_account(pool, cursor, uid, partner_id,
cursor, uid, partner_id).country
country_code = country.code
country_id = country.id
elif iban.valid:
country_ids = country_obj.search(cursor, uid,
[('code', '=', iban.countrycode)]
)
else:
if iban.valid:
country_ids = country_obj.search(cursor, uid,
[('code', '=', iban.countrycode)]
)
else:
country_ids = country_obj.search(cursor, uid,
[('code', '=', country_code)]
)
country_id = country_ids[0]
account_info = False
if not iban.valid:
# No, try to convert to IBAN
values.state = 'bank'
@@ -355,9 +364,11 @@ def create_bank_account(pool, cursor, uid, partner_id,
bic = account_info.bic
if bic:
values.bank_id = get_or_create_bank(pool, cursor, uid, bic)
values.bank = get_or_create_bank(pool, cursor, uid, bic)[0]
elif bankcode:
else:
if not bankcode:
bankcode = "UNKNOW"
# Try to link bank
bank_obj = pool.get('res.bank')
bank_ids = bank_obj.search(cursor, uid, [
@@ -365,10 +376,10 @@ def create_bank_account(pool, cursor, uid, partner_id,
])
if bank_ids:
# Check BIC on existing banks
values.bank_id = bank_ids[0]
bank = bank_obj.browse(cursor, uid, values.bank_id)
values.bank = bank_ids[0]
bank = bank_obj.browse(cursor, uid, values.bank)
if not bank.bic:
bank_obj.write(cursor, uid, values.bank_id, dict(bic=bic))
bank_obj.write(cursor, uid, values.bank, dict(bic=bic))
else:
# New bank - create
res = struct(country_id=country_id)
@@ -382,7 +393,7 @@ def create_bank_account(pool, cursor, uid, partner_id,
res.code = bankcode
res.name = _('Unknown Bank')
values.bank_id = bank_obj.create(cursor, uid, res)
values.bank = bank_obj.create(cursor, uid, res)
# Create bank account and return
return pool.get('res.partner.bank').create(cursor, uid, values)

View File

@@ -1,25 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record model="payment.type" id="account_banking_nl_clieop.export_clieop_inc">
<record model="payment.mode.type" id="account_banking_nl_clieop.export_clieop_inc">
<field name="name">ClieOp3 Direct Debit Batch</field>
<field name="code">CLIEOPINC</field>
<field name="suitable_bank_types"
<!-- <field name="suitable_bank_types"
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
-->
</record>
<record model="payment.type" id="account_banking_nl_clieop.export_clieop_pay">
<record model="payment.mode.type" id="account_banking_nl_clieop.export_clieop_pay">
<field name="name">ClieOp3 Payment Batch</field>
<field name="code">CLIEOPPAY</field>
<field name="suitable_bank_types"
<!-- <field name="suitable_bank_types"
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
-->
</record>
<record model="payment.type" id="account_banking_nl_clieop.export_clieop_sal">
<record model="payment.mode.type" id="account_banking_nl_clieop.export_clieop_sal">
<field name="name">ClieOp3 Salary Payment Batch</field>
<field name="code">CLIEOPSAL</field>
<field name="suitable_bank_types"
<!-- <field name="suitable_bank_types"
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
-->
</record>
</data>
</openerp>

View File

@@ -196,6 +196,11 @@ class wizard_banking_export_clieop(wizard.interface):
pool = pooler.get_pool(cursor.dbname)
payment_order_obj = pool.get('payment.order')
# Can get id from context. Seems necessary due to lack of support for
# old style wizards in the GTK client
if 'ids' not in data and context.get('payment_order_id', False):
data['ids'] = [context['payment_order_id']]
runs = {}
# Only orders of same type can be combined
payment_orders = payment_order_obj.browse(cursor, uid, data['ids'])
@@ -362,15 +367,16 @@ class wizard_banking_export_clieop(wizard.interface):
def _save_clieop(self, cursor, uid, data, context):
'''
Save the ClieOp: mark all payments in the file as 'sent'.
Save the ClieOp: mark all payments in the file as 'sent', if not a test
'''
pool = pooler.get_pool(cursor.dbname)
clieop_obj = pool.get('banking.export.clieop')
payment_order_obj = pool.get('payment.order')
clieop_file = clieop_obj.write(
cursor, uid, data['file_id'], {'state':'sent'}
)
payment_order_obj.write(cursor, uid, data['ids'], {'state': 'sent'})
if 'test' not in data['form'] or not data['form']['test']:
pool = pooler.get_pool(cursor.dbname)
clieop_obj = pool.get('banking.export.clieop')
payment_order_obj = pool.get('payment.order')
clieop_file = clieop_obj.write(
cursor, uid, data['file_id'], {'state':'sent'}
)
payment_order_obj.action_sent(cursor, uid, data['ids'])
return {'state': 'end'}
states = {
@@ -394,7 +400,7 @@ class wizard_banking_export_clieop(wizard.interface):
'fields': file_fields,
'state': [
('cancel', 'Cancel', 'gtk-cancel'),
('save', 'Save', 'gtk-save'),
('save', 'Finish', 'gtk-ok'),
]
},
},