117
by office at chricar
[ADD] account_payment_extension see README |
1 |
# -*- encoding: utf-8 -*-
|
2 |
##############################################################################
|
|
3 |
#
|
|
4 |
# OpenERP, Open Source Management Solution
|
|
5 |
# Copyright (c) 2008 Zikzakmedia S.L. (http://zikzakmedia.com) All Rights Reserved.
|
|
6 |
# Jordi Esteve <jesteve@zikzakmedia.com>
|
|
7 |
# $Id$
|
|
8 |
#
|
|
9 |
# This program is free software: you can redistribute it and/or modify
|
|
10 |
# it under the terms of the GNU General Public License as published by
|
|
11 |
# the Free Software Foundation, either version 3 of the License, or
|
|
12 |
# (at your option) any later version.
|
|
13 |
#
|
|
14 |
# This program is distributed in the hope that it will be useful,
|
|
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 |
# GNU General Public License for more details.
|
|
18 |
#
|
|
19 |
# You should have received a copy of the GNU General Public License
|
|
20 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21 |
#
|
|
22 |
##############################################################################
|
|
23 |
from osv import fields, osv |
|
24 |
||
25 |
class account_move_line(osv.osv): |
|
26 |
_name = 'account.move.line' |
|
27 |
_inherit = 'account.move.line' |
|
28 |
||
29 |
def _invoice(self, cr, uid, ids, name, arg, context=None): |
|
30 |
return super(account_move_line, self)._invoice(cr, uid, ids, name, arg, context) |
|
31 |
||
32 |
def _invoice_search(self, cr, uid, obj, name, args, context={}): |
|
33 |
""" Redefinition for searching account move lines without any invoice related ('invoice.id','=',False)"""
|
|
34 |
for x in args: |
|
35 |
if (x[2] is False) and (x[1] == '=') and (x[0] == 'invoice'): |
|
36 |
cr.execute('SELECT l.id FROM account_move_line l ' \ |
|
37 |
'LEFT JOIN account_invoice i ON l.move_id = i.move_id ' \
|
|
38 |
'WHERE i.id IS NULL', []) |
|
39 |
res = cr.fetchall() |
|
40 |
if not len(res): |
|
41 |
return [('id', '=', '0')] |
|
42 |
return [('id', 'in', [x[0] for x in res])] |
|
43 |
return super(account_move_line, self)._invoice_search(cr, uid, obj, name, args, context=context) |
|
44 |
||
45 |
def amount_to_pay(self, cr, uid, ids, name, arg={}, context={}): |
|
46 |
"""
|
|
47 |
Return amount pending to be paid taking into account payment lines and the reconciliation.
|
|
48 |
Note that the amount to pay can be due to negative supplier refund invoices or customer invoices.
|
|
49 |
"""
|
|
50 |
||
51 |
if not ids: |
|
52 |
return {} |
|
53 |
cr.execute("""SELECT ml.id, |
|
54 |
CASE WHEN ml.amount_currency < 0
|
|
55 |
THEN - ml.amount_currency
|
|
56 |
WHEN ml.amount_currency > 0
|
|
57 |
THEN ml.amount_currency
|
|
58 |
ELSE ml.credit - ml.debit
|
|
59 |
END AS debt,
|
|
60 |
(SELECT coalesce(sum(CASE WHEN pl.type='receivable' THEN -amount_currency ELSE amount_currency END),0)
|
|
61 |
FROM payment_line pl
|
|
62 |
INNER JOIN payment_order po
|
|
63 |
ON (pl.order_id = po.id)
|
|
64 |
WHERE
|
|
65 |
pl.move_line_id = ml.id AND
|
|
66 |
pl.payment_move_id IS NULL AND
|
|
67 |
po.state != 'cancel'
|
|
68 |
) AS paid,
|
|
69 |
(
|
|
70 |
SELECT
|
|
71 |
COALESCE( SUM(COALESCE(amrl.credit,0) - COALESCE(amrl.debit,0)), 0 )
|
|
72 |
FROM
|
|
73 |
account_move_reconcile amr,
|
|
74 |
account_move_line amrl
|
|
75 |
WHERE
|
|
76 |
amr.id = amrl.reconcile_partial_id AND
|
|
77 |
amr.id = ml.reconcile_partial_id
|
|
78 |
) AS unreconciled,
|
|
79 |
reconcile_id
|
|
80 |
FROM account_move_line ml
|
|
81 |
WHERE id in (%s)""" % (",".join([str(int(x)) for x in ids]))) |
|
82 |
result = {} |
|
83 |
for record in cr.fetchall(): |
|
84 |
id = record[0] |
|
85 |
debt = record[1] or 0.0 |
|
86 |
paid = record[2] |
|
87 |
unreconciled = record[3] |
|
88 |
reconcile_id = record[4] |
|
89 |
if reconcile_id: |
|
90 |
debt = 0.0 |
|
91 |
else: |
|
92 |
if not unreconciled: |
|
93 |
unreconciled = debt |
|
94 |
if debt > 0: |
|
95 |
debt = min(debt - paid, max(0.0, unreconciled)) |
|
96 |
else: |
|
97 |
debt = max(debt - paid, min(0.0, unreconciled)) |
|
98 |
result[id] = debt |
|
99 |
return result |
|
100 |
||
101 |
def _to_pay_search(self, cr, uid, obj, name, args, context={}): |
|
102 |
if not len(args): |
|
103 |
return [] |
|
104 |
currency = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.currency_id |
|
105 |
||
106 |
# For searching we first discard reconciled moves because the filter is fast and discards most records
|
|
107 |
# quickly.
|
|
108 |
ids = self.pool.get('account.move.line').search(cr, uid, [('reconcile_id','=',False)], context=context) |
|
109 |
records = self.pool.get('account.move.line').read(cr, uid, ids, ['id', 'amount_to_pay'], context) |
|
110 |
ids = [] |
|
111 |
for record in records: |
|
112 |
if not self.pool.get('res.currency').is_zero( cr, uid, currency, record['amount_to_pay'] ): |
|
113 |
ids.append( record['id'] ) |
|
114 |
if not ids: |
|
115 |
return [('id','=',False)] |
|
116 |
return [('id','in',ids)] |
|
117 |
||
118 |
def _payment_type_get(self, cr, uid, ids, field_name, arg, context={}): |
|
119 |
result = {} |
|
120 |
invoice_obj = self.pool.get('account.invoice') |
|
121 |
for rec in self.browse(cr, uid, ids, context): |
|
122 |
result[rec.id] = (0,0) |
|
123 |
invoice_id = invoice_obj.search(cr, uid, [('move_id', '=', rec.move_id.id)], context=context) |
|
124 |
if invoice_id: |
|
125 |
inv = invoice_obj.browse(cr, uid, invoice_id[0], context) |
|
126 |
if inv.payment_type: |
|
127 |
result[rec.id] = (inv.payment_type.id, self.pool.get('payment.type').browse(cr, uid, inv.payment_type.id, context).name) |
|
128 |
else: |
|
129 |
result[rec.id] = (0,0) |
|
130 |
return result |
|
131 |
||
132 |
def _payment_type_search(self, cr, uid, obj, name, args, context={}): |
|
133 |
if not len(args): |
|
134 |
return [] |
|
135 |
operator = args[0][1] |
|
136 |
value = args[0][2] |
|
137 |
if not value: |
|
138 |
return [] |
|
139 |
if isinstance(value, int) or isinstance(value, long): |
|
140 |
ids = [value] |
|
141 |
elif isinstance(value, list): |
|
142 |
ids = value |
|
143 |
else: |
|
144 |
ids = self.pool.get('payment.type').search(cr,uid,[('name','ilike',value)], context=context) |
|
145 |
if ids: |
|
146 |
cr.execute('SELECT l.id ' \ |
|
147 |
'FROM account_move_line l, account_invoice i ' \
|
|
148 |
'WHERE l.move_id = i.move_id AND i.payment_type in (%s)' % (','.join(map(str, ids)))) |
|
149 |
res = cr.fetchall() |
|
150 |
if len(res): |
|
151 |
return [('id', 'in', [x[0] for x in res])] |
|
152 |
return [('id','=','0')] |
|
153 |
||
154 |
_columns = { |
|
155 |
'invoice': fields.function(_invoice, method=True, string='Invoice', |
|
156 |
type='many2one', relation='account.invoice', fnct_search=_invoice_search), |
|
157 |
'received_check': fields.boolean('Received check', help="To write down that a check in paper support has been received, for example."), |
|
158 |
'partner_bank_id': fields.many2one('res.partner.bank','Bank Account'), |
|
159 |
'amount_to_pay' : fields.function(amount_to_pay, method=True, type='float', string='Amount to pay', fnct_search=_to_pay_search), |
|
160 |
'payment_type': fields.function(_payment_type_get, fnct_search=_payment_type_search, method=True, type="many2one", relation="payment.type", string="Payment type"), |
|
161 |
}
|
|
162 |
||
163 |
def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True): |
|
164 |
for key in vals.keys(): |
|
165 |
if key not in ['received_check', 'partner_bank_id', 'date_maturity']: |
|
166 |
return super(account_move_line, self).write(cr, uid, ids, vals, context, check, update_check) |
|
167 |
return super(account_move_line, self).write(cr, uid, ids, vals, context, check, update_check=False) |
|
168 |
||
169 |
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False, submenu=False): |
|
170 |
menus = [ |
|
171 |
self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'menu_action_invoice_payments'), |
|
172 |
self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'menu_action_done_payments'), |
|
173 |
]
|
|
174 |
menus = [m[1] for m in menus] |
|
175 |
if 'active_id' in context and context['active_id'] in menus: |
|
176 |
# Use standard views for account.move.line object
|
|
177 |
if view_type == 'search': |
|
178 |
# Get a specific search view (bug in 6.0RC1, it does not give the search view defined in the action window)
|
|
179 |
view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'view_payments_filter')[1] |
|
180 |
result = super(osv.osv, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu) |
|
181 |
else: |
|
182 |
# Use special views for account.move.line object (for ex. tree view contains user defined fields)
|
|
183 |
result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu) |
|
184 |
return result |
|
185 |
||
186 |
account_move_line() |
|
187 |
||
188 |
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|