[IMP] account: account reconcile partner process

bzr revid: mra@mra-laptop-20100618111559-knik7r51ry3se6wh
This commit is contained in:
Mustufa Rangwala 2010-06-18 16:45:59 +05:30
parent 5f78d076bf
commit 509cf3964e
11 changed files with 237 additions and 19 deletions

View File

@ -34,14 +34,15 @@
Budgets
Customer and Supplier Invoices
Bank statements
Reconciliation process by partner
Creates a dashboards for accountants that includes:
* List of uninvoiced quotations
* Graph of aged receivables
* Graph of aged incomes
* Graph of aged incomes
The processes like maintaining of general ledger is done through the defined financial Journals (entry move line or
grouping is maintained through journal) for a particular financial year and for preparation of vouchers there is a
module named account_voucherss
module named account_vouchers
""",
'website': 'http://www.openerp.com',
'init_xml': [],
@ -85,6 +86,7 @@ module named account_voucherss
'wizard/account_compare_account_balance_report_view.xml',
'wizard/account_third_party_ledger.xml',
'wizard/account_reconcile_view.xml',
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml',
'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.xml',

View File

@ -577,6 +577,39 @@ class account_move_line(osv.osv):
# writeoff; entry generated for the difference between the lines
#
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context is None:
context = {}
if context and context.get('next_partner_only', False):
if not context.get('partner_id', False):
partner = self.get_next_partner_only(cr, uid, offset, context)
else:
partner = context.get('partner_id', False)
if not partner:
return []
args.append(('partner_id', '=', partner[0]))
return super(account_move_line, self).search(cr, uid, args, offset, limit, order, context, count)
def get_next_partner_only(self, cr, uid, offset=0, context=None):
cr.execute(
"""
SELECT p.id
FROM res_partner p
RIGHT JOIN (
SELECT l.partner_id as partner_id, SUM(l.debit) as debit, SUM(l.credit) as credit
FROM account_move_line l
LEFT JOIN account_account a ON (a.id = l.account_id)
LEFT JOIN res_partner p ON (l.partner_id = p.id)
WHERE a.reconcile IS TRUE
AND l.reconcile_id IS NULL
AND (p.last_reconciliation_date IS NULL OR l.date > p.last_reconciliation_date)
AND l.state <> 'draft'
GROUP BY l.partner_id
) AS s ON (p.id = s.partner_id)
ORDER BY p.last_reconciliation_date LIMIT 1 OFFSET %s""", (offset,)
)
return cr.fetchone()
def reconcile_partial(self, cr, uid, ids, type='auto', context=None):
merges = []
unmerge = []
@ -730,6 +763,11 @@ class account_move_line(osv.osv):
# because of the way the line_id are defined: (4, x, False)
for id in ids:
wf_service.trg_trigger(uid, 'account.move.line', id, cr)
if lines and lines[0]:
partner_id = lines[0].partner_id.id
if context and context.get('stop_reconcile', False):
self.pool.get('res.partner').write(cr, uid, [partner_id], {'last_reconciliation_date': time.strftime('%Y-%m-%d %H:%M:%S')})
return r_id
def view_header_get(self, cr, user, view_id, view_type, context):

View File

@ -842,7 +842,9 @@
<separator orientation="vertical"/>
<field name="date" select='1'/>
<field name="account_id" select='1'/>
<field name="partner_id" select='1'/>
<field name="partner_id" select='1'>
<filter help="Next Partner Entries to reconcile" name="next_partner" string="Next Partner to reconcile" context="{'next_partner_only': 1}" icon="terp-partner" domain="[('account_id.reconcile','=',True),('reconcile_id','=',False)]"/>
</field>
<field name="balance" string="Debit/Credit" select='1'/>
</group>
</search>
@ -1182,6 +1184,18 @@
id="menu_action_account_bank_reconcile_check_tree"
parent="periodical_processing_reconciliation" groups="group_account_user" />
<act_window
context="{'search_default_next_partner':1}"
id="action_account_manual_reconcile" name="Entry Lines"
res_model="account.move.line"
/>
<menuitem
name="Manual Reconcilication" icon="STOCK_EXECUTE"
action="action_account_manual_reconcile"
id="menu_manual_reconcile"
parent="account.periodical_processing_reconciliation"/>
<act_window
domain="[('account_id', '=', active_id)]"

View File

@ -52,18 +52,15 @@
<!-- <wizard id="wizard_reconcile_unreconcile" model="account.move.reconcile" name="account.reconcile.unreconcile" string="Unreconcile Entries"/>-->
<!-- <wizard id="wizard_reconcile_select" menu="False" model="account.move.line" name="account.move.line.reconcile.select" string="Reconcile entries"/>
<menuitem action="wizard_reconcile_select" id="menu_reconcile_select" parent="account.next_id_20" type="wizard"/>
-->
<!-- <wizard id="wizard_reconcile_select" menu="False" model="account.move.line" name="account.move.line.reconcile.select" string="Reconcile entries"/> -->
<!-- <menuitem action="wizard_reconcile_select" id="menu_reconcile_select" parent="account.next_id_20" type="wizard"/> -->
<!-- unreconcile -->
<!-- <wizard id="wizard_unreconcile" model="account.move.line" name="account.move.line.unreconcile" string="Unreconcile Entries"/>-->
<!-- unreconcile
<wizard id="wizard_unreconcile_select" menu="False" model="account.move.line" name="account.move.line.unreconcile.select" string="Unreconcile entries"/>
<menuitem action="wizard_unreconcile_select" id="menu_unreconcile_select" parent="account.next_id_20" type="wizard"/>
-->
<!-- <wizard id="wizard_unreconcile_select" menu="False" model="account.move.line" name="account.move.line.unreconcile.select" string="Unreconcile entries"/> -->
<!-- <menuitem action="wizard_unreconcile_select" id="menu_unreconcile_select" parent="account.next_id_20" type="wizard"/> -->
<!-- subscriptions -->
<!--

View File

@ -89,7 +89,7 @@ class res_partner(osv.osv):
_name = 'res.partner'
_inherit = 'res.partner'
_description = 'Partner'
def _credit_debit_get(self, cr, uid, ids, field_names, arg, context):
query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
cr.execute("""SELECT l.partner_id, a.type, SUM(l.debit-l.credit)
@ -114,7 +114,7 @@ class res_partner(osv.osv):
if val is None: val=0
res[pid][maps[type]] = (type=='receivable') and val or -val
return res
def _asset_difference_search(self, cr, uid, obj, name, type, args, context=None):
if not len(args):
return []
@ -136,7 +136,7 @@ class res_partner(osv.osv):
if not len(res):
return [('id','=','0')]
return [('id','in',map(itemgetter(0), res))]
def _credit_search(self, cr, uid, obj, name, args, context):
return self._asset_difference_search(cr, uid, obj, name, 'receivable', args, context=context)
@ -187,6 +187,7 @@ class res_partner(osv.osv):
help="This payment term will be used instead of the default one for the current partner"),
'ref_companies': fields.one2many('res.company', 'partner_id',
'Companies that refers to partner'),
'last_reconciliation_date': fields.datetime('Last Reconcilation Date', help='Date on which partner account entries reconciled last time')
}
res_partner()

View File

@ -122,10 +122,10 @@
</notebook>
</field>
</record>
<!-- Partners info tab view-->
<act_window
<act_window
id="action_analytic_open"
name="Analytic Accounts"
res_model="account.analytic.account"
@ -134,5 +134,16 @@
view_type="form"
view_mode="tree,form,graph,calendar"/>
<record id="view_res_partner_reconcile" model="ir.ui.view">
<field name="name">res.partner.form.reconcile</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="credit_limit" position="after">
<field name="last_reconciliation_date"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@ -22,6 +22,7 @@
import account_automatic_reconcile
import account_move_line_reconcile_select
import account_move_line_unreconcile_select
import account_reconcile_partner_process
import account_reconcile
import account_unreconcile
import account_invoice_refund

View File

@ -31,8 +31,8 @@
<field name="target">new</field>
</record>
<menuitem action="action_account_reconcile_select"
id="menu_reconcile_select" parent="periodical_processing_reconciliation" />
<!-- <menuitem action="action_account_reconcile_select"
id="menu_reconcile_select" parent="periodical_processing_reconciliation" /> -->
</data>
</openerp>

View File

@ -31,8 +31,8 @@
<field name="target">new</field>
</record>
<menuitem action="action_account_unreconcile_select"
id="menu_unreconcile_select" parent="periodical_processing_reconciliation" />
<!-- <menuitem action="action_account_unreconcile_select"
id="menu_unreconcile_select" parent="periodical_processing_reconciliation" /> -->
</data>
</openerp>

View File

@ -0,0 +1,100 @@
# -*- 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/>.
#
##############################################################################
import time
from osv import osv, fields
from tools.translate import _
class account_partner_reconcile_process(osv.osv_memory):
_name = 'account.partner.reconcile.process'
_description = 'Reconcilation Process partner by partner'
def _get_to_reconcile(self, cr, uid, context=None):
cr.execute(
"SELECT l.partner_id " \
"FROM account_move_line AS l LEFT JOIN res_partner p ON (p.id = l.partner_id) " \
"WHERE l.reconcile_id IS NULL " \
"AND (%s > to_char(p.last_reconciliation_date, 'YYYY-MM-DD') " \
"OR p.last_reconciliation_date IS NULL ) " \
"AND l.state <> 'draft' " \
"GROUP BY l.partner_id ",(time.strftime('%Y-%m-%d'),)
)
return len(map(lambda x: x[0], cr.fetchall())) - 1
def _get_today_reconciled(self, cr, uid, context=None):
cr.execute(
"SELECT l.partner_id " \
"FROM account_move_line AS l LEFT JOIN res_partner p ON (p.id = l.partner_id) " \
"WHERE l.reconcile_id IS NULL " \
"AND %s = to_char(p.last_reconciliation_date, 'YYYY-MM-DD') " \
"AND l.state <> 'draft' " \
"GROUP BY l.partner_id ",(time.strftime('%Y-%m-%d'),)
)
return len(map(lambda x: x[0], cr.fetchall())) + 1
def _get_partner(self, cr, uid, context=None):
partner = self.pool.get('account.move.line').get_next_partner_only(cr, uid, offset=1, context=context)
if not partner:
return False
return partner[0]
def data_get(self, cr, uid, to_reconcile, today_reconciled, context=None):
return {'progress': (100 / float(to_reconcile + today_reconciled)) * today_reconciled}
def default_get(self, cr, uid, fields, context=None):
res = super(account_partner_reconcile_process, self).default_get(cr, uid, fields, context=context)
if 'to_reconcile' in res and 'today_reconciled' in res:
data = self.data_get(cr, uid, res['to_reconcile'], res['today_reconciled'], context)
res.update(data)
return res
def next_partner(self, cr, uid, ids, context=None):
partner_id = self.pool.get('account.move.line').read(cr, uid, context['active_id'], ['partner_id'])['partner_id'][0]
self.pool.get('res.partner').write(cr, uid, partner_id, {'last_reconciliation_date': time.strftime('%Y-%m-%d')}, context)
#TODO: we have to find a way to update the context of the current tab (we could open a new tab with the context but it's not really handy)
#TODO: remove that comments when the client side dev is done
#context.update({'partner_id': self.browse(cr, uid, ids, context)[0].next_partner_id})
#return {'context': context,
# 'target': 'opener',
# 'name': 'reconciliation process',
# 'view_type': 'form',
# 'view_mode': 'tree,form',
# 'res_model': 'account.move.line',
# 'type': 'ir.actions.act_window'
#}
return {}
_columns = {
'to_reconcile': fields.float('Remaining Partners', readonly=True, help='This is the remaining partners for who you should check if there is something to reconcile or not. This figure already count the current partner as reconciled.'),
'today_reconciled': fields.float('Partners Reconciled Today', readonly=True, help='This figure depicts the total number of partners that have gone throught the reconciliation process today. The current partner is counted as already processed.'),
'progress': fields.float('Progress', readonly=True, help='Shows you the progress made today on the reconciliation process. Given by \nPartners Reconciled Today \ (Remaining Partners + Partners Reconciled Today)'),
'next_partner_id': fields.many2one('res.partner', 'Next Partner to Reconcile', readonly=True, help='This field shows you the next partner that will be automatically chosen by the system to go through the reconciliation process, based on the latest day it have been reconciled.'), # TODO: remove the readonly=True when teh client side will allow to update the context of existing tab, so that the user can change this value if he doesn't want to follow openerp proposal
}
_defaults = {
'to_reconcile': _get_to_reconcile,
'today_reconciled': _get_today_reconciled,
'next_partner_id': _get_partner,
}
account_partner_reconcile_process()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_partner_reconcile_view" model="ir.ui.view">
<field name="name">Account Partner Reconcile</field>
<field name="model">account.partner.reconcile.process</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Partner Reconciliation">
<field name="progress" widget="progressbar" colspan="4"/>
<field name="today_reconciled"/>
<field name="to_reconcile"/>
<newline/>
<field name="next_partner_id" colspan="4"/>
<newline/>
<group colspan="4" col="4">
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
<button name="next_partner" icon="gtk-execute" type="object" string="Go to next partner" />
</group>
</form>
</field>
</record>
<record id="action_account_partner_reconcile" model="ir.actions.act_window">
<field name="name">Manual Reconciliation</field>
<field name="res_model">account.partner.reconcile.process</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="account_partner_reconcile_view"/>
<field name="context">{'record_id':active_id}</field>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_partner_reconcile_actino">
<field name="model_id" ref="account.model_account_move_line" />
<field name="object" eval="1" />
<field name="name">Partner reconciliation</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_account_partner_reconcile'))" />
<field name="key">action</field>
<field name="model">account.move.line</field>
</record>
<!-- <menuitem
icon="STOCK_EXECUTE"
name="Partner reconciliation"
action="action_account_partner_reconcile"
id="menu_partner_reconcile"
parent="account.next_id_20"/>
-->
</data>
</openerp>