1
# -*- coding: utf-8 -*-
2
###############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2014 Ursa Informative Systems (<www.ursainfosystems.com>).
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU Affero General Public License as
9
# published by the Free Software Foundation, either version 3 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Affero General Public License for more details.
17
# You should have received a copy of the GNU Affero General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
###############################################################################
23
from openerp.osv import fields, orm
24
from openerp import tools
27
class PartnerAgingCustomer(orm.Model):
28
_name = 'partner.aging.customer'
31
def open_document(self, cr, uid, ids, context=None):
33
@description Open document (invoice or payment) related to the
34
unapplied payment or outstanding balance on this line
38
models = self.pool.get('ir.model.data')
39
# Get this line's invoice id
40
inv_id = self.browse(cr, uid, ids[0], context=context).invoice_id.id
42
# if this is an unapplied payment(all unapplied payments hard-coded to
43
# -999), get the referenced voucher
45
ref = self.browse(cr, uid, ids[0], context=context).invoice_ref
46
voucher_pool = self.pool['account.voucher']
47
# Get referenced customer payment (invoice_ref field is actually a
49
voucher_id = voucher_pool.search(
52
[('number', '=', ref)],
56
view = models.get_object_reference(
63
view_id = view and view[1] or False
64
name = 'Customer Payments'
65
res_model = 'account.voucher'
68
# otherwise get the invoice
70
view = models.get_object_reference(
76
view_id = view and view[1] or False
77
name = 'Customer Invoices'
78
res_model = 'account.invoice'
79
ctx = "{'type':'out_invoice'}"
85
# Open up the document's form
91
'res_model': res_model,
93
'type': 'ir.actions.act_window',
100
'partner_id': fields.many2one(
105
'partner_name': fields.text('Name', readonly=True),
106
'avg_days_overdue': fields.integer(u'Avg Days Overdue', readonly=True),
107
'date': fields.date(u'Due Date', readonly=True),
108
'total': fields.float(u'Total', readonly=True),
109
'days_due_01to30': fields.float(u'01/30', readonly=True),
110
'days_due_31to60': fields.float(u'31/60', readonly=True),
111
'days_due_61to90': fields.float(u'61/90', readonly=True),
112
'days_due_91to120': fields.float(u'91/120', readonly=True),
113
'days_due_121togr': fields.float(u'+121', readonly=True),
114
'max_days_overdue': fields.integer(
116
group_operator="max",
119
'current': fields.float(u'Total', readonly=True),
120
'invoice_ref': fields.char('Reference', size=25, readonly=True),
121
'invoice_id': fields.many2one(
126
'currency_name': fields.text('Currency', readonly=True),
127
'comment': fields.text('Notes', readonly=True),
128
'salesman': fields.many2one('res.users', u'Sales Rep', readonly=True),
131
_order = 'partner_name'
135
@author Ursa Information Systems
136
@description Update table on load with latest aging information
144
oldest_invoice_date AS date,
157
FROM account_voucher_customer_unapplied
160
FROM (SELECT l.id AS id,
161
l.partner_id AS partner_id,
162
res_partner.name AS "partner_name",
163
res_partner.user_id AS salesman,
164
days_due AS "avg_days_overdue",
166
WHEN ai.id IS NOT NULL THEN ai.date_due
170
WHEN ai.id IS NOT NULL THEN
172
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
175
WHEN ai.id IS NULL THEN l.debit - l.credit
179
WHEN ( days_due BETWEEN 01 AND 30 )
180
AND ai.id IS NOT NULL THEN
182
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
185
WHEN ( days_due BETWEEN 01 AND 30 )
186
AND ai.id IS NULL THEN l.debit - l.credit
188
end AS "days_due_01to30",
190
WHEN ( days_due BETWEEN 31 AND 60 )
191
AND ai.id IS NOT NULL THEN
193
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
196
WHEN ( days_due BETWEEN 31 AND 60 )
197
AND ai.id IS NULL THEN l.debit - l.credit
199
end AS "days_due_31to60",
201
WHEN ( days_due BETWEEN 61 AND 90 )
202
AND ai.id IS NOT NULL THEN
204
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
207
WHEN ( days_due BETWEEN 61 AND 90 )
208
AND ai.id IS NULL THEN l.debit - l.credit
210
end AS "days_due_61to90",
212
WHEN ( days_due BETWEEN 91 AND 120 )
213
AND ai.id IS NOT NULL THEN
215
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
218
WHEN ( days_due BETWEEN 91 AND 120 )
219
AND ai.id IS NULL THEN l.debit - l.credit
221
end AS "days_due_91to120",
224
AND ai.id IS NOT NULL THEN
226
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
230
AND ai.id IS NULL THEN l.debit - l.credit
232
end AS "days_due_121togr",
234
WHEN days_due < 0 THEN 0
236
end AS "max_days_overdue",
239
AND ai.id IS NOT NULL THEN
241
WHEN ai.type = 'out_refund' THEN -1 * ai.residual
245
AND ai.id IS NULL THEN l.debit - l.credit
248
l.ref AS "invoice_ref",
249
ai.id AS "invoice_id",
251
res_currency.name AS "currency_name"
252
FROM account_move_line AS l
253
INNER JOIN (SELECT lt.id,
255
WHEN inv.id IS NOT NULL THEN
256
Extract(day FROM ( Now() - inv.date_due ))
257
ELSE Extract(day FROM (
258
Now() - lt.date_maturity ))
260
FROM account_move_line lt
261
LEFT JOIN account_invoice inv
262
ON lt.move_id = inv.move_id) DaysDue
264
INNER JOIN account_account
265
ON account_account.id = l.account_id
266
INNER JOIN res_company
267
ON account_account.company_id = res_company.id
268
INNER JOIN account_move
269
ON account_move.id = l.move_id
270
LEFT JOIN account_invoice AS ai
271
ON ai.move_id = l.move_id
272
INNER JOIN res_partner
273
ON res_partner.id = l.partner_id
274
INNER JOIN res_currency
275
ON res_currency.id = ai.currency_id
276
WHERE account_account.active
277
AND ai.state <> 'paid'
278
AND ( account_account.type IN ( 'receivable' ) )
279
AND ( l.reconcile_id IS NULL )
280
AND account_move.state = 'posted'
281
AND DaysDue.days_due IS NOT NULL) sq
284
tools.drop_view_if_exists(cr, '%s' % (self._name.replace('.', '_')))
286
"CREATE OR REPLACE VIEW %s AS ( %s)" %
287
(self._name.replace('.', '_'), query)