[IMP] Improved bank account management, report footer, stages by default on projects

bzr revid: fp@fp-laptop-20110815142141-938zg1laoe8wtbkd
This commit is contained in:
fp 2011-08-15 16:21:41 +02:00
parent 941496a321
commit fa7874cddc
19 changed files with 250 additions and 164 deletions

View File

@ -25,6 +25,7 @@ import project
import partner
import invoice
import account_bank_statement
import account_bank
import account_cash_statement
import account_move_line
import account_analytic_line

View File

@ -122,7 +122,8 @@ module named account_voucher.
'company_view.xml',
'board_account_view.xml',
"wizard/account_report_profit_loss_view.xml",
"wizard/account_report_balance_sheet_view.xml"
"wizard/account_report_balance_sheet_view.xml",
"account_bank_view.xml"
],
'demo_xml': [
'demo/account_demo.xml',

View File

@ -602,7 +602,7 @@ class account_journal(osv.osv):
_description = "Journal"
_columns = {
'name': fields.char('Journal Name', size=64, required=True),
'code': fields.char('Code', size=5, required=True, help="The code will be used to generate the numbers of the journal entries of this journal."),
'code': fields.char('Code', size=5, required=True, help="The code will be displayed on reports."),
'type': fields.selection([('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Cheques'), ('general', 'General'), ('situation', 'Opening/Closing Situation')], 'Type', size=32, required=True,
help="Select 'Sale' for Sale journal to be used at the time of making invoice."\
" Select 'Purchase' for Purchase Journal to be used at the time of approving purchase order."\
@ -2675,9 +2675,10 @@ class wizard_multi_charts_accounts(osv.osv_memory):
return False
def _get_default_accounts(self, cr, uid, context=None):
return [{'acc_name': _('Current'),'account_type':'bank'},
{'acc_name': _('Deposit'),'account_type':'bank'},
{'acc_name': _('Cash'),'account_type':'cash'}]
return [
{'acc_name': _('Bank Account'),'account_type':'bank'},
{'acc_name': _('Cash'),'account_type':'cash'}
]
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, [uid], c)[0].company_id.id,

View File

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 _
from osv import fields, osv
class bank(osv.osv):
_inherit = "res.partner.bank"
_columns = {
'journal_id': fields.many2one('account.journal', 'Account Journal', help="This journal will be created automatically for this bank account when you save the record"),
}
def create(self, cr, uid, data, context={}):
result = super(bank, self).create(cr, uid, data, context=context)
self.post_write(cr, uid, [result], context=context)
return result
def write(self, cr, uid, ids, data, context={}):
result = super(bank, self).write(cr, uid, ids, data, context=context)
self.post_write(cr, uid, ids, context=context)
return result
def post_write(self, cr, uid, ids, context={}):
obj_acc = self.pool.get('account.account')
obj_data = self.pool.get('ir.model.data')
for bank in self.browse(cr, uid, ids, context):
if bank.company_id and not bank.journal_id:
# Find the code and parent of the bank account to create
dig = 6
current_num = 1
ids = obj_acc.search(cr, uid, [('type','=','liquidity')], context=context)
# No liquidity account exists, no template available
if not ids: continue
ref_acc_bank_temp = obj_acc.browse(cr, uid, ids[0], context=context)
ref_acc_bank = ref_acc_bank_temp.parent_id
while True:
new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num)
ids = obj_acc.search(cr, uid, [('code', '=', new_code), ('company_id', '=', bank.company_id.id)])
if not ids:
break
current_num += 1
acc = {
'name': (bank.bank_name or '')+' '+bank.acc_number,
'currency_id': bank.company_id.currency_id.id,
'code': new_code,
'type': 'liquidity',
'user_type': ref_acc_bank_temp.user_type.id,
'reconcile': False,
'parent_id': ref_acc_bank.id,
'company_id': bank.company_id.id,
}
acc_bank_id = obj_acc.create(cr,uid,acc,context=context)
# Get the journal view id
data_id = obj_data.search(cr, uid, [('model','=','account.journal.view'), ('name','=','account_journal_bank_view')])
data = obj_data.browse(cr, uid, data_id[0], context=context)
view_id_cash = data.res_id
jour_obj = self.pool.get('account.journal')
new_code = 1
while True:
code = _('BNK')+str(new_code)
ids = jour_obj.search(cr, uid, [('code','=',code)], context=context)
if not ids:
break
new_code += 1
#create the bank journal
vals_journal = {
'name': (bank.bank_name or '')+' '+bank.acc_number,
'code': code,
'type': 'bank',
'company_id': bank.company_id.id,
'analytic_journal_id': False,
'currency_id': False,
'default_credit_account_id': acc_bank_id,
'default_debit_account_id': acc_bank_id,
'view_id': view_id_cash
}
journal_id = jour_obj.create(cr, uid, vals_journal, context=context)
self.write(cr, uid, [bank.id], {'journal_id': journal_id}, context=context)
return True

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!--
Bank Accounts
-->
<record id="view_partner_bank_form_inherit" model="ir.ui.view">
<field name="name">Partner Bank Accounts - Journal</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<group name="bank" position="after">
<group name="accounting" col="2" colspan="2" attrs="{'invisible': [('company_id','=', False)]}">
<separator string="Accounting Information" colspan="2"/>
<field name="journal_id"/>
</group>
</group>
</field>
</record>
<record id="action_bank_tree" model="ir.actions.act_window">
<field name="name">Bank Accounts</field>
<field name="res_model">res.partner.bank</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context" eval="{'default_partner_id':ref('base.main_partner'), 'company_hide':False, 'default_company_id':ref('base.main_company'), 'search_default_my_bank':1}"/>
<field name="help">Configure your company's bank account and select those that must appear on the report footer. You can drag &amp; drop bank in the list view to reorder bank accounts. If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.</field>
</record>
<menuitem
sequence="0"
parent="account.account_account_menu"
id="menu_action_bank_tree"
action="action_bank_tree"/>
<record id="account_configuration_bank_todo" model="ir.actions.todo">
<field name="action_id" ref="action_bank_tree"/>
<field name="category_id" ref="category_accounting_configuration"/>
<field name="sequence">4</field>
</record>
</data>
</openerp>

View File

@ -767,7 +767,7 @@
<field name="search_view_id" ref="view_account_type_search"/>
<field name="help">An account type is used to determine how an account is used in each journal. The deferral method of an account type determines the process for the annual closing. Reports such as the Balance Sheet and the Profit and Loss report use the category (profit/loss or balance sheet). For example, the account type could be linked to an asset account, expense account or payable account. From this view, you can create and manage the account types you need for your company.</field>
</record>
<menuitem action="action_account_type_form" sequence="6" id="menu_action_account_type_form" parent="account_account_menu"/>
<menuitem action="action_account_type_form" sequence="6" id="menu_action_account_type_form" parent="account_account_menu" groups="base.group_extended"/>
<!--
Entries
-->

View File

@ -97,27 +97,30 @@
<form string="Bank account">
<field name="state"/>
<newline/>
<field name="acc_number" attrs="{'invisible':[('state','!=','bank')]}"/>
<field name="acc_number"/>
<newline/>
<field name="bank"/>
<newline/>
<field name="sequence"/>
<field colspan="4" name="name"/>
<separator colspan="4" string="Bank account owner"/>
<field colspan="4" name="owner_name"/>
<field colspan="4" name="street"/>
<newline/>
<field name="zip"/>
<field name="city"/>
<newline/>
<field completion="1" name="country_id"/>
<field name="state_id"/>
<group name="owner" colspan="2" col="2">
<separator colspan="4" string="Bank Account Owner"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="owner_name"/>
<field name="street"/>
<field name="city"/>
<field name="zip"/>
<field name="state_id"/>
<field name="country_id"/>
</group>
<group name="bank" colspan="2" col="2">
<separator colspan="2" string="Information About the Bank"/>
<field name="bank" on_change="onchange_bank_id(bank)" groups="base.group_extended"/>
<field name="bank_name"/>
<field name="bank_bic"/>
</group>
</form>
<tree string="Bank Details">
<field name="state"/>
<field name="bank"/>
<field name="owner_name"/>
<field name="sequence" invisible="1"/>
<field name="acc_number"/>
<field name="bank_name"/>
<field name="owner_name"/>
</tree>
</field>
</page>

View File

@ -2,7 +2,7 @@
<openerp>
<data noupdate="1">
<record id="analytic_root" model="account.analytic.account">
<field name="name" model="res.company" use="name" search="[('id', '=', 1)]"/>
<field name="name" model="res.company" use="name" search="[]"/>
<field name="code">0</field>
</record>
<record id="analytic_absences" model="account.analytic.account">

View File

@ -83,14 +83,14 @@ class res_partner_bank(osv.osv):
def create(self, cr, uid, vals, context=None):
#overwrite to format the iban number correctly
if 'iban' in vals and vals['iban']:
vals['iban'] = _format_iban(vals['iban'])
if (vals.get('state',False)=='iban') and vals.get('acc_number', False):
vals['acc_number'] = _format_iban(vals['acc_number'])
return super(res_partner_bank, self).create(cr, uid, vals, context)
def write(self, cr, uid, ids, vals, context=None):
#overwrite to format the iban number correctly
if 'iban' in vals and vals['iban']:
vals['iban'] = _format_iban(vals['iban'])
if (vals.get('state',False)=='iban') and vals.get('acc_number', False):
vals['acc_number'] = _format_iban(vals['acc_number'])
return super(res_partner_bank, self).write(cr, uid, ids, vals, context)
def check_iban(self, cr, uid, ids, context=None):
@ -98,9 +98,9 @@ class res_partner_bank(osv.osv):
Check the IBAN number
'''
for bank_acc in self.browse(cr, uid, ids, context=context):
if not bank_acc.iban:
if bank_acc.state<>'iban':
continue
iban = _format_iban(bank_acc.iban).lower()
iban = _format_iban(bank_acc.acc_number).lower()
if iban[:2] in _iban_len and len(iban) != _iban_len[iban[:2]]:
return False
#the four first digits have to be shifted to the end
@ -122,39 +122,11 @@ class res_partner_bank(osv.osv):
def default_iban_check(iban_cn):
return iban_cn[0] in string.ascii_lowercase and iban_cn[1] in string.ascii_lowercase
iban_country = self.browse(cr, uid, ids)[0].iban[:2]
iban_country = self.browse(cr, uid, ids)[0].acc_number[:2].lower()
if default_iban_check(iban_country):
iban_example = iban_country in _ref_iban and _ref_iban[iban_country] + ' \nWhere A = Account number, B = National bank code, S = Branch code, C = account No, N = branch No, K = National check digits....' or ''
return _('The IBAN does not seem to be correct. You should have entered something like this %s'), (iban_example)
return _('The IBAN is invalid, It should begin with the country code'), ()
def name_get(self, cr, uid, ids, context=None):
res = []
to_check_ids = []
for val in self.browse(cr, uid, ids, context=context):
if val.state=='iban':
iban = _pretty_iban(val.iban or '')
bic = val.bank.bic or ''
res.append((val.id, _('IBAN: %s / BIC: %s') % (iban, bic)))
else:
to_check_ids.append(val.id)
res += super(res_partner_bank, self).name_get(cr, uid, to_check_ids, context=context)
return res
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
#overwrite the search method in order to search not only on bank type == basic account number but also on type == iban
res = super(res_partner_bank,self).search(cr, uid, args, offset, limit, order, context=context, count=count)
if filter(lambda x:x[0]=='acc_number' ,args):
#get the value of the search
iban_value = filter(lambda x:x[0]=='acc_number' ,args)[0][2]
#get the other arguments of the search
args1 = filter(lambda x:x[0]!='acc_number' ,args)
#add the new criterion
args1 += [('iban','ilike',iban_value)]
#append the results to the older search
res += super(res_partner_bank,self).search(cr, uid, args1, offset, limit,
order, context=context, count=count)
return res
return _('The IBAN is invalid, it should begin with the country code'), ()
def get_bban_from_iban(self, cr, uid, ids, context=None):
'''
@ -169,21 +141,23 @@ class res_partner_bank(osv.osv):
'gb': lambda x: x[14:],
}
for record in self.browse(cr, uid, ids, context=context):
if not record.iban:
if not record.acc_number:
res[record.id] = False
continue
res[record.id] = False
for code, function in mapping_list.items():
if record.iban.lower().startswith(code):
res[record.id] = function(record.iban)
if record.acc_number.lower().startswith(code):
res[record.id] = function(record.acc_number)
break
return res
_columns = {
'iban': fields.char('IBAN', size=34, readonly=True, help="International Bank Account Number"),
# Deprecated: we keep it for backward compatibility, to be removed in v7
# We use acc_number instead of IBAN since v6.1, but we keep this field
# to not break community modules.
'iban': fields.related('acc_number', string='IBAN', size=34, readonly=True, help="International Bank Account Number", type="char"),
}
_constraints = [(check_iban, _construct_constraint_msg, ["iban"])]
_constraints = [(check_iban, _construct_constraint_msg, ["acc_number"])]
res_partner_bank()

View File

@ -8,15 +8,10 @@
<record id="bank_iban" model="res.partner.bank.type">
<field name="name">IBAN Account</field>
<field name="code">iban</field>
</record>
<record id="bank_iban_field" model="res.partner.bank.type.field">
<field name="name">iban</field>
<field name="bank_type_id" ref="bank_iban"/>
<field eval="True" name="required"/>
<field eval="False" name="readonly"/>
<field name="format_layout">%(bank_name)s: IBAN %(acc_number)s - BIC %(bank_bic)s</field>
</record>
<record id="bank_swift_field" model="res.partner.bank.type.field">
<field name="name">bic</field>
<field name="name">bank_bic</field>
<field name="bank_type_id" ref="bank_iban"/>
<field eval="True" name="required"/>
<field eval="False" name="readonly"/>
@ -33,11 +28,5 @@
<field eval="False" name="required"/>
<field eval="False" name="readonly"/>
</record>
<record id="bank_acc_number_field" model="res.partner.bank.type.field">
<field name="name">acc_number</field>
<field name="bank_type_id" ref="bank_iban"/>
<field eval="False" name="required"/>
<field eval="True" name="readonly"/>
</record>
</data>
</openerp>

View File

@ -2,57 +2,5 @@
<openerp>
<data>
<record id="view_partner_bank_iban_form" model="ir.ui.view">
<field name="name">res.partner.bank.form.iban.inherit</field>
<field name="model">res.partner.bank</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="acc_number" position="after">
<newline/>
<field name="iban"/>
<newline/>
</field>
</field>
</record>
<record id="view_partner_abnk_iban_tree" model="ir.ui.view">
<field name="name">res.partner.bank.tree.iban.inherit</field>
<field name="model">res.partner.bank</field>
<field name="inherit_id" ref="base.view_partner_bank_tree"/>
<field name="type">tree</field>
<field name="arch" type="xml">
<field name="acc_number" position="after">
<field name="iban"/>
</field>
</field>
</record>
<!-- view for res.partner -->
<record id="view_partner_iban_form" model="ir.ui.view">
<field name="name">res.partner.form.iban.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="acc_number" position="after">
<newline/>
<field name="iban" attrs="{'invisible':[('state','!=','iban')]}"/>
<newline/>
</field>
</field>
</record>
<record id="view_partner_iban_list" model="ir.ui.view">
<field name="name">res.partner.form.iban.inherit.list</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='bank_ids']/tree/field[@name='acc_number']" position="after">
<field name="iban"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -16,6 +16,10 @@
<field name="implied_ids" eval="[(4, ref('base.group_sale_salesman_all_leads'))]"/>
</record>
<record model="res.users" id="base.user_admin">
<field eval="[(4,ref('base.group_partner_manager'))]" name="groups_id"/>
</record>
<record id="crm_rule_personal_lead" model="ir.rule">
<field name="name">Personal Leads</field>
<field ref="model_crm_lead" name="model_id"/>

View File

@ -3,10 +3,10 @@
<data noupdate="1">
<record id="base.group_hr_user" model="res.groups">
<field name="name">Human Resources / Officer</field>
<field name="name">Human Resources / HR Officer</field>
</record>
<record id="base.group_hr_manager" model="res.groups">
<field name="name">Human Resources / Manager</field>
<field name="name">Human Resources / HR Manager</field>
<field name="implied_ids" eval="[(4, ref('base.group_hr_user'))]"/>
</record>

View File

@ -121,7 +121,7 @@ class mrp_repair(osv.osv):
'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, domain="[('product_id','=',product_id)]"),
'state': fields.selection([
('draft','Quotation'),
('confirmed','Confirmed'),
('confirmed','Confirmed, to repair'),
('ready','Ready to Repair'),
('under_repair','Under Repair'),
('2binvoiced','To be Invoiced'),

View File

@ -26,10 +26,10 @@ from datetime import datetime, date
from tools.translate import _
from osv import fields, osv
class project_project(osv.osv):
_name = 'project.project'
project_project()
# I think we can remove this in v6.1 since VMT's improvements in the framework ?
#class project_project(osv.osv):
# _name = 'project.project'
#project_project()
class project_task_type(osv.osv):
_name = 'project.task.type'
@ -39,13 +39,12 @@ class project_task_type(osv.osv):
'name': fields.char('Stage Name', required=True, size=64, translate=True),
'description': fields.text('Description'),
'sequence': fields.integer('Sequence'),
'project_default': fields.boolean('Common to All Projects', help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."),
'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
}
_defaults = {
'sequence': 1
}
project_task_type()
class project(osv.osv):
@ -150,11 +149,16 @@ class project(osv.osv):
'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
}
def _get_type_common(self, cr, uid, context):
ids = self.pool.get('project.task.type').search(cr, uid, [('project_default','=',1)], context=context)
return ids
_order = "sequence"
_defaults = {
'active': True,
'priority': 1,
'sequence': 10,
'type_ids': _get_type_common
}
# TODO: Why not using a SQL contraints ?

View File

@ -15,10 +15,9 @@
<field name="object">project.task</field>
</record>
<!--
Resource: project.project
-->
Resource: project.project
-->
<record id="all_projects_account" model="account.analytic.account">
<field name="name">Projects</field>
@ -26,5 +25,29 @@
</record>
<function eval="('default',False,'parent_id', [('project.project', False)], all_projects_account, True, False, False, False, True)" id="parent_project_default_set" model="ir.values" name="set"/>
<!-- Task Stages -->
<record id="project_tt_specification" model="project.task.type">
<field name="sequence">1</field>
<field name="name">Design</field>
<field name="project_default" eval="1"/>
</record>
<record id="project_tt_development" model="project.task.type">
<field name="sequence">2</field>
<field name="name">Development</field>
<field name="project_default" eval="1"/>
</record>
<record id="project_tt_testing" model="project.task.type">
<field name="sequence">3</field>
<field name="name">Testing</field>
<field name="project_default" eval="1"/>
</record>
<record id="project_tt_merge" model="project.task.type">
<field name="sequence">4</field>
<field name="name">Deployment</field>
<field name="project_default" eval="1"/>
</record>
</data>
</openerp>

View File

@ -221,26 +221,8 @@
<record id="base.main_company" model="res.company">
<field name="project_time_mode_id" ref="product.uom_hour"></field>
</record>
<!-- Task Types -->
<record id="project_tt_specification" model="project.task.type">
<field name="sequence">1</field>
<field name="name">Specification</field>
</record>
<record id="project_tt_development" model="project.task.type">
<field name="sequence">2</field>
<field name="name">Development</field>
</record>
<record id="project_tt_testing" model="project.task.type">
<field name="sequence">3</field>
<field name="name">Testing</field>
</record>
<record id="project_tt_merge" model="project.task.type">
<field name="sequence">4</field>
<field name="name">Merge</field>
</record>
<!-- Projects -->
<!-- <record id="all_projects_account" model="project.project">
<field name="name">Projects</field>
<field name="code">3</field>

View File

@ -247,7 +247,7 @@
</group>
<field colspan="4" name="description" nolabel="1" attrs="{'readonly':[('state','=','done')]}" widget="text_wiki"/>
<field colspan="4" name="work_ids" nolabel="1" attrs="{'invisible':[('state','in',['draft'])],'readonly':[('state','=','done')]}">
<field colspan="4" name="work_ids" nolabel="1" attrs="{'readonly':[('state','in',['done','draft'])]}">
<tree string="Task Work" editable="top">
<field name="name" />
<field name="hours" widget="float_time" sum="Spent Hours"/>
@ -481,8 +481,11 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Task Stage">
<group colspan="4" col="6">
<field name="name" select="1"/>
<field name="project_default"/>
<field name="sequence"/>
</group>
<separator string="Description" colspan="4"/>
<field colspan="4" name="description" nolabel="1"/>
</form>

View File

@ -17,10 +17,12 @@
<field name="implied_ids" eval="[(4, ref('base.group_sale_salesman_all_leads'))]"/>
</record>
<record model="res.users" id="base.user_admin">
<field eval="[(4,ref('base.group_partner_manager'))]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="base.menu_base_partner">
<field eval="[(4, ref('base.group_sale_salesman'))]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="base.menu_base_config">
<field eval="[(4, ref('base.group_sale_manager'))]" name="groups_id"/>
</record>