[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 Budgets
Customer and Supplier Invoices Customer and Supplier Invoices
Bank statements Bank statements
Reconciliation process by partner
Creates a dashboards for accountants that includes: Creates a dashboards for accountants that includes:
* List of uninvoiced quotations * List of uninvoiced quotations
* Graph of aged receivables * 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 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 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', 'website': 'http://www.openerp.com',
'init_xml': [], 'init_xml': [],
@ -85,6 +86,7 @@ module named account_voucherss
'wizard/account_compare_account_balance_report_view.xml', 'wizard/account_compare_account_balance_report_view.xml',
'wizard/account_third_party_ledger.xml', 'wizard/account_third_party_ledger.xml',
'wizard/account_reconcile_view.xml', 'wizard/account_reconcile_view.xml',
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml', 'wizard/account_automatic_reconcile_view.xml',
'project/wizard/project_account_analytic_line_view.xml', 'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.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 # 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): def reconcile_partial(self, cr, uid, ids, type='auto', context=None):
merges = [] merges = []
unmerge = [] unmerge = []
@ -730,6 +763,11 @@ class account_move_line(osv.osv):
# because of the way the line_id are defined: (4, x, False) # because of the way the line_id are defined: (4, x, False)
for id in ids: for id in ids:
wf_service.trg_trigger(uid, 'account.move.line', id, cr) 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 return r_id
def view_header_get(self, cr, user, view_id, view_type, context): def view_header_get(self, cr, user, view_id, view_type, context):

View File

@ -842,7 +842,9 @@
<separator orientation="vertical"/> <separator orientation="vertical"/>
<field name="date" select='1'/> <field name="date" select='1'/>
<field name="account_id" 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'/> <field name="balance" string="Debit/Credit" select='1'/>
</group> </group>
</search> </search>
@ -1182,6 +1184,18 @@
id="menu_action_account_bank_reconcile_check_tree" id="menu_action_account_bank_reconcile_check_tree"
parent="periodical_processing_reconciliation" groups="group_account_user" /> 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 <act_window
domain="[('account_id', '=', active_id)]" 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_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"/> <!-- <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"/> <!-- <menuitem action="wizard_reconcile_select" id="menu_reconcile_select" parent="account.next_id_20" type="wizard"/> -->
-->
<!-- unreconcile --> <!-- unreconcile -->
<!-- <wizard id="wizard_unreconcile" model="account.move.line" name="account.move.line.unreconcile" string="Unreconcile Entries"/>--> <!-- <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"/> <!-- <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"/> <!-- <menuitem action="wizard_unreconcile_select" id="menu_unreconcile_select" parent="account.next_id_20" type="wizard"/> -->
-->
<!-- subscriptions --> <!-- subscriptions -->
<!-- <!--

View File

@ -89,7 +89,7 @@ class res_partner(osv.osv):
_name = 'res.partner' _name = 'res.partner'
_inherit = 'res.partner' _inherit = 'res.partner'
_description = 'Partner' _description = 'Partner'
def _credit_debit_get(self, cr, uid, ids, field_names, arg, context): 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) 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) 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 if val is None: val=0
res[pid][maps[type]] = (type=='receivable') and val or -val res[pid][maps[type]] = (type=='receivable') and val or -val
return res return res
def _asset_difference_search(self, cr, uid, obj, name, type, args, context=None): def _asset_difference_search(self, cr, uid, obj, name, type, args, context=None):
if not len(args): if not len(args):
return [] return []
@ -136,7 +136,7 @@ class res_partner(osv.osv):
if not len(res): if not len(res):
return [('id','=','0')] return [('id','=','0')]
return [('id','in',map(itemgetter(0), res))] return [('id','in',map(itemgetter(0), res))]
def _credit_search(self, cr, uid, obj, name, args, context): def _credit_search(self, cr, uid, obj, name, args, context):
return self._asset_difference_search(cr, uid, obj, name, 'receivable', args, context=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"), help="This payment term will be used instead of the default one for the current partner"),
'ref_companies': fields.one2many('res.company', 'partner_id', 'ref_companies': fields.one2many('res.company', 'partner_id',
'Companies that refers to partner'), '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() res_partner()

View File

@ -122,10 +122,10 @@
</notebook> </notebook>
</field> </field>
</record> </record>
<!-- Partners info tab view--> <!-- Partners info tab view-->
<act_window <act_window
id="action_analytic_open" id="action_analytic_open"
name="Analytic Accounts" name="Analytic Accounts"
res_model="account.analytic.account" res_model="account.analytic.account"
@ -134,5 +134,16 @@
view_type="form" view_type="form"
view_mode="tree,form,graph,calendar"/> 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> </data>
</openerp> </openerp>

View File

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

View File

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

View File

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