From 509cf3964e4964b3e3fe5276e5871427323832bd Mon Sep 17 00:00:00 2001 From: Mustufa Rangwala Date: Fri, 18 Jun 2010 16:45:59 +0530 Subject: [PATCH] [IMP] account: account reconcile partner process bzr revid: mra@mra-laptop-20100618111559-knik7r51ry3se6wh --- addons/account/__openerp__.py | 6 +- addons/account/account_move_line.py | 38 +++++++ addons/account/account_view.xml | 16 ++- addons/account/account_wizard.xml | 11 +- addons/account/partner.py | 7 +- addons/account/partner_view.xml | 15 ++- addons/account/wizard/__init__.py | 1 + ...ccount_move_line_reconcile_select_view.xml | 4 +- ...ount_move_line_unreconcile_select_view.xml | 4 +- .../account_reconcile_partner_process.py | 100 ++++++++++++++++++ ...account_reconcile_partner_process_view.xml | 54 ++++++++++ 11 files changed, 237 insertions(+), 19 deletions(-) create mode 100644 addons/account/wizard/account_reconcile_partner_process.py create mode 100644 addons/account/wizard/account_reconcile_partner_process_view.xml diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index d4408d63bfe..39e40555f39 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -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', diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 45edefe6082..72ab093e1ae 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -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): diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 1787ba06927..a93179e3f98 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -842,7 +842,9 @@ - + + + @@ -1182,6 +1184,18 @@ id="menu_action_account_bank_reconcile_check_tree" parent="periodical_processing_reconciliation" groups="group_account_user" /> + + + + --> - + + - + + - + + res.partner.form.reconcile + res.partner + + + + + + + + diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py index 39971f5c11a..c56c6c2e764 100644 --- a/addons/account/wizard/__init__.py +++ b/addons/account/wizard/__init__.py @@ -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 diff --git a/addons/account/wizard/account_move_line_reconcile_select_view.xml b/addons/account/wizard/account_move_line_reconcile_select_view.xml index 220c9e541de..4f88f618727 100644 --- a/addons/account/wizard/account_move_line_reconcile_select_view.xml +++ b/addons/account/wizard/account_move_line_reconcile_select_view.xml @@ -31,8 +31,8 @@ new - + \ No newline at end of file diff --git a/addons/account/wizard/account_move_line_unreconcile_select_view.xml b/addons/account/wizard/account_move_line_unreconcile_select_view.xml index 1daae353725..f2a3882db91 100644 --- a/addons/account/wizard/account_move_line_unreconcile_select_view.xml +++ b/addons/account/wizard/account_move_line_unreconcile_select_view.xml @@ -31,8 +31,8 @@ new - + \ No newline at end of file diff --git a/addons/account/wizard/account_reconcile_partner_process.py b/addons/account/wizard/account_reconcile_partner_process.py new file mode 100644 index 00000000000..6a1e354837d --- /dev/null +++ b/addons/account/wizard/account_reconcile_partner_process.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## +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: diff --git a/addons/account/wizard/account_reconcile_partner_process_view.xml b/addons/account/wizard/account_reconcile_partner_process_view.xml new file mode 100644 index 00000000000..cd296759752 --- /dev/null +++ b/addons/account/wizard/account_reconcile_partner_process_view.xml @@ -0,0 +1,54 @@ + + + + + + + Account Partner Reconcile + account.partner.reconcile.process + form + +
+ + + + + + + +