[MRG] From customer branch

(lp:c2c-financial-addons/6.1 rev 58)
This commit is contained in:
Joël Grand-Guillaume
2012-06-06 16:27:25 +02:00
parent 0bd4a219aa
commit d8e7cb77a2
51 changed files with 89 additions and 3815 deletions

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Joel Grand-Guillaume
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
@@ -20,5 +20,3 @@
##############################################################################
import statement
import report
import account

View File

@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Joel Grand-Guillaume
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
# Thanks to EduSense BV (<http://www.edusense.nl>) for some part and idea
# taken from the account_banking module
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,7 +21,7 @@
#
##############################################################################
{'name': "Bank statement extension and profiles",
{'name': "Account Bank Statement without Period",
'version': '1.0',
'author': 'Camptocamp',
'maintainer': 'Camptocamp',
@@ -27,51 +29,13 @@
'complexity': 'normal', #easy, normal, expert
'depends': ['account'],
'description': """
The goal of this module is to improve the basic bank statement, by adding various new features,
and help dealing with huge volume of reconciliation through payment offices (like Paypal, Lazer,
Visa, Amazon,...).
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 (see our other
set of modules, like : account_statement_base_completion, account_statement_base_import,
account_advanced_reconcile).
Features:
1) This module improves the bank statement in the way it allows you to define profiles (for each
Office or Bank). The bank statement will then generate the entries based on some criteria chosen
in the selected profile. You can setup on the profile:
- The journal to use
- Choose to use balance check or not
- Account commission and Analytic account for commission
- Partner concerned by the profile (used in commission and optionaly on generated credit move)
- Can force a to use a specifi credit account (instead of the receivalble/payable default one)
- Force Partner on the counter-part move (e.g. 100.- debit, Partner: M.Martin; 100.- credit, Partner: HSBC)
2) Adds a report on bank statement that can be used for checks remittance
3) When an error occurs in a bank statement confirmation, it will go through all line anyway and summarize
all the erronous line in a same popup instead of raising and crashing on every step.
4) Remove the period on the bank statement, and compute it for each line based on their date instead.
5) Cancelling a bank statement is much more easy and will cancel all related entries, unreconcile them,
and finally delete them.
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.)
Remove the period on the bank statement, and compute it for each line based on their date instead.
If errors occurs, it will summarize them all in one popup instead of blocking all the process at every error.
""",
'website': 'http://www.camptocamp.com',
'init_xml': [],
'update_xml': [
'statement_view.xml',
'report/bank_statement_webkit_header.xml',
'report.xml',
],
'demo_xml': [],
'test': [],

View File

@@ -1,40 +0,0 @@
# -*- 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(Model):
_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)

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" ?>
<openerp>
<data>
<report auto="False"
id="report_bank_statement_webkit"
model="account.bank.statement"
name="bank_statement_webkit"
file="account_statement_ext/report/bank_statement_report.mako"
string="Bank Statement"
report_type="webkit"
webkit_header="account_statement_ext.bank_statement_landscape_header"
header="1"/>
<record id="action_print_bank_statement_webkit" model="ir.values">
<field name="name">Bank Statement</field>
<field name="key2">client_print_multi</field>
<field name="value_unpickle"
eval="'ir.actions.report.xml,' +str(ref('report_bank_statement_webkit'))"/>
<field name="key">action</field>
<field name="model">account.bank.statement</field>
</record>
</data>
</openerp>

View File

@@ -1,31 +0,0 @@
# -*- encoding: utf-8 -*-
#
# __init__.py
#
# Copyright (c) 2009 CamptoCamp. All rights reserved.
##############################################################################
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import bank_statement_report

View File

@@ -1,69 +0,0 @@
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
${css}
</style>
</head>
<body>
<%!
def amount(text):
return text.replace('-', '&#8209;') # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
%>
<%setLang(user.context_lang)%>
%for statement in objects:
<div class="act_as_table data_table">
<div class="act_as_row labels">
<div class="act_as_cell">${_('Bordereau')}</div>
<div class="act_as_cell">${_('Date')}</div>
</div>
<div class="act_as_row">
<div class="act_as_cell">${ statement.name }</div>
<div class="act_as_cell">${ formatLang(statement.date,date=True) }</div>
</div>
</div>
<!-- we use div with css instead of table for tabular data because div do not cut rows at half at page breaks -->
<div class="act_as_table list_table" style="margin-top: 10px;">
<div class="act_as_thead">
<div class="act_as_row labels">
## date
<div class="act_as_cell first_column" style="width: 100px;">${_('Reference')}</div>
## period
<div class="act_as_cell" style="width: 175px;">${_('Partenaire')}</div>
## move
<div class="act_as_cell" style="width: 60px;">${_('Montant')}</div>
## journal
</div>
</div>
<% sum_statement = 0.0 %>
%for statementline in statement.line_ids:
<div class="act_as_tbody">
## curency code
<div class="act_as_cell">${statementline.name or '' }</div>
## currency balance
<div class="act_as_cell">${statementline.partner_id.name or '' }</div>
## currency balance cumulated
<div class="act_as_cell amount">${formatLang(statementline.amount) | amount }</div>
<% sum_statement += statementline.amount %>
</div>
%endfor
<div class="act_as_tbody">
## curency code
<div class="act_as_cell"></div>
## currency balance
<div class="act_as_cell">Total</div>
## currency balance cumulated
<div class="act_as_cell amount_total">${formatLang(sum_statement) }</div>
</div>
</div>
%endfor
</body>
</html>

View File

@@ -1,70 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi. Copyright 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 time
from report import report_sxw
from osv import osv
from tools.translate import _
import pooler
from operator import add, itemgetter
from itertools import groupby
from datetime import datetime
from report_webkit import webkit_report
class BankStatementWebkit(report_sxw.rml_parse):
def __init__(self, cursor, uid, name, context):
super(BankStatementWebkit, self).__init__(cursor, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr
company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('BORDEREAU DE REMISE DE CHEQUES'),
company.name, company.currency_id.name))
statement = self.pool.get('account.bank.statement').browse(cursor,uid,context['active_id']);
footer_date_time = self.formatLang(str(datetime.today())[:19], date_time=True)
self.localcontext.update({
'cr': cursor,
'uid': uid,
'get_bank_statement' : self._get_bank_statement_data,
'report_name': _('BORDEREAU DE REMISE DE CHEQUES'),
'additional_args': [
('--header-font-name', 'Helvetica'),
('--footer-font-name', 'Helvetica'),
('--header-font-size', '10'),
('--footer-font-size', '6'),
('--header-left', header_report_name),
('--header-spacing', '2'),
('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',),
],
})
def _get_bank_statement_data(self,statement):
statement_obj = self.pool.get('account.bank.statement.line')
statement_line_ids = statement_obj.search(self.cr,self.uid,[['statement_id','=',statement.id]])
statement_lines = statement_obj.browse(self.cr,self.uid,statement_line_ids)
return statement_lines
webkit_report.WebKitParser('report.bank_statement_webkit',
'account.bank.statement',
'addons/account_statement_ext/report/bank_statement_report.mako',
parser=BankStatementWebkit)

View File

@@ -1,180 +0,0 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="bank_statement_landscape_header" model="ir.header_webkit">
<field name="footer_html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
</head>
<% import datetime %>
<body style="border:0; margin: 0;" onload="subst()">
<table style="border-top: 1px solid black; width: 1080px">
<tr style="border-collapse:collapse;">
<td style="text-align:left;font-size:10;width:350px;">${formatLang( str(datetime.datetime.today()), date_time=True)}</td>
<td style="text-align:center;font-size:10;width:350px;">${user.name}</td>
<td style="text-align:right;font-size:10;width:350px;">Page&nbsp;<span class="page"/></td>
<td style="text-align:left;font-size:10;width:30px">&nbsp;of&nbsp;<span class="topage"/></td>
</tr>
</table>
</body>
</html>]]></field>
<field name="orientation">Portrait</field>
<field name="format">A4</field>
<field name="html"><![CDATA[
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
<style type="text/css">
${css}
</style>
</head>
<body style="border:0; margin: 0;" onload="subst()">
<table class="header" style="border-bottom: 0px solid black; width: 100%">
<tr>
<td style="text-align:left; font-size:11px; font-weight: bold;"><span style="text-transform:uppercase; font-size:12px;">${report_name}</span> - ${company.partner_id.name | entity} - ${company.currency_id.name | entity}</td>
</tr>
</table> ${_debug or ''|n} </body>
</html>]]>
</field>
<field eval="0.0" name="margin_top"/>
<field name="css"><![CDATA[
body, table, td, span, div {
font-family: Helvetica, Arial;
}
.act_as_table {
display: table;
}
.act_as_row {
display: table-row;
}
.act_as_cell {
display: table-cell;
}
.act_as_thead {
display: table-header-group;
}
.act_as_tbody {
display: table-row-group;
}
.act_as_tfoot {
display: table-footer-group;
}
.act_as_caption {
display: table-caption;
}
act_as_colgroup {
display: table-column-group;
}
.list_table, .data_table {
width: 720px;
table-layout: fixed
}
.bg, .act_as_row.labels {
background-color:#F0F0F0;
}
.list_table, .data_table, .list_table .act_as_row {
border-left:0px;
border-right:0px;
text-align:left;
font-size:9px;
padding-right:3px;
padding-left:3px;
padding-top:2px;
padding-bottom:2px;
border-collapse:collapse;
}
.list_table .act_as_row.labels, .list_table .act_as_row.initial_balance, .list_table .act_as_row.lines {
border-color:gray;
border-bottom:1px solid lightGrey;
}
.data_table .act_as_cell {
border: 1px solid lightGrey;
text-align: center;
}
.data_table .act_as_cell, .list_table .lines .act_as_cell {
word-wrap: break-word;
}
.nobreak {
word-wrap: normal;
}
.data_table .act_as_row.labels {
font-weight: bold;
}
.initial_balance .act_as_cell {
font-style:italic;
}
.account_title {
font-size:10px;
font-weight:bold;
page-break-after: avoid;
}
.act_as_cell.amount {
word-wrap:normal;
text-align:right;
}
.act_as_cell.amount_total {
word-wrap:normal;
text-align:right;
font-weight: bold;
}
.list_table .act_as_cell{
padding-left: 5px;
/* border-right:1px solid lightGrey; uncomment to active column lines */
}
.list_table .act_as_cell.first_column {
padding-left: 0px;
/* border-left:1px solid lightGrey; uncomment to active column lines */
}
.sep_left {
border-left: 1px solid lightGrey;
}
]]>
</field>
<field name="name">Bank Statement Landscape Header</field>
</record>
</data>
</openerp>

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Joel Grand-Guillaume
# Author: Joel Grand-Guillaume
# Copyright 2011-2012 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
@@ -19,125 +19,32 @@
#
##############################################################################
from osv import fields, osv
from tools.translate import _
from account_statement_import.file_parser.parser import FileParser
import datetime
import netsvc
logger = netsvc.Logger()
from openerp.osv.orm import Model, fields
from openerp.osv import fields, osv
class AccountStatementProfil(Model):
"""
A Profile will contain all infos related to the type of
bank statement, and related generated entries. It defines the
journal to use, the partner and commision account and so on.
"""
_name = "account.statement.profil"
_description = "Statement Profil"
_columns = {
'name': fields.char('Name', size=128, required=True),
'partner_id': fields.many2one('res.partner',
'Bank/Payment Office partner',
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)."),
'journal_id': fields.many2one('account.journal',
'Financial journal to use for transaction',
required=True),
'commission_account_id': fields.many2one('account.account',
'Commission account',
required=True),
'commission_analytic_id': fields.many2one('account.analytic.account',
'Commission analytic account'),
'receivable_account_id': fields.many2one('account.account',
'Force Receivable/Payable Account',
help="Choose a receivable account to force the default\
debit/credit account (eg. an intermediat bank account instead of\
default debitors)."),
'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 intermediat/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."
),
'bank_statement_prefix': fields.char('Bank Statement Prefix', size=32),
'bank_statement_ids': fields.one2many('account.bank.statement', 'profile_id', 'Bank Statement Imported'),
}
def _check_partner(self, cr, uid, ids, context=None):
obj = self.browse(cr, uid, ids[0], context=context)
if obj.partner_id == False and obj.force_partner_on_bank:
return False
return True
_constraints = [
(_check_partner, "You need to put a partner if you tic the 'Force partner on bank move' !", []),
]
class AccountBankSatement(Model):
"""
We improve the bank statement class mostly for :
- Removing the period and compute it from the date of each line.
- Allow to remove the balance check depending on the chosen profil
- 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 had to override quite some long method and we'll need to maintain
them up to date. Changes are point up by '#Chg' comment.
"""
class AccountSatement(osv.osv):
"""Override account bank statement to remove the period on it
and compute it for each line."""
_inherit = "account.bank.statement"
_columns = {
'profile_id': fields.many2one('account.statement.profil',
'Profil', required=True, states={'draft': [('readonly', False)]}),
'credit_partner_id': fields.related(
'profile_id',
'partner_id',
type='many2one',
relation='res.partner',
string='Financial Partner',
store=True, readonly=True),
'balance_check': fields.related(
'profile_id',
'balance_check',
type='boolean',
string='Balance check',
store=True, readonly=True),
'journal_id': fields.related(
'profile_id',
'journal_id',
type='many2one',
relation='account.journal',
string='Journal',
store=True, readonly=True),
'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True),
}
_defaults = {
'period_id': lambda *a: False,
}
def create(self, cr, uid, vals, context=None):
"""Need to pass the journal_id in vals anytime because of account.cash.statement
need it."""
if 'profile_id' in vals:
profil_obj = self.pool.get('account.statement.profil')
profile = profil_obj.browse(cr,uid,vals['profile_id'],context)
vals['journal_id'] = profile.journal_id.id
return super(AccountBankSatement, self).create(cr, uid, vals, context=context)
def _get_period(self, cursor, uid, date, context=None):
"""
Find matching period for date, used in the statement line creation.
"""
'''
Find matching period for date, used in thestatement line creation.
'''
period_obj = self.pool.get('account.period')
periods = period_obj.find(cursor, uid, dt=date, context=context)
return periods and periods[0] or False
@@ -157,54 +64,22 @@ class AccountBankSatement(Model):
return False
return True
# Redefine the constraint, or it still refer to the original method
_constraints = [
(_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. So no need to unreconcile all entries,
then unpost them, then finaly cancel the bank statement.
"""
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):
"""
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.
Remove the entry posting on generated account moves.
We change the move line generated from the lines depending on the profil:
- If receivable_account_id is set, we'll use it instead of the "partner" one
- 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
for the debit line, but we'll change it on the credit move line for the choosen partner_id
=> This will ease the reconciliation process with the bank as the partner will match the bank
statement line
:param int/long: st_line_id: account.bank.statement.line ID
:param int/long: company_currency_id: res.currency ID
:param char: st_line_number: that will be used as the name of the generated account move
:return: int/long: ID of the created account.move
"""
Remove the entry posting on generated account moves."""
if context is None:
context = {}
res_currency_obj = self.pool.get('res.currency')
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') # Chg
st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context) # Chg
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
context.update({'date': st_line.date})
@@ -220,7 +95,7 @@ class AccountBankSatement(Model):
'name': st_line_number,
'ref': st_line.ref,
}, context=context)
account_bank_statement_line_obj.write(cr, uid, [st_line.id], { # Chg
account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
'move_ids': [(4, move_id, False)]
})
@@ -246,8 +121,7 @@ class AccountBankSatement(Model):
'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,
# Replace with the treasury one instead of bank #Chg
'statement_id': st.id,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id, #Chg
'currency_id': st.currency.id,
@@ -275,23 +149,16 @@ class AccountBankSatement(Model):
if st.currency.id <> company_currency_id:
amount_currency = st_line.amount
currency_id = st.currency.id
# GET THE RIGHT PARTNER ACCORDING TO THE CHOSEN PROFIL # Chg
if st.profile_id.force_partner_on_bank: # Chg
bank_parrtner_id = st.profile_id.partner_id.id # Chg
else: # Chg
bank_parrtner_id = ((st_line.partner_id) and st_line.partner_id.id) or False # Chg
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': bank_parrtner_id, # Chg
'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,
# Replace with the treasury one instead of bank #Chg
'statement_id': st.id,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': period_id, #Chg
'amount_currency': amount_currency,
@@ -310,50 +177,34 @@ class AccountBankSatement(Model):
account_move_obj.post(cr, uid, [move_id], context=context)
return move_id
def _get_st_number_period_profil(self, cr, uid, date, profile_id):
"""
Retrieve the name of bank statement from sequence, according to the period
corresponding to the date passed in args. Add a prefix if set in the profil.
:param: date: date of the statement used to compute the right period
:param: int/long: profile_id: the account.statement.profil ID from which to take the
bank_statement_prefix for the name
:return: char: name of the bank statement (st_number)
"""
def _get_st_number_period(self, cr, uid, date, journal_sequence_id):
"""Retrieve the name of bank statement from sequence, according to the period
corresponding to the date passed in args"""
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}
obj_seq = self.pool.get('ir.sequence')
journal_sequence_id = profile.journal_id.sequence_id and profile.journal_id.sequence_id.id or False
if journal_sequence_id:
st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c)
else:
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
def button_confirm_bank(self, cr, uid, ids, context=None):
"""
Completely override the method in order to have
an error message which displays all the messages
instead of having them pop one by one.
We have to copy paste a big block of code, changing the error
stack + managing period from date.
TODO: Log the error in a bank statement field instead of using a popup !
"""
"""Completely override the method in order to have
an error message which displays all the messages
instead of having them pop one by one.
We have to copy paste a big block of code, changing the error
stack + managing period from date."""
# obj_seq = self.pool.get('irerrors_stack.sequence')
if context is None:
context = {}
for st in self.browse(cr, uid, ids, context=context):
j_type = st.journal_id.type
company_currency_id = st.journal_id.company_id.currency_id.id
if not self.check_status_condition(cr, uid, st.state, journal_type=j_type):
continue
self.balance_check(cr, uid, st.id, journal_type=j_type, context=context)
if (not st.journal_id.default_credit_account_id) \
or (not st.journal_id.default_debit_account_id):
@@ -364,7 +215,13 @@ class AccountBankSatement(Model):
st_number = st.name
else:
# Begin Changes
st_number = self._get_st_number_period_profil(cr, uid, st.date, st.profile_id.id)
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)
# 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
for line in st.move_line_ids:
if line.state <> 'valid':
@@ -399,232 +256,21 @@ class AccountBankSatement(Model):
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)
def get_account_for_counterpart(self, cursor, uid,
amount, account_receivable, account_payable):
"""
Give the amount, payable and receivable account (that can be found using
get_default_pay_receiv_accounts method) and receive the one to use. This method
should be use when there is no other way to know which one to take.
:param float: amount of the line
:param int/long: account_receivable the receivable account
:param int/long: account_payable the payable account
:return: int/long :the default account to be used by statement line as the counterpart
of the journal account depending on the amount.
"""
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 get_default_pay_receiv_accounts(self, cursor, uid, context=None):
"""
We try to determine default payable/receivable accounts to be used as counterpart
from the company default propoerty. This is to be used if there is no otherway to
find the good one, or to find a default value that will be overriden by a completion
method (rules of account_statement_base_completion) afterwards.
:return: tuple of int/long ID that give account_receivable, account_payable based on
company default.
"""
account_receivable = False
account_payable = False
context = context or {}
property_obj = self.pool.get('ir.property')
model_fields_obj = self.pool.get('ir.model.fields')
model_fields_ids = model_fields_obj.search(
cursor,
uid,
[('name', 'in', ['property_account_receivable',
'property_account_payable']),
('model', '=', 'res.partner'),],
context=context
)
property_ids = property_obj.search(
cursor,
uid, [
('fields_id', 'in', model_fields_ids),
('res_id', '=', False),
],
context=context
)
for erp_property in property_obj.browse(cursor, uid,
property_ids, context=context):
if erp_property.fields_id.name == 'property_account_receivable':
account_receivable = erp_property.value_reference.id
elif erp_property.fields_id.name == 'property_account_payable':
account_payable = erp_property.value_reference.id
return account_receivable, account_payable
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,
return True and do nothing, otherwise call super.
:param int/long st_id: ID of the concerned account.bank.statement
:param char: journal_type that concern the bank statement
:return: True
"""
st = self.browse(cr, uid, st_id, context=context)
if st.balance_check:
return super(AccountBankSatement,self).balance_check(cr, uid, st_id, journal_type, context)
else:
return True
def onchange_imp_config_id(self, cr, uid, ids, profile_id, context=None):
"""
Compute values on the change of the profile.
:param: int/long: profile_id that changed
:return dict of dict with key = name of the field
"""
if not profile_id:
return {}
import_config = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
journal_id = import_config.journal_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
return {'value': {'journal_id':journal_id, 'account_id': account_id,
'balance_check':import_config.balance_check,
'credit_partner_id':credit_partner_id,
}}
class AccountBankSatementLine(Model):
"""
Override to compute the period from the date of the line, add a method to retrieve
the values for a line from the profile. Override the on_change method to take care of
the profile when fullfilling the bank statement manually. Set the reference to 64
Char long instead 32.
"""
_inherit = "account.bank.statement.line"
class AccountSatementLine(osv.osv):
'''
Adds the period on line, matched on the date.
'''
_inherit = 'account.bank.statement.line'
def _get_period(self, cursor, user, context=None):
"""
Return a period from a given date in the context.
"""
date = context.get('date', None)
periods = self.pool.get('account.period').find(cursor, user, dt=date)
return periods and periods[0] or False
_columns = {
# Set them as required + 64 char instead of 32
'ref': fields.char('Reference', size=64, required=True),
'period_id': fields.many2one('account.period', 'Period', required=True),
}
_defaults = {
'period_id': _get_period,
}
def get_values_for_line(self, cr, uid, profile_id = False, partner_id = False, line_type = False, amount = False, context = None):
"""
Return the account_id to be used in the line of a bank statement. It'll base the result as follow:
- If a receivable_account_id is set in the profil, return this value and type = general
- Elif line_type is given, take the partner receivable/payable property (payable if type= supplier, receivable
otherwise)
- Elif amount is given, take the partner receivable/payable property (receivable if amount >= 0.0,
payable otherwise). In that case, we also fullfill the type (receivable = customer, payable = supplier)
so it is easier for the accountant to know why the receivable/payable has been chosen
- Then, if no partner are given we look and take the property from the company so we always give a value
for account_id. Note that in that case, we return the receivable one.
:param int/long profile_id of the related bank statement
:param int/long partner_id of the line
:param char line_type: a value from: 'general', 'supplier', 'customer'
:param float: amount of the line
:return: A dict of value that can be passed directly to the write method of
the statement line:
{'partner_id': value,
'account_id' : value,
'type' : value,
...
}
"""
if context is None:
context = {}
res = {}
obj_partner = self.pool.get('res.partner')
obj_stat = self.pool.get('account.bank.statement')
receiv_account = pay_account = account_id = False
# If profil has a receivable_account_id, we return it in any case
if profile_id:
profile = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
if profile.receivable_account_id:
res['account_id'] = profile.receivable_account_id.id
res['type'] = 'general'
return res
# If partner -> take from him
if partner_id:
part = obj_partner.browse(cr, uid, partner_id, context=context)
pay_account = part.property_account_payable.id
receiv_account = part.property_account_receivable.id
# If no value, look on the default company property
if not pay_account or not receiv_account:
receiv_account, pay_account = obj_stat.get_default_pay_receiv_accounts(cr, uid, context=None)
# Now we have both pay and receive account, choose the one to use
# based on line_type first, then amount, otherwise take receivable one.
if line_type is not False:
if line_type == 'supplier':
res['account_id'] = pay_account
else:
res['account_id'] = receiv_account
elif amount is not False:
if amount >= 0:
res['account_id'] = receiv_account
res['type'] = 'customer'
else:
res['account_id'] = pay_account
res['type'] = 'supplier'
if not account_id:
res['account_id'] = receiv_account
return res
def onchange_partner_id(self, cr, uid, ids, partner_id, profile_id, context=None):
"""
Override of the basic method as we need to pass the profile_id in the on_change_type
call.
"""
obj_partner = self.pool.get('res.partner')
if context is None:
context = {}
if not partner_id:
return {}
part = obj_partner.browse(cr, uid, partner_id, context=context)
if not part.supplier and not part.customer:
type = 'general'
elif part.supplier and part.customer:
type = 'general'
else:
if part.supplier == True:
type = 'supplier'
if part.customer == True:
type = 'customer'
res_type = self.onchange_type(cr, uid, ids, partner_id, type, profile_id, context=context) # Chg
if res_type['value'] and res_type['value'].get('account_id', False):
return {'value': {'type': type, 'account_id': res_type['value']['account_id']}}
return {'value': {'type': type}}
def onchange_type(self, cr, uid, line_id, partner_id, type, profile_id, context=None):
"""
Keep the same features as in standard and call super. If an account is returned,
call the method to compute line values.
"""
if context is None:
context = {}
res = super(AccountBankSatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context)
if 'account_id' in res['value']:
result = self.get_values_for_line(cr, uid, profile_id = profile_id,
partner_id = partner_id, line_type = type, context = context)
if result:
res['value'].update({'account_id':result['account_id']})
return res

View File

@@ -1,76 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Account Move Line : add statement_treasury_id -->
<record id="view_move_line_tree" model="ir.ui.view">
<field name="name">account.move.line.tree</field>
<field name="model">account.move.line</field>
<field name="type">tree</field>
<field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="arch" type="xml">
<field name="ref" position="after">
<field name="statement_id"/>
</field>
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="model">account.move.line</field>
<field name="type">search</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<field name="period_id" context="{'period_id':self}" position="after">
<field name="statement_id"/>
</field>
</field>
</record>
<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>
<record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Import statement">
<separator string="" colspan="4"/>
<field name="name" select="1" />
<field name="partner_id" select="1"/>
<field name="journal_id" select="1"/>
<field name="commission_account_id" />
<field name="commission_analytic_id" />
<field name="receivable_account_id" />
<field name="force_partner_on_bank"/>
<field name="balance_check"/>
<field name="bank_statement_prefix"/>
</form>
<field name="period_id" position="replace"/>
</field>
</record>
<record id="statement_importer_view_tree" model="ir.ui.view">
<field name="name">account.statement.profil.view</field>
<field name="model">account.statement.profil</field>
<record id="view_banking_bank_statement_tree" model="ir.ui.view">
<field name="name">account.bank.statement.tree.banking</field>
<field name="inherit_id" ref="account.view_bank_statement_tree" />
<field name="model">account.bank.statement</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Import statement">
<field name="name" />
<field name="partner_id" />
<field name="journal_id" />
<field name="commission_account_id" />
<field name="commission_analytic_id" />
<field name="receivable_account_id" />
<field name="force_partner_on_bank"/>
<field name="balance_check"/>
</tree>
<field name="period_id" position="replace"/>
</field>
</record>
<record id="action_treasury_statement_profil_tree" model="ir.actions.act_window">
<field name="name">Bank Statements Profile</field>
<field name="res_model">account.statement.profil</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<record id="view_banking_bank_statement_form_add_period" model="ir.ui.view">
<field name="name">account.bank.statement.form.add_period</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">
<xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='ref']" position="after">
<field name="period_id"/>
</xpath>
</field>
</record>
<menuitem string="Bank Statements Profile" action="action_treasury_statement_profil_tree" id="menu_treasury_statement_profil_tree" parent="account.menu_configuration_misc" sequence="30"/>
<record id="view_banking_bank_statement_add_period_2" model="ir.ui.view">
<field name="name">account.bank.statement.form.add_period2</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">
<data>
<xpath expr="/form/notebook/page[@string='Transaction']/field/form/field[@name='ref']" position="after">
<field name="period_id"/>
</xpath>
</data>
</field>
</record>
<record model="ir.ui.view" id="id_in_statement_line">
<field name="name">account.bank.statement.line.inherit</field>
<field name="model">account.bank.statement</field>
@@ -83,120 +58,6 @@
</field>
</record>
<record id="view_treasury_statement_search" model="ir.ui.view">
<field name="name">account.bank.statement.search</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_search"/>
<field name="type">search</field>
<field name="arch" type="xml">
<xpath expr="/search/group/field[@name='name']" position="before">
<field name="profile_id"/>
<field name="credit_partner_id"/>
<separator orientation="vertical"/>
</xpath>
<xpath expr="/search/group/field[@name='period_id']" position="replace">
</xpath>
<xpath expr="/search/group/filter[@string='Period']" position="replace">
<filter string="Financial Partner" context="{'group_by': 'credit_partner_id'}" icon="terp-partner"/>
</xpath>
</field>
</record>
<record id="view_treasury_statement_tree" model="ir.ui.view">
<field name="name">account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="type">tree</field>
<field name="arch" type="xml">
<xpath expr="/tree/field[@name='name']" position="after">
<field name="profile_id"/>
</xpath>
<xpath expr="/tree/field[@name='period_id']" position="replace">
<field name="credit_partner_id"/>
</xpath>
</field>
</record>
<record id="view_treasury_statement_form" model="ir.ui.view">
<field name="name">account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<!-- Remove name and date from group tag -->
<xpath expr="/form/group/field[@name='name']" position="replace">
</xpath>
<xpath expr="/form/group/field[@name='date']" position="replace">
</xpath>
<!-- Add a new group before the first one with name, profil and date -->
<xpath expr="/form/group[@col='7']" position="before">
<group col="6" colspan="4">
<field name="name" select="1"/>
<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)"/>
</group>
<separator string="Details" colspan="4"/>
</xpath>
<!-- Make balance visible or not depending on profil -->
<xpath expr="/form/group/field[@name='balance_start']" position="replace">
</xpath>
<xpath expr="/form/group/field[@name='balance_end_real']" position="replace">
</xpath>
<xpath expr="/form/group[@col='7']" position="after">
<separator string="Balance Check" colspan="4" attrs="{'invisible':[('balance_check','=',False)]}"/>
<group col="6" colspan="4" attrs="{'invisible':[('balance_check','=',False)]}">
<field name="balance_start" />
<field name="balance_end_real" />
</group>
</xpath>
<xpath expr="/form/group/field[@name='balance_end']" position="replace">
<field name="balance_end" attrs="{'invisible':[('balance_check','=',False)]}"/>
</xpath>
<xpath expr="/form/group/field[@name='journal_id']" position="attributes">
<attribute name="widget"></attribute>
</xpath>
<xpath expr="/form/group/field[@name='period_id']" position="replace">
<field name="credit_partner_id"/>
<field name="account_id" invisible="1"/>
<field name="balance_check" invisible="1"/>
</xpath>
<xpath expr="/form/notebook/page/field/tree/field[@name='sequence']" position="after">
<field name="id"/>
</xpath>
<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.profile_id)"/>
</xpath>
<xpath expr="/form/notebook/page/field/form/field[@name='date']" position="before">
<field name="id"/>
</xpath>
<!-- Adapt onchange signature -->
<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.profile_id)"/>
</xpath>
<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.profile_id)"/>
</xpath>
<xpath expr="/form/notebook/page/field/form/field[@name='type']" position="replace">
<field name="type" on_change="onchange_type(partner_id, type, parent.profile_id)"/>
</xpath>
<xpath expr="/form/notebook/page/field/tree/field[@name='type']" position="replace">
<field name="type" on_change="onchange_type(partner_id, type, parent.profile_id)"/>
</xpath>
</field>
</record>
<act_window id="act_bank_statement_from_profile"
name="Open Statements"
res_model="account.bank.statement"
src_model="account.statement.profil"
domain="[('profile_id','=',active_id),]"
view_type="form"/>
</data>
</openerp>