1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
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
##############################################################################
22
from openerp.osv import osv
23
from openerp.osv import fields
25
class account_voucher(osv.osv):
27
_inherit = 'account.voucher'
29
def recompute_voucher_lines(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context=None):
31
Returns a dict that contains new values and context
33
@param partner_id: latest value from user input for field partner_id
34
@param args: other arguments
35
@param context: context arguments, like lang, time zone
37
@return: Returns a dict which contains new values, and context
39
def _remove_noise_in_o2m():
40
"""if the line is partially reconciled, then we must pay attention to display it only once and
42
This function returns True if the line is considered as noise and should not be displayed
44
if line.reconcile_partial_id:
45
if currency_id == line.currency_id.id:
46
if line.amount_residual_currency <= 0:
49
if line.amount_residual <= 0:
55
context_multi_currency = context.copy()
57
currency_pool = self.pool.get('res.currency')
58
move_line_pool = self.pool.get('account.move.line')
59
partner_pool = self.pool.get('res.partner')
60
journal_pool = self.pool.get('account.journal')
61
line_pool = self.pool.get('account.voucher.line')
65
'value': {'line_dr_ids': [] ,'line_cr_ids': [] ,'pre_line': False,},
69
line_ids = ids and line_pool.search(cr, uid, [('voucher_id', '=', ids[0])]) or False
71
line_pool.unlink(cr, uid, line_ids)
73
if not partner_id or not journal_id:
76
journal = journal_pool.browse(cr, uid, journal_id, context=context)
77
partner = partner_pool.browse(cr, uid, partner_id, context=context)
78
currency_id = currency_id or journal.company_id.currency_id.id
82
account_type = 'receivable'
83
if ttype == 'payment':
84
account_type = 'payable'
85
total_debit = price or 0.0
87
total_credit = price or 0.0
88
account_type = 'receivable'
90
if not context.get('move_line_ids', False):
91
if account_type in ('payable', 'receivable'):
92
ids = move_line_pool.search(cr, uid, [('state','=','valid'), ('account_id.type', 'in', ('payable', 'receivable')), ('reconcile_id', '=', False), ('partner_id', '=', partner_id)], context=context)
94
ids = move_line_pool.search(cr, uid, [('state','=','valid'), ('account_id.type', '=', account_type), ('reconcile_id', '=', False), ('partner_id', '=', partner_id)], context=context)
96
ids = context['move_line_ids']
97
invoice_id = context.get('invoice_id', False)
98
company_currency = journal.company_id.currency_id.id
99
move_line_found = False
101
#order the lines by most old first
103
account_move_lines = move_line_pool.browse(cr, uid, ids, context=context)
105
#compute the total debit/credit and look for a matching open amount or invoice
106
for line in account_move_lines:
107
if _remove_noise_in_o2m():
111
if line.invoice.id == invoice_id:
112
#if the invoice linked to the voucher line is equal to the invoice_id in context
113
#then we assign the amount on that line, whatever the other voucher lines
114
move_line_found = line.id
116
elif currency_id == company_currency:
117
#otherwise treatments is the same but with other field names
118
if line.amount_residual == price:
119
#if the amount residual is equal the amount voucher, we assign it to that voucher
120
#line, whatever the other voucher lines
121
move_line_found = line.id
123
#otherwise we will split the voucher amount on each line (by most old first)
124
total_credit += line.credit or 0.0
125
total_debit += line.debit or 0.0
126
elif currency_id == line.currency_id.id:
127
if line.amount_residual_currency == price:
128
move_line_found = line.id
130
total_credit += line.credit and line.amount_currency or 0.0
131
total_debit += line.debit and line.amount_currency or 0.0
133
#voucher line creation
134
for line in account_move_lines:
136
if _remove_noise_in_o2m():
139
if line.currency_id and currency_id == line.currency_id.id:
140
amount_original = abs(line.amount_currency)
141
amount_unreconciled = abs(line.amount_residual_currency)
143
#always use the amount booked in the company currency as the basis of the conversion into the voucher currency
144
amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0, context=context_multi_currency)
145
amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual), context=context_multi_currency)
146
line_currency_id = line.currency_id and line.currency_id.id or company_currency
148
'name':line.move_id.name,
149
'type': line.credit and 'dr' or 'cr',
150
'move_line_id':line.id,
151
'account_id':line.account_id.id,
152
'amount_original': amount_original,
153
'amount': (move_line_found == line.id) and min(abs(price), amount_unreconciled) or 0.0,
154
'date_original':line.date,
155
'date_due':line.date_maturity,
156
'amount_unreconciled': amount_unreconciled,
157
'currency_id': line_currency_id,
159
#in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
160
#on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
161
if not move_line_found:
162
if currency_id == line_currency_id:
164
amount = min(amount_unreconciled, abs(total_debit))
165
rs['amount'] = amount
166
total_debit -= amount
168
amount = min(amount_unreconciled, abs(total_credit))
169
rs['amount'] = amount
170
total_credit -= amount
172
if rs['amount_unreconciled'] == rs['amount']:
173
rs['reconcile'] = True
175
if rs['type'] == 'cr':
176
default['value']['line_cr_ids'].append(rs)
178
default['value']['line_dr_ids'].append(rs)
180
if ttype == 'payment' and len(default['value']['line_cr_ids']) > 0:
181
default['value']['pre_line'] = 1
182
elif ttype == 'receipt' and len(default['value']['line_dr_ids']) > 0:
183
default['value']['pre_line'] = 1
184
default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price, ttype)