[IMP] account: Now uses a customized view to display manual reconciliations.

bzr revid: nicolas.vanhoren@openerp.com-20120921145235-pixrb3hqo4d19rkl
This commit is contained in:
niv-openerp
2012-09-21 16:52:35 +02:00
9 changed files with 230 additions and 38 deletions
+10 -2
View File
@@ -63,6 +63,8 @@ for a particular financial year and for preparation of vouchers there is a modul
'wizard/account_use_model_view.xml',
'account_installer.xml',
'wizard/account_period_close_view.xml',
'wizard/account_reconcile_view.xml',
'wizard/account_unreconcile_view.xml',
'account_view.xml',
'account_report.xml',
'account_financial_report_data.xml',
@@ -85,14 +87,12 @@ for a particular financial year and for preparation of vouchers there is a modul
'wizard/account_journal_select_view.xml',
'wizard/account_change_currency_view.xml',
'wizard/account_validate_move_view.xml',
'wizard/account_unreconcile_view.xml',
'wizard/account_report_general_ledger_view.xml',
'wizard/account_invoice_state_view.xml',
'wizard/account_report_partner_balance_view.xml',
'wizard/account_report_account_balance_view.xml',
'wizard/account_report_aged_partner_balance_view.xml',
'wizard/account_report_partner_ledger_view.xml',
'wizard/account_reconcile_view.xml',
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml',
'wizard/account_financial_report_view.xml',
@@ -126,6 +126,14 @@ for a particular financial year and for preparation of vouchers there is a modul
'res_config_view.xml',
'account_pre_install.yml'
],
'js': [
'static/src/js/account_move_reconciliation.js',
],
'qweb' : [
"static/src/xml/account_move_reconciliation.xml",
],
'css':['static/src/css/account_move_reconciliation.css'
],
'demo': [
'demo/account_demo.xml',
'project/project_demo.xml',
+17 -15
View File
@@ -708,7 +708,9 @@ class account_move_line(osv.osv):
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)
partner = self.list_partners_to_reconcile(cr, uid, context=context)
if partner:
partner = partner[0]
else:
partner = context.get('partner_id', False)
if not partner:
@@ -716,26 +718,26 @@ class account_move_line(osv.osv):
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):
def list_partners_to_reconcile(self, cr, uid, 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
SELECT partner_id
FROM (
SELECT l.partner_id, p.last_reconciliation_date, 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)
RIGHT JOIN account_account a ON (a.id = l.account_id)
RIGHT 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)
GROUP BY l.partner_id, p.last_reconciliation_date
) AS s
WHERE debit > 0 AND credit > 0
ORDER BY p.last_reconciliation_date LIMIT 1 OFFSET %s""", (offset, )
)
return cr.fetchone()
ORDER BY last_reconciliation_date""")
ids = cr.fetchall()
ids = len(ids) and list(ids[0]) or []
return self.pool.get('res.partner').name_get(cr, uid, ids, context=context)
def reconcile_partial(self, cr, uid, ids, type='auto', context=None, writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False):
move_rec_obj = self.pool.get('account.move.reconcile')
@@ -915,8 +917,8 @@ class account_move_line(osv.osv):
if lines and lines[0]:
partner_id = lines[0].partner_id and lines[0].partner_id.id or False
if partner_id and context and context.get('stop_reconcile', False):
partner_obj.write(cr, uid, [partner_id], {'last_reconciliation_date': time.strftime('%Y-%m-%d %H:%M:%S')})
if not partner_obj.has_something_to_reconcile(cr, uid, partner_id, context=context):
partner_obj.mark_as_reconciled(cr, uid, [partner_id], context=context)
return r_id
def view_header_get(self, cr, user, view_id, view_type, context=None):
+2 -2
View File
@@ -1551,12 +1551,12 @@
</record>
<record id="action_account_manual_reconcile" model="ir.actions.act_window">
<field name="context">{'search_default_next_partner':1,'view_mode':True}</field>
<field name="context">{'search_default_unreconciled': 1,'view_mode':True}</field>
<field name="name">Journal Items to Reconcile</field>
<field name="res_model">account.move.line</field>
<field name="view_id" ref="view_move_line_tree_reconcile"/>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">account_reconciliation_list</field>
<field name="help" type="html">
<p>
Good job!
+25 -2
View File
@@ -20,8 +20,8 @@
##############################################################################
from operator import itemgetter
from osv import fields, osv
import time
class account_fiscal_position(osv.osv):
_name = 'account.fiscal.position'
@@ -145,6 +145,29 @@ class res_partner(osv.osv):
def _debit_search(self, cr, uid, obj, name, args, context=None):
return self._asset_difference_search(cr, uid, obj, name, 'payable', args, context=context)
def has_something_to_reconcile(self, cr, uid, partner_id, context=None):
'''
at least a debit, a credit and a line older than the last reconciliation date of the partner
'''
cr.execute('''
SELECT l.partner_id, SUM(l.debit) AS debit, SUM(l.credit) AS credit
FROM account_move_line l
RIGHT JOIN account_account a ON (a.id = l.account_id)
RIGHT JOIN res_partner p ON (l.partner_id = p.id)
WHERE a.reconcile IS TRUE
AND p.id = %s
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''', (partner_id,))
res = cr.dictfetchone()
if res:
return bool(res['debit'] and res['credit'])
return False
def mark_as_reconciled(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'last_reconciliation_date': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
_columns = {
'credit': fields.function(_credit_debit_get,
fnct_search=_credit_search, string='Total Receivable', multi='dc', help="Total amount this customer owes you."),
@@ -185,7 +208,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('Latest Reconciliation Date', help='Date on which the partner accounting entries were reconciled last time')
'last_reconciliation_date': fields.datetime('Latest Reconciliation Date', help='Date on which the partner accounting entries were fully reconciled last time. It differs from the date of the last reconciliation made for this partner, as here we depict the fact that nothing more was to be reconciled at this date. This can be achieved in 2 ways: either the last debit/credit entry was reconciled, either the user pressed the button "Fully Reconciled" in the manual reconciliation process')
}
res_partner()
@@ -0,0 +1,19 @@
.openerp .oe_account_reconciliation {
border-bottom: 1px solid #CACACA;
padding: 5px;
}
.openerp .oe_account_reconciliation button {
margin: 3px;
}
.openerp .oe_account_reconciliation>div {
display: table;
width: 100%;
}
.openerp .oe_account_reconciliation>div>div {
display: table-cell;
width: 50%:
}
@@ -0,0 +1,124 @@
openerp.account = function (instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.web.account = {};
instance.web.views.add('account_reconciliation_list', 'instance.web.account.ReconciliationListView');
instance.web.account.ReconciliationListView = instance.web.ListView.extend({
init: function() {
this._super.apply(this, arguments);
var self = this;
this.current_partner = null;
this.do_select.add(function() {
if (self.get_selected_ids().length === 0) {
self.$(".oe_account_recon_reconcile").attr("disabled", "");
} else {
self.$(".oe_account_recon_reconcile").removeAttr("disabled");
}
});
},
on_loaded: function() {
var self = this;
var tmp = this._super.apply(this, arguments);
if (this.partners) {
this.$el.prepend(QWeb.render("AccountReconciliation", {widget: this}));
this.$(".oe_account_recon_previous").click(function() {
self.current_partner = (self.current_partner - 1) % self.partners.length;
self.search_by_partner();
});
this.$(".oe_account_recon_next").click(function() {
self.current_partner = (self.current_partner + 1) % self.partners.length;
self.search_by_partner();
});
this.$(".oe_account_recon_reconcile").click(function() {
self.reconcile();
});
this.$(".oe_account_recom_mark_as_reconciled").click(function() {
self.mark_as_reconciled();
});
}
return tmp;
},
do_search: function(domain, context, group_by) {
var self = this;
this.last_domain = domain;
this.last_context = context;
this.last_group_by = group_by;
this.old_search = _.bind(this._super, this);
var mod = new instance.web.Model("account.move.line", context, domain);
return mod.call("list_partners_to_reconcile", []).pipe(function(result) {
var current = self.current_partner !== null ? self.partners[self.current_partner][0] : null;
self.partners = result;
var index = _.find(_.range(self.partners.length), function(el) {
if (current === self.partners[el][0])
return true;
});
if (index !== undefined)
self.current_partner = index;
else
self.current_partner = self.partners.length == 0 ? null : 0;
self.search_by_partner();
});
},
search_by_partner: function() {
var self = this;
var fct = function() {
return self.old_search(new instance.web.CompoundDomain(self.last_domain,
[["partner_id", "in", self.current_partner === null ? [] :
[self.partners[self.current_partner][0]] ]]), self.last_context, self.last_group_by);
};
if (self.current_partner === null) {
self.last_reconciliation_date = _t("Never");
return fct();
} else {
return new instance.web.Model("res.partner").call("read",
[self.partners[self.current_partner][0], ["last_reconciliation_date"]]).pipe(function(res) {
self.last_reconciliation_date =
instance.web.format_value(res.last_reconciliation_date, {"type": "datetime"}, _t("Never"));
return fct();
});
}
},
reconcile: function() {
var self = this;
var ids = this.get_selected_ids();
if (ids.length === 0) {
instance.web.dialog($("<div />").text(_t("You must choose at least one record.")), {
title: _t("Warning"),
modal: true
});
return false;
}
new instance.web.Model("ir.model.data").call("get_object_reference", ["account", "action_view_account_move_line_reconcile"]).pipe(function(result) {
var additional_context = _.extend({
active_id: ids[0],
active_ids: ids,
active_model: self.model
});
return self.rpc("/web/action/load", {
action_id: result[1],
context: additional_context
}, function (result) {
result = result.result;
result.context = _.extend(result.context || {}, additional_context);
result.flags = result.flags || {};
result.flags.new_window = true;
return self.do_action(result, function () {
self.do_search(self.last_domain, self.last_context, self.last_group_by);
});
});
});
},
mark_as_reconciled: function() {
var self = this;
var id = self.partners[self.current_partner][0];
new instance.web.Model("res.partner").call("mark_as_reconciled", [[id]]).pipe(function() {
self.do_search(self.last_domain, self.last_context, self.last_group_by);
});
},
});
};
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="AccountReconciliation">
<div class="oe_account_reconciliation">
<t t-if="widget.current_partner === null">
There is no pending reconciliation.
</t>
<t t-if="widget.current_partner !== null">
<div>
<div>
<button class="oe_account_recon_previous oe_button" href="javascript:void(0)">&lt;</button>
<t t-esc="'' + widget.partners[widget.current_partner][1] + ' (' + (widget.current_partner + 1) + '/' + widget.partners.length + ')'"/>
<button class="oe_account_recon_next oe_button" href="javascript:void(0)">&gt;</button>
</div>
<div>
Last Reconciliation: <t t-esc="widget.last_reconciliation_date" />
</div>
</div>
<div>
<button class="oe_account_recon_reconcile oe_button oe_highlight" href="javascript:void(0)"
disabled="">Reconcile</button>
<button class="oe_account_recom_mark_as_reconciled oe_button" href="javascript:void(0)">Nothing to reconcile</button>
</div>
</t>
</div>
</t>
</templates>
@@ -86,19 +86,6 @@ class account_move_line_reconcile(osv.osv_memory):
ids = period_obj.find(cr, uid, dt=date, context=context)
if ids:
period_id = ids[0]
#stop the reconciliation process by partner (manual reconciliation) only if there is nothing more to reconcile for this partner
if 'active_ids' in context and context['active_ids']:
tmp_ml_id = account_move_line_obj.browse(cr, uid, context['active_ids'], context)[0]
partner_id = tmp_ml_id.partner_id and tmp_ml_id.partner_id.id or False
debit_ml_ids = account_move_line_obj.search(cr, uid, [('partner_id', '=', partner_id), ('account_id.reconcile', '=', True), ('reconcile_id', '=', False), ('debit', '>', 0)], context=context)
credit_ml_ids = account_move_line_obj.search(cr, uid, [('partner_id', '=', partner_id), ('account_id.reconcile', '=', True), ('reconcile_id', '=', False), ('credit', '>', 0)], context=context)
for ml_id in context['active_ids']:
if ml_id in debit_ml_ids:
debit_ml_ids.remove(ml_id)
if ml_id in credit_ml_ids:
credit_ml_ids.remove(ml_id)
if not debit_ml_ids and credit_ml_ids:
context.update({'stop_reconcile': True})
account_move_line_obj.reconcile(cr, uid, context['active_ids'], 'manual', account_id,
period_id, journal_id, context=context)
return {'type': 'ir.actions.act_window_close'}
@@ -166,7 +153,6 @@ class account_move_line_reconcile_writeoff(osv.osv_memory):
if ids:
period_id = ids[0]
context.update({'stop_reconcile': True})
account_move_line_obj.reconcile(cr, uid, context['active_ids'], 'manual', account_id,
period_id, journal_id, context=context)
return {'type': 'ir.actions.act_window_close'}
@@ -57,10 +57,10 @@ class account_partner_reconcile_process(osv.osv_memory):
def _get_partner(self, cr, uid, context=None):
move_line_obj = self.pool.get('account.move.line')
partner = move_line_obj.get_next_partner_only(cr, uid, offset=1, context=context)
partner = move_line_obj.list_partners_to_reconcile(cr, uid, context=context)
if not partner:
return False
return partner[0]
return partner[0][0]
def data_get(self, cr, uid, to_reconcile, today_reconciled, context=None):
return {'progress': (100 / (float(to_reconcile + today_reconciled) or 1.0)) * today_reconciled}
@@ -100,4 +100,4 @@ class account_partner_reconcile_process(osv.osv_memory):
account_partner_reconcile_process()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: