mirror of
https://github.com/OCA/account-reconcile.git
synced 2025-01-20 12:27:39 +02:00
[IMP] Rebuild of all bank statment stuffs. This commit is more a backup cause it is under hard devs
(lp:c2c-financial-addons/6.1 rev 24.1.17)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Author: Nicolas Bessi
|
# Author: Joel Grand-Guillaume
|
||||||
# Copyright 2011-2012 Camptocamp SA
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -19,4 +19,4 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import parser
|
import statement
|
||||||
47
account_statement_base_completion/__openerp__.py
Normal file
47
account_statement_base_completion/__openerp__.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
{'name': "Bank statement base completion",
|
||||||
|
'version': '1.0',
|
||||||
|
'author': 'Camptocamp',
|
||||||
|
'maintainer': 'Camptocamp',
|
||||||
|
'category': 'Finance',
|
||||||
|
'complexity': 'normal', #easy, normal, expert
|
||||||
|
'depends': ['account_statement_ext'],
|
||||||
|
'description': """
|
||||||
|
The goal of this module is to improve the basic bank statement, help dealing with huge volume of
|
||||||
|
reconciliation by providing basic rules to identify the partner of a bank statement line.
|
||||||
|
|
||||||
|
It will also take care of the chosen profile to make his work.
|
||||||
|
""",
|
||||||
|
'website': 'http://www.camptocamp.com',
|
||||||
|
'init_xml': [],
|
||||||
|
'update_xml': [
|
||||||
|
'statement_view.xml',
|
||||||
|
],
|
||||||
|
'demo_xml': [],
|
||||||
|
'test': [],
|
||||||
|
'installable': True,
|
||||||
|
'images': [],
|
||||||
|
'auto_install': False,
|
||||||
|
'license': 'AGPL-3',
|
||||||
|
'active': False,
|
||||||
|
}
|
||||||
83
account_statement_base_completion/partner.py
Normal file
83
account_statement_base_completion/partner.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
|
||||||
|
# #
|
||||||
|
# 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 osv import fields, osv
|
||||||
|
|
||||||
|
class res_partner(osv.osv):
|
||||||
|
"""Add a bank label on the partner so that we can use it to match
|
||||||
|
this partner when we found this in a statement line."""
|
||||||
|
_inherit = 'res.partner'
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
'bank_statement_label':fields.char('Bank Statement Label', size=100,
|
||||||
|
help="Enter the various label found on your bank statement separated by a ; If \
|
||||||
|
one of this label is include in the bank statement line, the partner will be automatically \
|
||||||
|
filled (as long as you use thi method in your statement profile)."),
|
||||||
|
}
|
||||||
|
|
||||||
|
# def get_partner_from_order_ref(self, cr, uid, order_ref, context=None):
|
||||||
|
# order_obj = self.pool.get('sale.order')
|
||||||
|
# so_id = order_obj.search(cr, uid, [('name', '=', order_ref)], context=context)
|
||||||
|
# if so_id:
|
||||||
|
# so = order_obj.browse(cr, uid, so_id, context=context)[0]
|
||||||
|
# return so.partner_id.id
|
||||||
|
# return False
|
||||||
|
#
|
||||||
|
# def get_partner_from_name(self, cr, uid, partner_name, context=None):
|
||||||
|
# #print 'try to get partner from name', partner_name
|
||||||
|
# return False
|
||||||
|
#
|
||||||
|
# def get_partner_from_email(self, cr, uid, partner_email, context=None):
|
||||||
|
# address_ids = self.pool.get('res.partner.address').search(cr, uid, [['email', '=', partner_email]], context=context)
|
||||||
|
# if address_ids:
|
||||||
|
# partner_id = self.search(cr, uid, [['address', 'in', address_ids]], context=context)
|
||||||
|
# return partner_id and partner_id[0]
|
||||||
|
# return False
|
||||||
|
|
||||||
|
def get_partner_from_label_based_on_bank_statement_label(self, cr, uid, label, context=None):
|
||||||
|
ids = self.search(cr, uid, [['bank_statement_label', '!=', False]], context=context)
|
||||||
|
for partner in self.browse(cr, uid, ids, context=context):
|
||||||
|
for partner_label in partner.bank_statement_label.split(';'):
|
||||||
|
if partner_label in label:
|
||||||
|
return partner.id
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_supplier_partner_from_label_based_on_name(self, cr, uid, label, context=None):
|
||||||
|
supplier_ids = self.search(cr, uid, [['supplier', '=', True]], context=context)
|
||||||
|
for partner in self.browse(cr, uid, supplier_ids, context=context):
|
||||||
|
if partner.name in label:
|
||||||
|
return partner.id
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_partner_account(self, cr, uid, id, amount, context=None):
|
||||||
|
partner = self.browse(cr, uid, id, context=context)
|
||||||
|
if partner.supplier and not partner.customer:
|
||||||
|
return partner.property_account_payable.id
|
||||||
|
if partner.customer and not partner.supplier:
|
||||||
|
return partner.property_account_receivable.id
|
||||||
|
|
||||||
|
if amount >0:
|
||||||
|
return partner.property_account_receivable.id
|
||||||
|
else:
|
||||||
|
return partner.property_account_payable.id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
res_partner()
|
||||||
22
account_statement_base_completion/partner_view.xml
Normal file
22
account_statement_base_completion/partner_view.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record id="bk_view_partner_form" model="ir.ui.view">
|
||||||
|
<field name="name">account_bank_statement_import.view.partner.form</field>
|
||||||
|
<field name="model">res.partner</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="priority">20</field>
|
||||||
|
<field name="inherit_id" ref="account.view_partner_property_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="property_account_payable" position="after">
|
||||||
|
<field name="bank_statement_label"/>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
201
account_statement_base_completion/statement.py
Normal file
201
account_statement_base_completion/statement.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Nicolas Bessi, Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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 tools.translate import _
|
||||||
|
import netsvc
|
||||||
|
logger = netsvc.Logger()
|
||||||
|
from openerp.osv.orm import Model, fields
|
||||||
|
|
||||||
|
class AccountStatementProfil(Model):
|
||||||
|
_inherit = "account.statement.profil"
|
||||||
|
|
||||||
|
_columns={
|
||||||
|
# For now, we don't implement this features, but this would probably be there:
|
||||||
|
# 'auto_completion': fields.text('Auto Completion'),
|
||||||
|
# 'transferts_account_id':fields.many2one('account.account', 'Transferts Account'),
|
||||||
|
|
||||||
|
'rule_ids':fields.many2many('account.statement.completion.rule',
|
||||||
|
rel='account_statement_rule_statement_profile_to_rel',
|
||||||
|
'profile_id','rule_id',
|
||||||
|
'Related statement profiles'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def find_partner_by_rules(self, cr, uid, ids, field_value, context=None):
|
||||||
|
"""This method will execute all rules, in their sequence order,
|
||||||
|
to match a partner for the given statement.line and return his id."""
|
||||||
|
if not context:
|
||||||
|
context={}
|
||||||
|
partner_id = False
|
||||||
|
for profile in self.browse(cr, uid, ids, context=context):
|
||||||
|
for rule in profile.rule_ids:
|
||||||
|
method_to_call = getattr(rule, rule.function_to_call)
|
||||||
|
partner_id = method_to_call(cr,uid,field_value,context)
|
||||||
|
if partner_id:
|
||||||
|
return partner_id
|
||||||
|
return partner_id
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStatementCompletionRule(Model):
|
||||||
|
"""This will represent all the completion method that we can have to
|
||||||
|
fullfill the bank statement. You'll be able to extend them in you own module
|
||||||
|
and choose those to apply for every statement profile."""
|
||||||
|
|
||||||
|
_name = "account.statement.completion.rule"
|
||||||
|
_order = "sequence asc"
|
||||||
|
|
||||||
|
_get_functions = [('get_from_label_and_partner_field', 'From line label (based on partner field)'),\
|
||||||
|
('in', 'External -> OpenERP'), ('out', 'External <- OpenERP')]
|
||||||
|
|
||||||
|
_columns={
|
||||||
|
'sequence': fields.integer('Sequence'),
|
||||||
|
'name': fields.char('Name')
|
||||||
|
'profile_ids':fields.many2many('account.statement.profil',
|
||||||
|
rel='account_statement_rule_statement_profile_to_rel',
|
||||||
|
'rule_id', 'profile_id',
|
||||||
|
'Related statement profiles'),
|
||||||
|
'function_to_call': fields.selection(_get_functions, 'Type'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_from_label_and_partner_field(self, cr, uid, field_value, context=None):
|
||||||
|
"""Match the partner based on the label field of the statement line
|
||||||
|
and the text defined in the 'bank_statement_label' field of the partner.
|
||||||
|
Remember that we can have values separated with ;"""
|
||||||
|
partner_obj = self.pool.get('res.partner')
|
||||||
|
ids = partner_obj.search(cr, uid, [['bank_statement_label', '!=', False]], context=context)
|
||||||
|
for partner in self.browse(cr, uid, ids, context=context):
|
||||||
|
for partner_label in partner.bank_statement_label.split(';'):
|
||||||
|
if partner_label in field_value:
|
||||||
|
return partner.id
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_from_label_and_partner_name(self, cr, uid, field_value, context=None):
|
||||||
|
"""Match the partner based on the label field of the statement line
|
||||||
|
and the name of the partner."""
|
||||||
|
supplier_ids = self.search(cr, uid, [['supplier', '=', True]], context=context)
|
||||||
|
sql = """SELECT id FROM res_partner WHERE name ilike """
|
||||||
|
for partner in self.browse(cr, uid, supplier_ids, context=context):
|
||||||
|
if partner.name in label:
|
||||||
|
return partner.id
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStatementLine(Model):
|
||||||
|
"""Add sparse field on the statement line to allow to store all the
|
||||||
|
bank infos that are given by an office. You can then add you own in your
|
||||||
|
module."""
|
||||||
|
_inherit = "account.bank.statement.line"
|
||||||
|
|
||||||
|
_columns={
|
||||||
|
# 'email_address': fields.char('Email', size=64),
|
||||||
|
# 'order_ref': fields.char('Order Ref', size=64),
|
||||||
|
# 'partner_name': fields.char('Partner Name', size=64),
|
||||||
|
#
|
||||||
|
# Only label for a start, but other module can add their own
|
||||||
|
'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', help="Used by completion and import system."),
|
||||||
|
'label': fields.sparse(type='char', string='Label',
|
||||||
|
serialization_field='additionnal_bank_fields'),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def auto_complete_line(self, cr, uid, line, context=None):
|
||||||
|
res={}
|
||||||
|
if not line.partner_id or line.account_id.id ==1:
|
||||||
|
partner_obj = self.pool.get('res.partner')
|
||||||
|
partner_id=False
|
||||||
|
if line.order_ref:
|
||||||
|
partner_id = partner_obj.get_partner_from_order_ref(cr, uid, line.order_ref, context=context)
|
||||||
|
if not partner_id and line.email_address:
|
||||||
|
partner_id = partner_obj.get_partner_from_email(cr, uid, line.email_address, context=context)
|
||||||
|
if not partner_id and line.partner_name:
|
||||||
|
partner_id = partner_obj.get_partner_from_name(cr, uid, line.partner_name, context=context)
|
||||||
|
if not partner_id and line.label:
|
||||||
|
partner_id = partner_obj.get_partner_from_label_based_on_bank_statement_label(cr, uid, line.label, context=context)
|
||||||
|
if partner_id:
|
||||||
|
res = {'partner_id': partner_id}
|
||||||
|
if context['auto_completion']:
|
||||||
|
#Build the space for expr
|
||||||
|
space = {
|
||||||
|
'self':self,
|
||||||
|
'cr':cr,
|
||||||
|
'uid':uid,
|
||||||
|
'line': line,
|
||||||
|
'res': res,
|
||||||
|
'context':context,
|
||||||
|
}
|
||||||
|
exec context['auto_completion'] in space
|
||||||
|
if space.get('result', False):
|
||||||
|
res.update(space['result'])
|
||||||
|
return res
|
||||||
|
|
||||||
|
class A(object):
|
||||||
|
def xx_toto():
|
||||||
|
print 'toto'
|
||||||
|
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
funcs = ['yy_toto', 'xx_toto']
|
||||||
|
for i in funcs:
|
||||||
|
if hasattr(a, i):
|
||||||
|
to_call = getattr(a, i)
|
||||||
|
to_call()
|
||||||
|
else:
|
||||||
|
raise NameError('blblblb')
|
||||||
|
|
||||||
|
class AccountBankSatement(Model):
|
||||||
|
"""We add a basic button and stuff to support the auto-completion
|
||||||
|
of the bank statement once line have been imported or manually entred.
|
||||||
|
"""
|
||||||
|
_inherit = "account.bank.statement"
|
||||||
|
|
||||||
|
|
||||||
|
def button_auto_completion(self, cr, uid, ids, context=None):
|
||||||
|
if not context:
|
||||||
|
context={}
|
||||||
|
stat_line_obj = self.pool.get('account.bank.statement.line')
|
||||||
|
for stat in self.browse(cr, uid, ids, context=context):
|
||||||
|
ctx = context.copy()
|
||||||
|
if stat.bank_statement_import_id:
|
||||||
|
ctx['partner_id'] = stat.bank_statement_import_id.partner_id.id
|
||||||
|
ctx['transferts_account_id'] = stat.bank_statement_import_id.transferts_account_id.id
|
||||||
|
ctx['credit_account_id'] = stat.bank_statement_import_id.credit_account_id.id
|
||||||
|
ctx['fee_account_id'] = stat.bank_statement_import_id.fee_account_id.id
|
||||||
|
ctx['auto_completion'] = stat.bank_statement_import_id.auto_completion
|
||||||
|
for line in stat.line_ids:
|
||||||
|
vals = stat_line_obj.auto_complete_line(cr, uid, line, context=ctx)
|
||||||
|
if not line.ref and not vals.get('ref', False):
|
||||||
|
vals['ref'] = stat.name
|
||||||
|
if vals:
|
||||||
|
stat_line_obj.write(cr, uid, line.id, vals, context=ctx)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def auto_confirm(self, cr, uid, ids, context=None):
|
||||||
|
if not context:
|
||||||
|
context={}
|
||||||
|
ok=True
|
||||||
|
for stat in self.browse(cr, uid, ids, context=context):
|
||||||
|
for line in stat.line_ids:
|
||||||
|
if not line.partner_id or line.account_id.id == 1:
|
||||||
|
ok=False
|
||||||
|
continue
|
||||||
|
if ok:
|
||||||
|
self.button_confirm(cr, uid, [stat.id], context=context)
|
||||||
|
return True
|
||||||
34
account_statement_base_completion/statement_view.xml
Normal file
34
account_statement_base_completion/statement_view.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record id="bank_statement_view_form" model="ir.ui.view">
|
||||||
|
<field name="name">account_bank_statement_import_base.bank_statement.view_form</field>
|
||||||
|
<field name="model">account.bank.statement</field>
|
||||||
|
<field name="inherit_id" ref="account.view_bank_statement_form" />
|
||||||
|
<field eval="16" name="priority"/>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<data>
|
||||||
|
<xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='ref']" position="after">
|
||||||
|
<!-- <field name="partner_name" />
|
||||||
|
<field name="order_ref" />
|
||||||
|
<field name="email_address" /> -->
|
||||||
|
<field name="label" />
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="/form/group[2]" position="attributes">
|
||||||
|
<attribute name="col">10</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="/form/group/field[@name='balance_end']" position="after">
|
||||||
|
<button name="button_auto_completion" string="Auto Completion" type="object" colspan="1"/>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Author Nicolas Bessi. Copyright Camptocamp SA
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU Affero General Public License as
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
# (at your option) any later version.
|
# License, or (at your option) any later version.
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU Affero General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import import_statement
|
|
||||||
|
import statement
|
||||||
46
account_statement_base_import/__openerp__.py
Normal file
46
account_statement_base_import/__openerp__.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
{'name': "Bank statement easy import",
|
||||||
|
'version': '1.0',
|
||||||
|
'author': 'Camptocamp',
|
||||||
|
'maintainer': 'Camptocamp',
|
||||||
|
'category': 'Finance',
|
||||||
|
'complexity': 'normal', #easy, normal, expert
|
||||||
|
'depends': ['account_statement_ext','account_statement_base_completion'],
|
||||||
|
'description': """
|
||||||
|
The goal of this module is bring basic method and fields on bank statement to deal with
|
||||||
|
the importation of different bank and offices.
|
||||||
|
|
||||||
|
|
||||||
|
""",
|
||||||
|
'website': 'http://www.camptocamp.com',
|
||||||
|
'init_xml': [],
|
||||||
|
'update_xml': [
|
||||||
|
],
|
||||||
|
'demo_xml': [],
|
||||||
|
'test': [],
|
||||||
|
'installable': True,
|
||||||
|
'images': [],
|
||||||
|
'auto_install': False,
|
||||||
|
'license': 'AGPL-3',
|
||||||
|
'active': False,
|
||||||
|
}
|
||||||
81
account_statement_base_import/statement.py
Normal file
81
account_statement_base_import/statement.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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 tools.translate import _
|
||||||
|
import datetime
|
||||||
|
import netsvc
|
||||||
|
logger = netsvc.Logger()
|
||||||
|
from openerp.osv.orm import Model, fields
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStatementProfil(Model):
|
||||||
|
_inherit = "account.statement.profil"
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
'launch_import_completion': fields.boolean("Launch completion after import",
|
||||||
|
help="Tic that box to automatically launch the completion on each imported\
|
||||||
|
file using this profile."),
|
||||||
|
'last_import_date': fields.date("Last Import Date"),
|
||||||
|
'rec_log': fields.text('log', readonly=True),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def launch_import_bank_statement(self, cr, uid, ids, context=None):
|
||||||
|
stat_obj = self.pool.get('account.bank.statement')
|
||||||
|
for id in ids:
|
||||||
|
logger = netsvc.Logger()
|
||||||
|
res = self.action_import_bank_statement(cr, uid, id, conteaccount_xt)
|
||||||
|
#autocomplete bank statement
|
||||||
|
stat_obj.button_auto_completion(cr, uid, res['crids'], context=context)
|
||||||
|
stat_obj.auto_confirm(cr, uid, res['crids'], context=context)
|
||||||
|
log = self.read(cr, uid, id, ['rec_log'], context=context)['rec_log']
|
||||||
|
log_line = log and log.split("\n") or []
|
||||||
|
log_line[0:0] = [datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ' : ' + str(len(res['crids'])) + _(' bank statement have been imported and ' + str(len(res['exist_ids'])) + _(' bank statement already exist'))]
|
||||||
|
log = "\n".join(log_line)
|
||||||
|
self.write(cr, uid, id, {'rec_log' : log}, context=context)
|
||||||
|
logger.notifyChannel('banck statement import', netsvc.LOG_INFO, "%s bank statement have been imported and %s bank statement already exist"%(len(res['crids']), len(res['exist_ids'])))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def action_import_bank_statement(self, cr, uid, id, context=None):
|
||||||
|
'''not implemented in this module'''
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def open_bank_statement(self, cr, uid, ids, context):
|
||||||
|
task = self.browse(cr, uid, ids, context=context)[0]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'name': 'Bank ',
|
||||||
|
'view_type': 'form',
|
||||||
|
'view_mode': 'form',
|
||||||
|
'view_id': [252],
|
||||||
|
'res_model': self._name,
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'nodestroy': True,
|
||||||
|
'target': 'current',
|
||||||
|
'res_id': self.read(cr, uid, ids, ['bank_statement_ids'],context=context)[0]['bank_statement_ids'],
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountBankSatement(Model):
|
||||||
|
|
||||||
|
_inherit = "account.bank.statement"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
47
account_statement_base_import/statement_view.xml
Normal file
47
account_statement_base_import/statement_view.xml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="statement_importer_view_form" model="ir.ui.view">
|
||||||
|
<field name="name">account.statement.profil.view</field>
|
||||||
|
<field name="model">account.statement.profil</field>
|
||||||
|
<field name="inherit_id" ref="account_statement_ext.statement_importer_view_form"/>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="bank_statement_prefix" position="after">
|
||||||
|
<separator colspan="4" String="Import related infos"/>
|
||||||
|
<field name="launch_import_completion"/>
|
||||||
|
<field name="last_import_date"/>
|
||||||
|
<button icon="gtk-ok" name="launch_import_bank_statement" colspan = "2" string="Import Bank Statement" type="object"/>
|
||||||
|
<separator colspan="4" String="Import Logs"/>
|
||||||
|
<field name="rec_log" colspan="4" nolabel="1"/>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- To port -->
|
||||||
|
|
||||||
|
<!-- <record id="action_bank_statement_import" model="ir.actions.act_window">
|
||||||
|
<field name="name">account bank statement import</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">account.bank.statement.import</field>
|
||||||
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="context">{'wizard_object' : 'account.bank.statement.import', 'function' : 'action_import_bank_statement', 'object_link' : 'account.bank.statement.import' }</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<menuitem action="action_bank_statement_import" id="menu_account_bank_import" parent="account.menu_finance"/>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="ir_action_create_scheduler_in_easy_reconcile" model="ir.values">
|
||||||
|
<field name="key2">client_action_multi</field>
|
||||||
|
<field name="model">account.bank.statement.import</field>
|
||||||
|
<field name="name">Create a Scheduler</field>
|
||||||
|
<field eval="'ir.actions.act_window,%d'%ref('base_scheduler_creator.action_scheduler_creator_wizard')" name="value"/>
|
||||||
|
<field eval="True" name="object"/>
|
||||||
|
</record> -->
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
@@ -23,3 +23,4 @@ import file_parser
|
|||||||
import wizard
|
import wizard
|
||||||
import statement
|
import statement
|
||||||
import report
|
import report
|
||||||
|
import account
|
||||||
@@ -27,15 +27,16 @@
|
|||||||
'complexity': 'normal', #easy, normal, expert
|
'complexity': 'normal', #easy, normal, expert
|
||||||
'depends': ['base_transaction_id'],
|
'depends': ['base_transaction_id'],
|
||||||
'description': """
|
'description': """
|
||||||
The goal of this module is to help dealing with huge volume of reconciliation through
|
The goal of this module is to improve the basic bank statement, help dealing with huge volume of
|
||||||
payment offices like Paypal, Lazer, Visa, Amazon and so on. It's mostly used for
|
reconciliation through payment offices like Paypal, Lazer, Visa, Amazon and so on.
|
||||||
E-commerce but can be usefule for other use cases as it introduce a notion of profil
|
|
||||||
on the bank statement to have more control on the generated entries.
|
It will be mostly used for E-commerce but can be usefule for other use cases as it introduce a
|
||||||
|
notion of profil on the bank statement to have more control on the generated entries. It will
|
||||||
|
be the base for all new features developped to improve the reconciliation process.
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
1) This module improves the bank statement that allow and you to import your bank transactions with
|
1) This module improves the bank statement that allow and you to define profile for each
|
||||||
a standard .csv or .xls file (you'll find it in the 'data' folder). You can now define profile for each
|
|
||||||
Office or Bank that will generate the entries based on some criteria. You can setup:
|
Office or Bank that will generate the entries based on some criteria. You can setup:
|
||||||
|
|
||||||
- Account commission and partner relation
|
- Account commission and partner relation
|
||||||
@@ -51,15 +52,19 @@
|
|||||||
|
|
||||||
4) Remove the period on the bank statement, and compute it for each line based on their date instead.
|
4) Remove the period on the bank statement, and compute it for each line based on their date instead.
|
||||||
|
|
||||||
5) Provide a standard import format to create and fullfill a bank statement from a .csv or .xls file. For
|
5) Cancelling a bank statement is much more easy and will cancel all related entries, unreconcile them,
|
||||||
|
and finally delete it.
|
||||||
|
|
||||||
|
6) Add the ID in entries view so that you can easily filter on a statement ID to reconcile all related
|
||||||
|
entries at once (e.g. one statement (ID 100) for paypal on an intermediate account, and then another for
|
||||||
|
the bank on the bank account. You can then manually reconcile all the line from the first one with
|
||||||
|
one line of the second by finding them through the statement ID.)
|
||||||
|
|
||||||
|
|
||||||
""",
|
""",
|
||||||
'website': 'http://www.camptocamp.com',
|
'website': 'http://www.camptocamp.com',
|
||||||
'init_xml': [],
|
'init_xml': [],
|
||||||
'update_xml': [
|
'update_xml': [
|
||||||
'statement_view.xml',
|
'statement_view.xml',
|
||||||
'wizard/import_statement_view.xml',
|
|
||||||
'report/bank_statement_webkit_header.xml',
|
'report/bank_statement_webkit_header.xml',
|
||||||
'report.xml',
|
'report.xml',
|
||||||
],
|
],
|
||||||
|
|||||||
38
account_statement_ext/account.py
Normal file
38
account_statement_ext/account.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
import netsvc
|
||||||
|
logger = netsvc.Logger()
|
||||||
|
from openerp.osv.orm import Model, fields
|
||||||
|
|
||||||
|
class account_move(osv.osv):
|
||||||
|
_inherit='account.move'
|
||||||
|
|
||||||
|
def unlink(self, cr, uid, ids, context=None):
|
||||||
|
"""Delete the reconciliation when we delete the moves. This
|
||||||
|
allow an easier way of cancelling the bank statement."""
|
||||||
|
for move in self.browse(cr, uid, ids, context=context):
|
||||||
|
for move_line in move.line_id:
|
||||||
|
if move_line.reconcile_id:
|
||||||
|
move_line.reconcile_id.unlink(context=context)
|
||||||
|
return super(account_move, self).unlink(cr, uid, ids, context=context)
|
||||||
|
account_move()
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
"transaction_id";"date";"amount";"commission_amount";"label"
|
|
||||||
50969286;2011-03-07 13:45:14;118.4;-11.84;"label a"
|
|
||||||
51065326;2011-03-05 13:45:14;189;-15.12;"label b"
|
|
||||||
51179306;2011-03-02 17:45:14;189;-15.12;"label c"
|
|
||||||
|
Binary file not shown.
@@ -1,131 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright Camptocamp SA
|
|
||||||
# Author Nicolas Bessi
|
|
||||||
# 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/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
Parser for csv or xml for file containing credit transfert data from
|
|
||||||
financial institure as VISA
|
|
||||||
"""
|
|
||||||
|
|
||||||
from tools.translate import _
|
|
||||||
import base64
|
|
||||||
import csv
|
|
||||||
import tempfile
|
|
||||||
import datetime
|
|
||||||
try:
|
|
||||||
import xlrd
|
|
||||||
except:
|
|
||||||
raise Exception(_('Please install python lib xlrd'))
|
|
||||||
|
|
||||||
def UnicodeDictReader(utf8_data, **kwargs):
|
|
||||||
csv_reader = csv.DictReader(utf8_data, **kwargs)
|
|
||||||
for row in csv_reader:
|
|
||||||
yield dict([(key, unicode(value, 'utf-8')) for key, value in row.iteritems()])
|
|
||||||
|
|
||||||
# TODO extract into a lib helper module
|
|
||||||
class FileParser(object):
|
|
||||||
def __init__(self, filebuffer, keys_to_validate=None, decode_base_64=True, ftype='csv'):
|
|
||||||
if ftype in ('csv', 'xls'):
|
|
||||||
self.ftype = ftype
|
|
||||||
else:
|
|
||||||
raise Exception(_('Invalide file type %s. please use csv or xls') % (ftype))
|
|
||||||
self.keys_to_validate = keys_to_validate
|
|
||||||
self.decode_base_64 = decode_base_64
|
|
||||||
if filebuffer:
|
|
||||||
self.filebuffer = filebuffer
|
|
||||||
else:
|
|
||||||
raise Exception(_('No buffer file'))
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
"launch parsing of csv or xls"
|
|
||||||
if self.decode_base_64:
|
|
||||||
self._decode_64b_stream()
|
|
||||||
res = None
|
|
||||||
if self.ftype == 'csv':
|
|
||||||
res = self.parse_csv()
|
|
||||||
else:
|
|
||||||
res = self.parse_xls()
|
|
||||||
if self.keys_to_validate:
|
|
||||||
self._validate_column(res, self.keys_to_validate)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _decode_64b_stream(self):
|
|
||||||
self.filebuffer = base64.b64decode(self.filebuffer)
|
|
||||||
return self.filebuffer
|
|
||||||
|
|
||||||
def _validate_column(self, array_of_dict, cols):
|
|
||||||
parsed_cols = array_of_dict[0].keys()
|
|
||||||
for col in cols:
|
|
||||||
if col not in parsed_cols:
|
|
||||||
raise Exception(_('col %s not present in file') % (col))
|
|
||||||
|
|
||||||
def parse_csv(self, delimiter=';'):
|
|
||||||
"return an array of dict from csv file"
|
|
||||||
csv_file = tempfile.NamedTemporaryFile()
|
|
||||||
csv_file.write(self.filebuffer)
|
|
||||||
# We ensure that cursor is at beginig of file
|
|
||||||
csv_file.seek(0)
|
|
||||||
reader = UnicodeDictReader(
|
|
||||||
open(csv_file.name).readlines(),
|
|
||||||
delimiter=delimiter
|
|
||||||
)
|
|
||||||
return [x for x in reader]
|
|
||||||
|
|
||||||
def parse_xls(self):
|
|
||||||
"return an array of dict from csv file"
|
|
||||||
wb_file = tempfile.NamedTemporaryFile()
|
|
||||||
wb_file.write(self.filebuffer)
|
|
||||||
# We ensure that cursor is at beginig of file
|
|
||||||
wb_file.seek(0)
|
|
||||||
wb = xlrd.open_workbook(wb_file.name)
|
|
||||||
sheet = wb.sheet_by_index(0)
|
|
||||||
header = sheet.row_values(0)
|
|
||||||
res = []
|
|
||||||
for rownum in range(1, sheet.nrows):
|
|
||||||
res.append(dict(zip(header, sheet.row_values(rownum))))
|
|
||||||
try:
|
|
||||||
wb_file.close()
|
|
||||||
except Exception, e:
|
|
||||||
pass #file is allready closed
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _from_csv(self, result_set, conversion_rules):
|
|
||||||
for line in result_set:
|
|
||||||
for rule in conversion_rules:
|
|
||||||
if conversion_rules[rule] == datetime.datetime:
|
|
||||||
date_string = line[rule].split(' ')[0]
|
|
||||||
line[rule] = datetime.datetime.strptime(date_string,
|
|
||||||
'%Y-%m-%d')
|
|
||||||
else:
|
|
||||||
line[rule] = conversion_rules[rule](line[rule])
|
|
||||||
return result_set
|
|
||||||
|
|
||||||
def _from_xls(self, result_set, conversion_rules):
|
|
||||||
for line in result_set:
|
|
||||||
for rule in conversion_rules:
|
|
||||||
if conversion_rules[rule] == datetime.datetime:
|
|
||||||
t_tuple = xlrd.xldate_as_tuple(line[rule], 1)
|
|
||||||
line[rule] = datetime.datetime(*t_tuple)
|
|
||||||
else:
|
|
||||||
line[rule] = conversion_rules[rule](line[rule])
|
|
||||||
return result_set
|
|
||||||
|
|
||||||
def cast_rows(self, result_set, conversion_rules):
|
|
||||||
func = getattr(self, '_from_%s'%(self.ftype))
|
|
||||||
return func(result_set, conversion_rules)
|
|
||||||
@@ -27,13 +27,16 @@ logger = netsvc.Logger()
|
|||||||
from openerp.osv.orm import Model, fields
|
from openerp.osv.orm import Model, fields
|
||||||
|
|
||||||
class AccountStatementProfil(Model):
|
class AccountStatementProfil(Model):
|
||||||
|
"""A Profile will contain all infos related to the type of
|
||||||
|
bank statement, and related generated entries. It define the
|
||||||
|
journal to use, the partner and commision account and so on."""
|
||||||
_name = "account.statement.profil"
|
_name = "account.statement.profil"
|
||||||
_description = "Statement Profil"
|
_description = "Statement Profil"
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Name', size=128, required=True),
|
'name': fields.char('Name', size=128, required=True),
|
||||||
'partner_id': fields.many2one('res.partner',
|
'partner_id': fields.many2one('res.partner',
|
||||||
'Credit insitute partner',
|
'Bank/Payment Office partner',
|
||||||
help="Put a partner if you want to have it on the commission move (and optionaly\
|
help="Put a partner if you want to have it on the commission move (and optionaly\
|
||||||
on the counterpart of the intermediate/banking move if you tic the corresponding checkbox)."),
|
on the counterpart of the intermediate/banking move if you tic the corresponding checkbox)."),
|
||||||
'journal_id': fields.many2one('account.journal',
|
'journal_id': fields.many2one('account.journal',
|
||||||
@@ -57,6 +60,10 @@ class AccountStatementProfil(Model):
|
|||||||
help="Tic that box if you want OpenERP to control the start/end balance\
|
help="Tic that box if you want OpenERP to control the start/end balance\
|
||||||
before confirming a bank statement. If don't ticked, no balance control will be done."
|
before confirming a bank statement. If don't ticked, no balance control will be done."
|
||||||
),
|
),
|
||||||
|
'bank_statement_prefix': fields.char('Bank Statement Prefix', size=32),
|
||||||
|
'bank_statement_ids': fields.one2many('account.bank.statement', 'profile_id', 'Bank Statement Imported'),
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {}
|
_defaults = {}
|
||||||
@@ -73,43 +80,40 @@ class AccountStatementProfil(Model):
|
|||||||
|
|
||||||
|
|
||||||
class AccountBankSatement(Model):
|
class AccountBankSatement(Model):
|
||||||
"""A kind of bank statement for intermediate move between customer and real bank, used
|
"""We improve the bank statement class mostly for :
|
||||||
for manageing check, payment office like paypal or marketplace like amazon.
|
- Removing the period and compute it from the date of each line.
|
||||||
We inherit account.bank.statement because it's a very close object with only some
|
- Allow to remove the balance check depending on the chosen profil
|
||||||
difference. But we want some method to be completely different, so we create a new object."""
|
- Report errors on confirmation all at once instead of crashing onr by one
|
||||||
|
- Add a profil notion that can change the generated entries on statement
|
||||||
|
confirmation.
|
||||||
|
For this, we'll had to override quite some long method and we'll need to maintain
|
||||||
|
them up to date. Changes are point up by '#Chg' comment."""
|
||||||
|
|
||||||
_inherit = "account.bank.statement"
|
_inherit = "account.bank.statement"
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'import_config_id': fields.many2one('account.statement.profil',
|
'profile_id': fields.many2one('account.statement.profil',
|
||||||
'Profil', required=True, states={'draft': [('readonly', False)]}),
|
'Profil', required=True, states={'draft': [('readonly', False)]}),
|
||||||
'credit_partner_id': fields.related(
|
'credit_partner_id': fields.related(
|
||||||
'import_config_id',
|
'profile_id',
|
||||||
'partner_id',
|
'partner_id',
|
||||||
type='many2one',
|
type='many2one',
|
||||||
relation='res.partner',
|
relation='res.partner',
|
||||||
string='Financial Partner',
|
string='Financial Partner',
|
||||||
store=True, readonly=True),
|
store=True, readonly=True),
|
||||||
'balance_check': fields.related(
|
'balance_check': fields.related(
|
||||||
'import_config_id',
|
'profile_id',
|
||||||
'balance_check',
|
'balance_check',
|
||||||
type='boolean',
|
type='boolean',
|
||||||
string='Balance check',
|
string='Balance check',
|
||||||
store=True, readonly=True),
|
store=True, readonly=True),
|
||||||
'journal_id': fields.related(
|
'journal_id': fields.related(
|
||||||
'import_config_id',
|
'profile_id',
|
||||||
'journal_id',
|
'journal_id',
|
||||||
type='many2one',
|
type='many2one',
|
||||||
relation='account.journal',
|
relation='account.journal',
|
||||||
string='Journal',
|
string='Journal',
|
||||||
store=True, readonly=True),
|
store=True, readonly=True),
|
||||||
# 'line_ids': fields.one2many('account.bank.statement.line',
|
|
||||||
# 'statement_id', 'Statement lines',
|
|
||||||
# states={'confirm':[('readonly', True)]}),
|
|
||||||
# 'move_line_ids': fields.one2many('account.move.line', 'statement_treasury_id',
|
|
||||||
# 'Entry lines', states={'confirm':[('readonly',True)]}),
|
|
||||||
# Redefine this field to avoid his computation (it is a function field on bank statement)
|
|
||||||
# 'balance_end': fields.dummy(string="Computed Balance"),
|
|
||||||
'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True),
|
'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,15 +124,15 @@ class AccountBankSatement(Model):
|
|||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
"""Need to pass the journal_id in vals anytime because of account.cash.statement
|
"""Need to pass the journal_id in vals anytime because of account.cash.statement
|
||||||
that need it."""
|
that need it."""
|
||||||
if 'import_config_id' in vals:
|
if 'profile_id' in vals:
|
||||||
profil_obj = self.pool.get('account.statement.profil')
|
profil_obj = self.pool.get('account.statement.profil')
|
||||||
profile = profil_obj.browse(cr,uid,vals['import_config_id'],context)
|
profile = profil_obj.browse(cr,uid,vals['profile_id'],context)
|
||||||
vals['journal_id'] = profile.journal_id.id
|
vals['journal_id'] = profile.journal_id.id
|
||||||
return super(AccountBankSatement, self).create(cr, uid, vals, context=context)
|
return super(AccountBankSatement, self).create(cr, uid, vals, context=context)
|
||||||
|
|
||||||
def _get_period(self, cursor, uid, date, context=None):
|
def _get_period(self, cursor, uid, date, context=None):
|
||||||
'''
|
'''
|
||||||
Find matching period for date, used in thestatement line creation.
|
Find matching period for date, used in the statement line creation.
|
||||||
'''
|
'''
|
||||||
period_obj = self.pool.get('account.period')
|
period_obj = self.pool.get('account.period')
|
||||||
periods = period_obj.find(cursor, uid, dt=date, context=context)
|
periods = period_obj.find(cursor, uid, dt=date, context=context)
|
||||||
@@ -154,6 +158,22 @@ class AccountBankSatement(Model):
|
|||||||
(_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
|
(_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def button_cancel(self, cr, uid, ids, context={}):
|
||||||
|
"""We cancel the related move, delete them and finally put the
|
||||||
|
statement in draft state."""
|
||||||
|
done = []
|
||||||
|
for st in self.browse(cr, uid, ids, context=context):
|
||||||
|
if st.state=='draft':
|
||||||
|
continue
|
||||||
|
ids = []
|
||||||
|
for line in st.line_ids:
|
||||||
|
for move in line.move_ids:
|
||||||
|
move.button_cancel(context=context)
|
||||||
|
move.unlink(context=context)
|
||||||
|
done.append(st.id)
|
||||||
|
self.write(cr, uid, done, {'state':'draft'}, context=context)
|
||||||
|
return True
|
||||||
|
|
||||||
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
|
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
|
||||||
"""Override a large portion of the code to compute the periode for each line instead of
|
"""Override a large portion of the code to compute the periode for each line instead of
|
||||||
taking the period of the whole statement.
|
taking the period of the whole statement.
|
||||||
@@ -165,7 +185,7 @@ class AccountBankSatement(Model):
|
|||||||
- If partner_id is set, we'll us it for the commission (when imported throufh the wizard)
|
- If partner_id is set, we'll us it for the commission (when imported throufh the wizard)
|
||||||
- If partner_id is set and force_partner_on_bank is ticked, we'll let the partner of each line
|
- If partner_id is set and force_partner_on_bank is ticked, we'll let the partner of each line
|
||||||
for the debit line, but we'll change it on the credit move line for the choosen partner_id
|
for the debit line, but we'll change it on the credit move line for the choosen partner_id
|
||||||
=> This will ease the reconsiliation process with the bank as the partner will match the bank
|
=> This will ease the reconciliation process with the bank as the partner will match the bank
|
||||||
statement line
|
statement line
|
||||||
"""
|
"""
|
||||||
if context is None:
|
if context is None:
|
||||||
@@ -246,8 +266,8 @@ class AccountBankSatement(Model):
|
|||||||
amount_currency = st_line.amount
|
amount_currency = st_line.amount
|
||||||
currency_id = st.currency.id
|
currency_id = st.currency.id
|
||||||
# GET THE RIGHT PARTNER ACCORDING TO THE CHOSEN PROFIL # Chg
|
# GET THE RIGHT PARTNER ACCORDING TO THE CHOSEN PROFIL # Chg
|
||||||
if st.import_config_id.force_partner_on_bank: # Chg
|
if st.profile_id.force_partner_on_bank: # Chg
|
||||||
bank_parrtner_id = st.import_config_id.partner_id.id # Chg
|
bank_parrtner_id = st.profile_id.partner_id.id # Chg
|
||||||
else: # Chg
|
else: # Chg
|
||||||
bank_parrtner_id = ((st_line.partner_id) and st_line.partner_id.id) or False # Chg
|
bank_parrtner_id = ((st_line.partner_id) and st_line.partner_id.id) or False # Chg
|
||||||
|
|
||||||
@@ -280,16 +300,19 @@ class AccountBankSatement(Model):
|
|||||||
account_move_obj.post(cr, uid, [move_id], context=context)
|
account_move_obj.post(cr, uid, [move_id], context=context)
|
||||||
return move_id
|
return move_id
|
||||||
|
|
||||||
def _get_st_number_period(self, cr, uid, date, journal_sequence_id):
|
def _get_st_number_period_profil(self, cr, uid, date, profile_id, journal_sequence_id):
|
||||||
"""Retrieve the name of bank statement from sequence, according to the period
|
"""Retrieve the name of bank statement from sequence, according to the period
|
||||||
corresponding to the date passed in args"""
|
corresponding to the date passed in args. Add a prefix if set in the profil."""
|
||||||
year = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id
|
year = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id
|
||||||
|
profile = self.pool.get('account.statement.profil').browse(cr,uid, profile_id)
|
||||||
c = {'fiscalyear_id': year}
|
c = {'fiscalyear_id': year}
|
||||||
obj_seq = self.pool.get('ir.sequence')
|
obj_seq = self.pool.get('ir.sequence')
|
||||||
if journal_sequence_id:
|
if journal_sequence_id:
|
||||||
st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c)
|
st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c)
|
||||||
else:
|
else:
|
||||||
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
|
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
|
||||||
|
if profile.bank_statement_prefix:
|
||||||
|
st_number = profile.bank_statement_prefix + st_number
|
||||||
return st_number
|
return st_number
|
||||||
|
|
||||||
def button_confirm_bank(self, cr, uid, ids, context=None):
|
def button_confirm_bank(self, cr, uid, ids, context=None):
|
||||||
@@ -319,12 +342,7 @@ class AccountBankSatement(Model):
|
|||||||
else:
|
else:
|
||||||
# Begin Changes
|
# Begin Changes
|
||||||
seq_id = st.journal_id.sequence_id and st.journal_id.sequence_id.id or False
|
seq_id = st.journal_id.sequence_id and st.journal_id.sequence_id.id or False
|
||||||
st_number = self._get_st_number_period(cr, uid, st.date, seq_id)
|
st_number = self._get_st_number_period_profil(cr, uid, st.date, st.profile_id.id, seq_id)
|
||||||
# c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}
|
|
||||||
# if st.journal_id.sequence_id:
|
|
||||||
# st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c)
|
|
||||||
# else:
|
|
||||||
# st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
|
|
||||||
# End Changes
|
# End Changes
|
||||||
for line in st.move_line_ids:
|
for line in st.move_line_ids:
|
||||||
if line.state <> 'valid':
|
if line.state <> 'valid':
|
||||||
@@ -359,24 +377,30 @@ class AccountBankSatement(Model):
|
|||||||
self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,))
|
self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,))
|
||||||
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
|
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
|
||||||
|
|
||||||
def get_partner_from_so(self, cursor, uid,transaction_id):
|
def get_account_for_counterpart(self, cursor, uid,
|
||||||
"""Look for the SO that has the given transaction_id, if not
|
amount, account_receivable, account_payable):
|
||||||
found, try to match the SO name instead. If still nothing,
|
"""Give the amount, payable and receivable account (that can be found using
|
||||||
return False"""
|
get_default_pay_receiv_accounts).
|
||||||
so_obj = self.pool.get('sale.order')
|
Return the default account to be used by statement line as the counterpart
|
||||||
so_id = so_obj.search(cursor, uid, [('transaction_id', '=', transaction_id)])
|
of the journal account depending on the amount"""
|
||||||
if so_id and len(so_id) == 1:
|
account_id = False
|
||||||
return so_obj.browse(cursor, uid, so_id[0]).partner_id.id
|
if amount >= 0:
|
||||||
|
account_id = account_receivable
|
||||||
else:
|
else:
|
||||||
so_id2 = so_obj.search(cursor, uid, [('name', '=', transaction_id)])
|
account_id = account_payable
|
||||||
if so_id2 and len(so_id2) == 1:
|
if not account_id:
|
||||||
return so_obj.browse(cursor, uid, so_id2[0]).partner_id.id
|
raise osv.except_osv(
|
||||||
return False
|
_('Can not determine account'),
|
||||||
|
_('Please ensure that minimal properties are set')
|
||||||
|
)
|
||||||
|
return account_id
|
||||||
|
|
||||||
|
def get_default_pay_receiv_accounts(self, cursor, uid, receivable_account_id, context=None):
|
||||||
def get_default_accounts(self, cursor, uid, receivable_account_id, context=None):
|
"""We try to determine default payable/receivable accounts to be used as counterpart
|
||||||
"""We try to determine default accounts if not receivable_account_id set, otherwise
|
of the journal one.
|
||||||
take it for both receivable and payable account"""
|
|
||||||
|
If receivable_account_id is set (from the profil), take it as receivable/payable
|
||||||
|
account. Otherwise take it from the property of the partner."""
|
||||||
account_receivable = False
|
account_receivable = False
|
||||||
account_payable = False
|
account_payable = False
|
||||||
if receivable_account_id:
|
if receivable_account_id:
|
||||||
@@ -410,21 +434,6 @@ class AccountBankSatement(Model):
|
|||||||
account_payable = erp_property.value_reference.id
|
account_payable = erp_property.value_reference.id
|
||||||
return account_receivable, account_payable
|
return account_receivable, account_payable
|
||||||
|
|
||||||
def _get_account_id(self, cursor, uid,
|
|
||||||
amount, account_receivable, account_payable):
|
|
||||||
"return the default account to be used by statement line"
|
|
||||||
account_id = False
|
|
||||||
if amount >= 0:
|
|
||||||
account_id = account_receivable
|
|
||||||
else:
|
|
||||||
account_id = account_payable
|
|
||||||
if not account_id:
|
|
||||||
raise osv.except_osv(
|
|
||||||
_('Can not determine account'),
|
|
||||||
_('Please ensure that minimal properties are set')
|
|
||||||
)
|
|
||||||
return account_id
|
|
||||||
|
|
||||||
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
|
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
|
||||||
"""Balance check depends on the profil. If no check for this profil is required,
|
"""Balance check depends on the profil. If no check for this profil is required,
|
||||||
return True"""
|
return True"""
|
||||||
@@ -433,25 +442,11 @@ class AccountBankSatement(Model):
|
|||||||
return super(AccountBankSatement,self).balance_check(cr, uid, st_id, journal_type, context)
|
return super(AccountBankSatement,self).balance_check(cr, uid, st_id, journal_type, context)
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _get_value_from_import_config(self, cr, uid, import_config_id):
|
|
||||||
"""Return a dict with with values taken from the given config.
|
|
||||||
e.g. (journal_id, partner_id, commission_account_id, mode, forced_account_id)
|
|
||||||
"""
|
|
||||||
# Get variable from config
|
|
||||||
import_config = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
|
||||||
forced_account_id = import_config.receivable_account_id and import_config.receivable_account_id.id or False
|
|
||||||
journal_id = import_config.journal_id and import_config.journal_id.id or False
|
|
||||||
partner_id = import_config.partner_id and import_config.partner_id.id or False
|
|
||||||
commission_account_id = import_config.commission_account_id.id
|
|
||||||
commission_analytic_id = import_config.commission_analytic_id and import_config.commission_analytic_id.id or False
|
|
||||||
force_partner_on_bank = import_config.force_partner_on_bank
|
|
||||||
return journal_id, partner_id, commission_account_id, commission_analytic_id, forced_account_id, force_partner_on_bank
|
|
||||||
|
|
||||||
def onchange_imp_config_id(self, cr, uid, ids, import_config_id, context=None):
|
def onchange_imp_config_id(self, cr, uid, ids, profile_id, context=None):
|
||||||
if not import_config_id:
|
if not profile_id:
|
||||||
return {}
|
return {}
|
||||||
import_config = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
import_config = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
|
||||||
journal_id = import_config.journal_id.id
|
journal_id = import_config.journal_id.id
|
||||||
account_id = import_config.journal_id.default_debit_account_id.id
|
account_id = import_config.journal_id.default_debit_account_id.id
|
||||||
credit_partner_id = import_config.partner_id and import_config.partner_id.id or False
|
credit_partner_id = import_config.partner_id and import_config.partner_id.id or False
|
||||||
@@ -460,132 +455,6 @@ class AccountBankSatement(Model):
|
|||||||
'credit_partner_id':credit_partner_id,
|
'credit_partner_id':credit_partner_id,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
def credit_statement_import(self, cursor, uid, ids,
|
|
||||||
import_config_id,
|
|
||||||
file_stream,
|
|
||||||
ftype="csv",
|
|
||||||
context=None):
|
|
||||||
"Create statement from file stream encoded in base 64"
|
|
||||||
context = context or {}
|
|
||||||
statement_obj = self.pool.get('account.bank.statement')
|
|
||||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
|
||||||
attachment_obj = self.pool.get('ir.attachment')
|
|
||||||
|
|
||||||
# Get variable from config
|
|
||||||
journal_id, partner_id, commission_account_id, commission_analytic_id, \
|
|
||||||
forced_account_id, force_partner_on_bank = self._get_value_from_import_config(cursor,uid,import_config_id)
|
|
||||||
|
|
||||||
account_receivable, account_payable = self.get_default_accounts(cursor, uid, forced_account_id)
|
|
||||||
|
|
||||||
##Order of cols does not matter but first row has to be header
|
|
||||||
keys = ['transaction_id', 'label', 'date', 'amount', 'commission_amount']
|
|
||||||
#required_values = ['transaction_id', 'amount', 'commission_amount']
|
|
||||||
convertion_dict = {
|
|
||||||
'transaction_id': unicode,
|
|
||||||
'label': unicode,
|
|
||||||
'date': datetime.datetime,
|
|
||||||
'amount': float,
|
|
||||||
'commission_amount': float
|
|
||||||
}
|
|
||||||
|
|
||||||
f_parser = FileParser(file_stream,
|
|
||||||
keys_to_validate=keys,
|
|
||||||
decode_base_64=True,
|
|
||||||
ftype=ftype)
|
|
||||||
statement_lines = f_parser.parse()
|
|
||||||
statement_lines = f_parser.cast_rows(statement_lines, convertion_dict)
|
|
||||||
journal = self.pool.get('account.journal').browse(cursor, uid, journal_id)
|
|
||||||
statement_id = statement_obj.create(cursor,
|
|
||||||
uid,
|
|
||||||
{ 'import_config_id':import_config_id,
|
|
||||||
'journal_id': journal_id,
|
|
||||||
'journal_id': journal_id,
|
|
||||||
'credit_partner_id': partner_id,
|
|
||||||
'statement_type': 'credit_partner',
|
|
||||||
},
|
|
||||||
context)
|
|
||||||
commission_global_amount = 0.0
|
|
||||||
if not journal.default_debit_account_id \
|
|
||||||
or not journal.default_credit_account_id:
|
|
||||||
raise osv.except_osv(
|
|
||||||
_("Missing default account on journal %s")%(journal.name),
|
|
||||||
_("Please correct the journal"))
|
|
||||||
try:
|
|
||||||
for line in statement_lines:
|
|
||||||
line_partner_id = False
|
|
||||||
line_to_reconcile = False
|
|
||||||
# We ensure that required values of the line are set
|
|
||||||
# for val in required_values:
|
|
||||||
# if not line.get(val, False) and line.get(val, False) != 0.0:
|
|
||||||
# raise osv.except_osv(
|
|
||||||
# _("Field %s not set for line %s")%(str(line),),
|
|
||||||
# _("Please correct the file"))
|
|
||||||
|
|
||||||
commission_global_amount += line.get('commission_amount', 0.0)
|
|
||||||
values = {
|
|
||||||
'name': "IN %s %s"%(line['transaction_id'],
|
|
||||||
line.get('label', '')),
|
|
||||||
'date': line.get('date', datetime.datetime.now().date()),
|
|
||||||
'amount': line['amount'],
|
|
||||||
'ref': "TID_%s"%(line['transaction_id'],),
|
|
||||||
'type': 'customer',
|
|
||||||
'statement_id': statement_id,
|
|
||||||
#'account_id': journal.default_debit_account_id
|
|
||||||
}
|
|
||||||
values['account_id'] = self._get_account_id(
|
|
||||||
cursor,
|
|
||||||
uid,
|
|
||||||
line['amount'],
|
|
||||||
account_receivable,
|
|
||||||
account_payable
|
|
||||||
)
|
|
||||||
if not line_partner_id:
|
|
||||||
line_partner_id = self.get_partner_from_so(cursor,
|
|
||||||
uid, line['transaction_id'])
|
|
||||||
values['partner_id'] = line_partner_id
|
|
||||||
# we finally create the line in system
|
|
||||||
statement_line_obj.create(cursor, uid, values, context=context)
|
|
||||||
|
|
||||||
# we create commission line
|
|
||||||
if commission_global_amount:
|
|
||||||
comm_values = {
|
|
||||||
'name': 'IN '+ _('Commission line'),
|
|
||||||
'date': datetime.datetime.now().date(),
|
|
||||||
'amount': commission_global_amount,
|
|
||||||
'partner_id': partner_id,
|
|
||||||
'type': 'general',
|
|
||||||
'statement_id': statement_id,
|
|
||||||
'account_id': commission_account_id,
|
|
||||||
'ref': 'commission',
|
|
||||||
'analytic_account_id': commission_analytic_id
|
|
||||||
}
|
|
||||||
statement_line_obj.create(cursor, uid,
|
|
||||||
comm_values,
|
|
||||||
context=context)
|
|
||||||
|
|
||||||
attachment_obj.create(
|
|
||||||
cursor,
|
|
||||||
uid,
|
|
||||||
{
|
|
||||||
'name': 'statement file',
|
|
||||||
'datas': file_stream,
|
|
||||||
'datas_fname': "%s.%s"%(datetime.datetime.now().date(),
|
|
||||||
ftype),
|
|
||||||
'res_model': 'account.bank.statement',
|
|
||||||
'res_id': statement_id,
|
|
||||||
},
|
|
||||||
context=context
|
|
||||||
)
|
|
||||||
except Exception, exc:
|
|
||||||
logger.notifyChannel("Statement import",
|
|
||||||
netsvc.LOG_ERROR,
|
|
||||||
_("Statement can not be created %s") %(exc,))
|
|
||||||
|
|
||||||
statement_obj.unlink(cursor, uid, [statement_id])
|
|
||||||
raise exc
|
|
||||||
return statement_id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AccountBankSatementLine(Model):
|
class AccountBankSatementLine(Model):
|
||||||
_inherit = "account.bank.statement.line"
|
_inherit = "account.bank.statement.line"
|
||||||
@@ -596,11 +465,7 @@ class AccountBankSatementLine(Model):
|
|||||||
return periods and periods[0] or False
|
return periods and periods[0] or False
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
# 'statement_id': fields.many2one('account.bank.statement', 'Statement',
|
# Set them as required
|
||||||
# select=True, required=True, ondelete='cascade'),
|
|
||||||
# 'move_ids': fields.many2many('account.move',
|
|
||||||
# 'account_treasury_statement_line_move_rel', 'statement_line_id','move_id',
|
|
||||||
# 'Moves'),
|
|
||||||
'ref': fields.char('Reference', size=32, required=True),
|
'ref': fields.char('Reference', size=32, required=True),
|
||||||
'period_id': fields.many2one('account.period', 'Period', required=True),
|
'period_id': fields.many2one('account.period', 'Period', required=True),
|
||||||
}
|
}
|
||||||
@@ -608,18 +473,11 @@ class AccountBankSatementLine(Model):
|
|||||||
'period_id': _get_period,
|
'period_id': _get_period,
|
||||||
}
|
}
|
||||||
|
|
||||||
# WARNING => Crash cause the super method here calls onchange_type => and then
|
|
||||||
# we don't call it from the good model.... => We'll need to override the complete method here
|
|
||||||
def onchange_partner_id(self, cr, uid, ids, partner_id, import_config_id, context=None):
|
def onchange_partner_id(self, cr, uid, ids, partner_id, profile_id, context=None):
|
||||||
# import pdb;pdb.set_trace()
|
"""When changing the partner, we'll now need to look in the profil to determine which
|
||||||
# if context is None:
|
account to use."""
|
||||||
# context = {}
|
|
||||||
# res = super(AccountTreasurySatementLine,self).onchange_partner_id(cr, uid, ids, partner_id, context)
|
|
||||||
# c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
|
||||||
# acc_id=c.receivable_account_id and c.receivable_account_id.id or False
|
|
||||||
# if acc_id:
|
|
||||||
# res['value'].update({'account_id':acc_id})
|
|
||||||
# return res
|
|
||||||
obj_partner = self.pool.get('res.partner')
|
obj_partner = self.pool.get('res.partner')
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
@@ -635,34 +493,26 @@ class AccountBankSatementLine(Model):
|
|||||||
type = 'supplier'
|
type = 'supplier'
|
||||||
if part.customer == True:
|
if part.customer == True:
|
||||||
type = 'customer'
|
type = 'customer'
|
||||||
res_type = self.onchange_type(cr, uid, ids, partner_id, type, import_config_id, context=context)
|
res_type = self.onchange_type(cr, uid, ids, partner_id, type, profile_id, context=context)
|
||||||
if res_type['value'] and res_type['value'].get('account_id', False):
|
if res_type['value'] and res_type['value'].get('account_id', False):
|
||||||
res = {'value': {'type': type, 'account_id': res_type['value']['account_id']}}
|
res = {'value': {'type': type, 'account_id': res_type['value']['account_id']}}
|
||||||
else:
|
else:
|
||||||
res = {'value': {'type': type}}
|
res = {'value': {'type': type}}
|
||||||
|
|
||||||
c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
c = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
|
||||||
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
|
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
|
||||||
if acc_id:
|
if acc_id:
|
||||||
res['value'].update({'account_id':acc_id})
|
res['value'].update({'account_id':acc_id})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# TOFIX
|
# TOFIX: don't seems to work as expected
|
||||||
def onchange_type(self, cr, uid, line_id, partner_id, type, import_config_id, context=None):
|
def onchange_type(self, cr, uid, line_id, partner_id, type, profile_id, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
res = super(AccountBankSatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context)
|
res = super(AccountBankSatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context)
|
||||||
c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
c = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
|
||||||
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
|
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
|
||||||
if acc_id:
|
if acc_id:
|
||||||
res['value'].update({'account_id':acc_id})
|
res['value'].update({'account_id':acc_id})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# class AccountMoveLine(Model):
|
|
||||||
# _inherit = "account.move.line"
|
|
||||||
#
|
|
||||||
# _columns = {
|
|
||||||
# 'statement_treasury_id': fields.many2one('account.bank.statement', 'Statement', help="The intermediate statement used for reconciliation", select=1),
|
|
||||||
# }
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<field name="receivable_account_id" />
|
<field name="receivable_account_id" />
|
||||||
<field name="force_partner_on_bank"/>
|
<field name="force_partner_on_bank"/>
|
||||||
<field name="balance_check"/>
|
<field name="balance_check"/>
|
||||||
|
<field name="bank_statement_prefix"/>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -90,7 +91,7 @@
|
|||||||
<field name="type">search</field>
|
<field name="type">search</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="/search/group/field[@name='name']" position="before">
|
<xpath expr="/search/group/field[@name='name']" position="before">
|
||||||
<field name="import_config_id"/>
|
<field name="profile_id"/>
|
||||||
<field name="credit_partner_id"/>
|
<field name="credit_partner_id"/>
|
||||||
<separator orientation="vertical"/>
|
<separator orientation="vertical"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -109,7 +110,7 @@
|
|||||||
<field name="type">tree</field>
|
<field name="type">tree</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="/tree/field[@name='name']" position="after">
|
<xpath expr="/tree/field[@name='name']" position="after">
|
||||||
<field name="import_config_id"/>
|
<field name="profile_id"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/tree/field[@name='period_id']" position="replace">
|
<xpath expr="/tree/field[@name='period_id']" position="replace">
|
||||||
<field name="credit_partner_id"/>
|
<field name="credit_partner_id"/>
|
||||||
@@ -133,7 +134,7 @@
|
|||||||
<xpath expr="/form/group[@col='7']" position="before">
|
<xpath expr="/form/group[@col='7']" position="before">
|
||||||
<group col="6" colspan="4">
|
<group col="6" colspan="4">
|
||||||
<field name="name" select="1"/>
|
<field name="name" select="1"/>
|
||||||
<field name="import_config_id" select="1" required="1" on_change="onchange_imp_config_id(import_config_id)" widget="selection"/>
|
<field name="profile_id" select="1" required="1" on_change="onchange_imp_config_id(profile_id)" widget="selection"/>
|
||||||
<field name="date" select="1" on_change="onchange_date(date, company_id)"/>
|
<field name="date" select="1" on_change="onchange_date(date, company_id)"/>
|
||||||
</group>
|
</group>
|
||||||
<separator string="Details" colspan="4"/>
|
<separator string="Details" colspan="4"/>
|
||||||
@@ -166,23 +167,23 @@
|
|||||||
<field name="id"/>
|
<field name="id"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/notebook/page/field/tree/field[@name='partner_id']" position="replace">
|
<xpath expr="/form/notebook/page/field/tree/field[@name='partner_id']" position="replace">
|
||||||
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.import_config_id)"/>
|
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.profile_id)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/notebook/page/field/form/field[@name='date']" position="before">
|
<xpath expr="/form/notebook/page/field/form/field[@name='date']" position="before">
|
||||||
<field name="id"/>
|
<field name="id"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<!-- Adapt onchange signature -->
|
<!-- Adapt onchange signature -->
|
||||||
<xpath expr="/form/notebook/page/field/tree/field[@name='partner_id']" position="replace">
|
<xpath expr="/form/notebook/page/field/tree/field[@name='partner_id']" position="replace">
|
||||||
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.import_config_id)"/>
|
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.profile_id)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/notebook/page/field/form/field[@name='partner_id']" position="replace">
|
<xpath expr="/form/notebook/page/field/form/field[@name='partner_id']" position="replace">
|
||||||
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.import_config_id)"/>
|
<field name="partner_id" on_change="onchange_partner_id(partner_id,parent.profile_id)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/notebook/page/field/form/field[@name='type']" position="replace">
|
<xpath expr="/form/notebook/page/field/form/field[@name='type']" position="replace">
|
||||||
<field name="type" on_change="onchange_type(partner_id, type, parent.import_config_id)"/>
|
<field name="type" on_change="onchange_type(partner_id, type, parent.profile_id)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/notebook/page/field/tree/field[@name='type']" position="replace">
|
<xpath expr="/form/notebook/page/field/tree/field[@name='type']" position="replace">
|
||||||
<field name="type" on_change="onchange_type(partner_id, type, parent.import_config_id)"/>
|
<field name="type" on_change="onchange_type(partner_id, type, parent.profile_id)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Author: Nicolas Bessi, Joel Grand-Guillaume
|
|
||||||
# Copyright 2011-2012 Camptocamp SA
|
|
||||||
#
|
|
||||||
# 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/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
Wizard to import financial institute date in bank statement
|
|
||||||
"""
|
|
||||||
|
|
||||||
from osv import fields, osv
|
|
||||||
from tools.translate import _
|
|
||||||
import os
|
|
||||||
|
|
||||||
class CreditPartnerStatementImporter(osv.osv_memory):
|
|
||||||
"""Import Credit statement"""
|
|
||||||
|
|
||||||
_name = "credit.statement.import"
|
|
||||||
_description = __doc__
|
|
||||||
_columns = {
|
|
||||||
|
|
||||||
'import_config_id': fields.many2one('account.statement.profil',
|
|
||||||
'Import configuration parameter',
|
|
||||||
required=True),
|
|
||||||
'partner_id': fields.many2one('res.partner',
|
|
||||||
'Credit insitute partner',
|
|
||||||
),
|
|
||||||
'journal_id': fields.many2one('account.journal',
|
|
||||||
'Financial journal to use transaction',
|
|
||||||
),
|
|
||||||
'input_statement': fields.binary('Statement file', required=True),
|
|
||||||
'file_name': fields.char('File Name', size=128),
|
|
||||||
'commission_account_id': fields.many2one('account.account',
|
|
||||||
'Commission account',
|
|
||||||
),
|
|
||||||
'commission_analytic_id': fields.many2one('account.analytic.account',
|
|
||||||
'Commission analytic account',
|
|
||||||
),
|
|
||||||
'receivable_account_id': fields.many2one('account.account',
|
|
||||||
'Force Receivable/Payable Account'),
|
|
||||||
'force_partner_on_bank': fields.boolean('Force partner on bank move',
|
|
||||||
help="Tic that box if you want to use the credit insitute partner\
|
|
||||||
in the counterpart of the treasury/banking move."
|
|
||||||
),
|
|
||||||
'balance_check': fields.boolean('Balance check',
|
|
||||||
help="Tic that box if you want OpenERP to control the start/end balance\
|
|
||||||
before confirming a bank statement. If don't ticked, no balance control will be done."
|
|
||||||
),
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def onchange_import_config_id(self, cr, uid, ids, import_config_id, context=None):
|
|
||||||
res={}
|
|
||||||
if import_config_id:
|
|
||||||
c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
|
|
||||||
res = {'value': {'partner_id': c.partner_id and c.partner_id.id or False,
|
|
||||||
'journal_id': c.journal_id and c.journal_id.id or False, 'commission_account_id': \
|
|
||||||
c.commission_account_id and c.commission_account_id.id or False,
|
|
||||||
'receivable_account_id': c.receivable_account_id and c.receivable_account_id.id or False,
|
|
||||||
'commission_a':c.commission_analytic_id and c.commission_analytic_id.id or False,
|
|
||||||
'force_partner_on_bank':c.force_partner_on_bank,
|
|
||||||
'balance_check':c.balance_check,}}
|
|
||||||
return res
|
|
||||||
|
|
||||||
def import_statement(self, cursor, uid, req_id, context=None):
|
|
||||||
"""This Function import credit card agency statement"""
|
|
||||||
context = context or {}
|
|
||||||
if isinstance(req_id, list):
|
|
||||||
req_id = req_id[0]
|
|
||||||
importer = self.browse(cursor, uid, req_id, context)
|
|
||||||
(shortname, ftype) = os.path.splitext(importer.file_name)
|
|
||||||
if not ftype:
|
|
||||||
#We do not use osv exception we do not want to have it logged
|
|
||||||
raise Exception(_('Please use a file with an extention'))
|
|
||||||
sid = self.pool.get(
|
|
||||||
'account.bank.statement').credit_statement_import(
|
|
||||||
cursor,
|
|
||||||
uid,
|
|
||||||
False,
|
|
||||||
importer.import_config_id.id,
|
|
||||||
importer.input_statement,
|
|
||||||
ftype.replace('.',''),
|
|
||||||
context=context
|
|
||||||
)
|
|
||||||
obj_data = self.pool.get('ir.model.data')
|
|
||||||
act_obj = self.pool.get('ir.actions.act_window')
|
|
||||||
result = obj_data.get_object_reference(cursor, uid, 'account_statement_import', 'action_treasury_statement_tree')
|
|
||||||
|
|
||||||
id = result and result[1] or False
|
|
||||||
result = act_obj.read(cursor, uid, [id], context=context)[0]
|
|
||||||
result['domain'] = str([('id','in',[sid])])
|
|
||||||
return result
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<openerp>
|
|
||||||
<data>
|
|
||||||
<record id="statement_importer_view" model="ir.ui.view">
|
|
||||||
<field name="name">credit.statement.import.config.view</field>
|
|
||||||
<field name="model">credit.statement.import</field>
|
|
||||||
<field name="type">form</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Import statement">
|
|
||||||
<group colspan="4" >
|
|
||||||
<field name="import_config_id" on_change="onchange_import_config_id(import_config_id)"/>
|
|
||||||
<field name="input_statement" filename="file_name" colspan="2"/>
|
|
||||||
<field name="file_name" colspan="2" invisible="1"/>
|
|
||||||
<separator string="Import Parameters Summary" colspan="4"/>
|
|
||||||
<field name="partner_id" readonly="1"/>
|
|
||||||
<field name="journal_id" readonly="1"/>
|
|
||||||
<field name="commission_account_id" readonly="1"/>
|
|
||||||
<field name="commission_analytic_id" readonly="1"/>
|
|
||||||
<field name="receivable_account_id" readonly="1"/>
|
|
||||||
<field name="force_partner_on_bank" readonly="1"/>
|
|
||||||
<field name="balance_check" readonly="1"/>
|
|
||||||
</group>
|
|
||||||
<separator string="" colspan="4"/>
|
|
||||||
<group colspan="4" col="6">
|
|
||||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
|
||||||
<button icon="gtk-ok" name="import_statement" string="Import statement" type="object"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="statement_importer_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Import statement</field>
|
|
||||||
<field name="res_model">credit.statement.import</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
<field name="view_id" ref="statement_importer_view"/>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<menuitem id="statement_importer_menu" name="Import Treasury Statement" action="statement_importer_action" parent="account.menu_finance_periodical_processing"/>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</openerp>
|
|
||||||
22
account_statement_transactionid_completion/__init__.py
Normal file
22
account_statement_transactionid_completion/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
import statement
|
||||||
47
account_statement_transactionid_completion/__openerp__.py
Normal file
47
account_statement_transactionid_completion/__openerp__.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
{'name': "Bank statement completion from transaction ID",
|
||||||
|
'version': '1.0',
|
||||||
|
'author': 'Camptocamp',
|
||||||
|
'maintainer': 'Camptocamp',
|
||||||
|
'category': 'Finance',
|
||||||
|
'complexity': 'normal', #easy, normal, expert
|
||||||
|
'depends': ['base_transaction_id','account_statement_base_completion'],
|
||||||
|
'description': """
|
||||||
|
Add a completion method based on transaction ID providen by the bank/office. This
|
||||||
|
transaction ID has been recorded on the SO (by a mapping through the e-commerce connector,
|
||||||
|
or manually). Completion will look in the SO with that transaction ID to match the partner.
|
||||||
|
|
||||||
|
""",
|
||||||
|
'website': 'http://www.camptocamp.com',
|
||||||
|
'init_xml': [],
|
||||||
|
'update_xml': [
|
||||||
|
"statement_view.xml",
|
||||||
|
],
|
||||||
|
'demo_xml': [],
|
||||||
|
'test': [],
|
||||||
|
'installable': True,
|
||||||
|
'images': [],
|
||||||
|
'auto_install': False,
|
||||||
|
'license': 'AGPL-3',
|
||||||
|
'active': False,
|
||||||
|
}
|
||||||
51
account_statement_transactionid_completion/statement.py
Normal file
51
account_statement_transactionid_completion/statement.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Author: Joel Grand-Guillaume
|
||||||
|
# Copyright 2011-2012 Camptocamp SA
|
||||||
|
#
|
||||||
|
# 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 tools.translate import _
|
||||||
|
import datetime
|
||||||
|
import netsvc
|
||||||
|
logger = netsvc.Logger()
|
||||||
|
from openerp.osv.orm import Model, fields
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStatementProfil(Model):
|
||||||
|
_inherit = "account.statement.profil"
|
||||||
|
|
||||||
|
|
||||||
|
class AccountBankSatement(Model):
|
||||||
|
|
||||||
|
_inherit = "account.bank.statement"
|
||||||
|
|
||||||
|
class AccountStatementLine(Model):
|
||||||
|
_inherit = "account.bank.statement.line"
|
||||||
|
|
||||||
|
_columns={
|
||||||
|
# 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', help="Used by completion and import system."),
|
||||||
|
'transaction_id': fields.sparse(type='char', string='Transaction ID',
|
||||||
|
size=128,
|
||||||
|
serialization_field='additionnal_bank_fields',
|
||||||
|
help="Transction id from the financial institute"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record id="bank_statement_view_form" model="ir.ui.view">
|
||||||
|
<field name="name">account_bank_statement_import_base.bank_statement.view_form</field>
|
||||||
|
<field name="model">account.bank.statement</field>
|
||||||
|
<field name="inherit_id" ref="account.view_bank_statement_form" />
|
||||||
|
<field eval="16" name="priority"/>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<data>
|
||||||
|
<xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='ref']" position="after">
|
||||||
|
<field name="transaction_id" />
|
||||||
|
</xpath>
|
||||||
|
</data>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
Reference in New Issue
Block a user