1
# -*- encoding: utf-8 -*-
2
##############################################################################
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>
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU Affero 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.
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 Affero General Public License for more details.
19
# You should have received a copy of the GNU Affero General Public License
20
# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
##############################################################################
25
from osv import fields, osv
27
class account_move_line(osv.osv):
28
_name = 'account.move.line'
29
_inherit = 'account.move.line'
31
def _invoice(self, cr, uid, ids, name, arg, context=None):
32
return super(account_move_line, self)._invoice(cr, uid, ids, name, arg, context)
34
def _invoice_search(self, cr, uid, obj, name, args, context={}):
35
""" Redefinition for searching account move lines without any invoice related ('invoice.id','=',False)"""
37
if (x[2] is False) and (x[1] == '=') and (x[0] == 'invoice'):
38
cr.execute('SELECT l.id FROM account_move_line l ' \
39
'LEFT JOIN account_invoice i ON l.move_id = i.move_id ' \
40
'WHERE i.id IS NULL', [])
43
return [('id', '=', '0')]
44
return [('id', 'in', [x[0] for x in res])]
45
return super(account_move_line, self)._invoice_search(cr, uid, obj, name, args, context=context)
47
def amount_to_pay(self, cr, uid, ids, name, arg={}, context={}):
49
Return amount pending to be paid taking into account payment lines and the reconciliation.
50
Note that the amount to pay can be due to negative supplier refund invoices or customer invoices.
55
cr.execute("""SELECT ml.id,
56
CASE WHEN ml.amount_currency < 0
57
THEN - ml.amount_currency
58
WHEN ml.amount_currency > 0
59
THEN ml.amount_currency
60
ELSE ml.credit - ml.debit
62
(SELECT coalesce(sum(CASE WHEN pl.type='receivable' THEN -amount_currency ELSE amount_currency END),0)
64
INNER JOIN payment_order po
65
ON (pl.order_id = po.id)
67
pl.move_line_id = ml.id AND
68
pl.payment_move_id IS NULL AND
73
COALESCE( SUM(COALESCE(amrl.credit,0) - COALESCE(amrl.debit,0)), 0 )
75
account_move_reconcile amr,
76
account_move_line amrl
78
amr.id = amrl.reconcile_partial_id AND
79
amr.id = ml.reconcile_partial_id
82
FROM account_move_line ml
83
WHERE id in (%s)""" % (",".join([str(int(x)) for x in ids])))
85
for record in cr.fetchall():
87
debt = record[1] or 0.0
89
unreconciled = record[3]
90
reconcile_id = record[4]
97
debt = min(debt - paid, max(0.0, unreconciled))
99
debt = max(debt - paid, min(0.0, unreconciled))
103
def _to_pay_search(self, cr, uid, obj, name, args, context={}):
106
currency = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.currency_id
108
# For searching we first discard reconciled moves because the filter is fast and discards most records
110
ids = self.pool.get('account.move.line').search(cr, uid, [('reconcile_id','=',False)], context=context)
111
records = self.pool.get('account.move.line').read(cr, uid, ids, ['id', 'amount_to_pay'], context)
113
for record in records:
114
if not self.pool.get('res.currency').is_zero( cr, uid, currency, record['amount_to_pay'] ):
115
ids.append( record['id'] )
117
return [('id','=',False)]
118
return [('id','in',ids)]
120
def _payment_type_get(self, cr, uid, ids, field_name, arg, context={}):
122
invoice_obj = self.pool.get('account.invoice')
123
for rec in self.browse(cr, uid, ids, context):
124
result[rec.id] = (0,0)
125
invoice_id = invoice_obj.search(cr, uid, [('move_id', '=', rec.move_id.id)], context=context)
127
inv = invoice_obj.browse(cr, uid, invoice_id[0], context)
129
result[rec.id] = (inv.payment_type.id, self.pool.get('payment.type').browse(cr, uid, inv.payment_type.id, context).name)
131
result[rec.id] = (0,0)
134
def _payment_type_search(self, cr, uid, obj, name, args, context={}):
137
operator = args[0][1]
141
if isinstance(value, int) or isinstance(value, long):
143
elif isinstance(value, list):
146
ids = self.pool.get('payment.type').search(cr,uid,[('name','ilike',value)], context=context)
148
cr.execute('SELECT l.id ' \
149
'FROM account_move_line l, account_invoice i ' \
150
'WHERE l.move_id = i.move_id AND i.payment_type in (%s)' % (','.join(map(str, ids))))
153
return [('id', 'in', [x[0] for x in res])]
154
return [('id','=','0')]
157
'invoice': fields.function(_invoice, method=True, string='Invoice',
158
type='many2one', relation='account.invoice', fnct_search=_invoice_search),
159
'received_check': fields.boolean('Received check', help="To write down that a check in paper support has been received, for example."),
160
'partner_bank_id': fields.many2one('res.partner.bank','Bank Account'),
161
'amount_to_pay' : fields.function(amount_to_pay, method=True, type='float', string='Amount to pay', fnct_search=_to_pay_search),
162
'payment_type': fields.function(_payment_type_get, fnct_search=_payment_type_search, method=True, type="many2one", relation="payment.type", string="Payment type"),
165
def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
166
for key in vals.keys():
167
if key not in ['received_check', 'partner_bank_id', 'date_maturity']:
168
return super(account_move_line, self).write(cr, uid, ids, vals, context, check, update_check)
169
return super(account_move_line, self).write(cr, uid, ids, vals, context, check, update_check=False)
171
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False, submenu=False):
173
self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'menu_action_invoice_payments'),
174
self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'menu_action_done_payments'),
176
menus = [m[1] for m in menus]
177
if 'active_id' in context and context['active_id'] in menus:
178
# Use standard views for account.move.line object
179
if view_type == 'search':
180
# Get a specific search view (bug in 6.0RC1, it does not give the search view defined in the action window)
181
view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_payment_extension', 'view_payments_filter')[1]
182
result = super(osv.osv, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
184
# Use special views for account.move.line object (for ex. tree view contains user defined fields)
185
result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
190
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: