import time
from lxml import etree
-from openerp import netsvc
from openerp.osv import fields, osv
import openerp.addons.decimal_precision as dp
from openerp.tools.translate import _
from openerp.tools import float_compare
+from openerp.report import report_sxw
class res_currency(osv.osv):
_inherit = "res.currency"
- def _current_rate(self, cr, uid, ids, name, arg, context=None):
+ def _get_current_rate(self, cr, uid, ids, raise_on_no_rate=True, context=None):
if context is None:
context = {}
- res = super(res_currency, self)._current_rate(cr, uid, ids, name, arg, context=context)
+ res = super(res_currency, self)._get_current_rate(cr, uid, ids, raise_on_no_rate, context=context)
if context.get('voucher_special_currency') in ids and context.get('voucher_special_currency_rate'):
res[context.get('voucher_special_currency')] = context.get('voucher_special_currency_rate')
return res
- _columns = {
- # same definition of rate that in base in order to just overwrite the function
- 'rate': fields.function(_current_rate, string='Current Rate', digits=(12,6),
- help='The rate of the currency to the currency of rate 1.'),
- }
-
class res_company(osv.osv):
_inherit = "res.company"
domain="[('type', '=', 'other')]",),
}
-res_company()
class account_config_settings(osv.osv_memory):
_inherit = 'account.config.settings'
if context is None: context = {}
if context.get('period_id', False):
return context.get('period_id')
- ctx = dict(context, account_period_prefer_normal=True)
- periods = self.pool.get('account.period').find(cr, uid, context=ctx)
+ periods = self.pool.get('account.period').find(cr, uid, context=context)
return periods and periods[0] or False
def _make_journal_search(self, cr, uid, ttype, context=None):
if context.get('type', 'sale') in ('purchase', 'payment'):
nodes = doc.xpath("//field[@name='partner_id']")
for node in nodes:
- node.set('context', "{'search_default_supplier': 1}")
+ node.set('context', "{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}")
if context.get('invoice_type','') in ('in_invoice', 'in_refund'):
node.set('string', _("Supplier"))
res['arch'] = etree.tostring(doc)
line_osv = self.pool.get("account.voucher.line")
line_dr_ids = resolve_o2m_operations(cr, uid, line_osv, line_dr_ids, ['amount'], context)
line_cr_ids = resolve_o2m_operations(cr, uid, line_osv, line_cr_ids, ['amount'], context)
-
#compute the field is_multi_currency that is used to hide/display options linked to secondary currency on the voucher
is_multi_currency = False
#loop on the voucher lines to see if one of these has a secondary currency. If yes, we need to see the options
for voucher_line in line_dr_ids+line_cr_ids:
- line_currency = voucher_line.get('move_line_id', False) and self.pool.get('account.move.line').browse(cr, uid, voucher_line.get('move_line_id'), context=context).currency_id
- if line_currency:
+ line_id = voucher_line.get('id') and self.pool.get('account.voucher.line').browse(cr, uid, voucher_line['id'], context=context).move_line_id.id or voucher_line.get('move_line_id')
+ if line_id and self.pool.get('account.move.line').browse(cr, uid, line_id, context=context).currency_id:
is_multi_currency = True
break
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount, type), 'is_multi_currency': is_multi_currency}}
res[voucher.id] = self.pool.get('res.currency').compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, voucher.amount, context=ctx)
return res
+ def _get_currency_help_label(self, cr, uid, currency_id, payment_rate, payment_rate_currency_id, context=None):
+ """
+ This function builds a string to help the users to understand the behavior of the payment rate fields they can specify on the voucher.
+ This string is only used to improve the usability in the voucher form view and has no other effect.
+
+ :param currency_id: the voucher currency
+ :type currency_id: integer
+ :param payment_rate: the value of the payment_rate field of the voucher
+ :type payment_rate: float
+ :param payment_rate_currency_id: the value of the payment_rate_currency_id field of the voucher
+ :type payment_rate_currency_id: integer
+ :return: translated string giving a tip on what's the effect of the current payment rate specified
+ :rtype: str
+ """
+ rml_parser = report_sxw.rml_parse(cr, uid, 'currency_help_label', context=context)
+ currency_pool = self.pool.get('res.currency')
+ currency_str = payment_rate_str = ''
+ if currency_id:
+ currency_str = rml_parser.formatLang(1, currency_obj=currency_pool.browse(cr, uid, currency_id, context=context))
+ if payment_rate_currency_id:
+ payment_rate_str = rml_parser.formatLang(payment_rate, currency_obj=currency_pool.browse(cr, uid, payment_rate_currency_id, context=context))
+ currency_help_label = _('At the operation date, the exchange rate was\n%s = %s') % (currency_str, payment_rate_str)
+ return currency_help_label
+
+ def _fnct_currency_help_label(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for voucher in self.browse(cr, uid, ids, context=context):
+ res[voucher.id] = self._get_currency_help_label(cr, uid, voucher.currency_id.id, voucher.payment_rate, voucher.payment_rate_currency_id.id, context=context)
+ return res
+
_name = 'account.voucher'
_description = 'Accounting Voucher'
_inherit = ['mail.thread']
help='The specific rate that will be used, in this voucher, between the selected currency (in \'Payment Rate Currency\' field) and the voucher currency.'),
'paid_amount_in_company_currency': fields.function(_paid_amount_in_company_currency, string='Paid Amount in Company Currency', type='float', readonly=True),
'is_multi_currency': fields.boolean('Multi Currency Voucher', help='Fields with internal purpose only that depicts if the voucher is a multi currency one or not'),
+ 'currency_help_label': fields.function(_fnct_currency_help_label, type='text', string="Helping Sentence", help="This sentence helps you to know how to specify the payment rate by giving you the direct effect it has"),
}
_defaults = {
'active': True,
return default
def onchange_rate(self, cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=None):
- res = {'value': {'paid_amount_in_company_currency': amount}}
+ res = {'value': {'paid_amount_in_company_currency': amount, 'currency_help_label': self._get_currency_help_label(cr, uid, currency_id, rate, payment_rate_currency_id, context=context)}}
if rate and amount and currency_id:
company_currency = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id
#context should contain the date, the payment currency and the payment rate specified on the voucher
total_credit = 0.0
total_debit = 0.0
- account_type = 'receivable'
+ account_type = None
+ if context.get('account_id'):
+ account_type = self.pool['account.account'].browse(cr, uid, context['account_id'], context=context).type
if ttype == 'payment':
- account_type = 'payable'
+ if not account_type:
+ account_type = 'payable'
total_debit = price or 0.0
else:
total_credit = price or 0.0
- account_type = 'receivable'
+ if not account_type:
+ account_type = 'receivable'
if not context.get('move_line_ids', False):
ids = move_line_pool.search(cr, uid, [('state','=','valid'), ('account_id.type', '=', account_type), ('reconcile_id', '=', False), ('partner_id', '=', partner_id)], context=context)
ids = context['move_line_ids']
invoice_id = context.get('invoice_id', False)
company_currency = journal.company_id.currency_id.id
- move_line_found = False
+ move_lines_found = []
#order the lines by most old first
ids.reverse()
if line.invoice.id == invoice_id:
#if the invoice linked to the voucher line is equal to the invoice_id in context
#then we assign the amount on that line, whatever the other voucher lines
- move_line_found = line.id
- break
+ move_lines_found.append(line.id)
elif currency_id == company_currency:
#otherwise treatments is the same but with other field names
if line.amount_residual == price:
#if the amount residual is equal the amount voucher, we assign it to that voucher
#line, whatever the other voucher lines
- move_line_found = line.id
+ move_lines_found.append(line.id)
break
#otherwise we will split the voucher amount on each line (by most old first)
total_credit += line.credit or 0.0
total_debit += line.debit or 0.0
elif currency_id == line.currency_id.id:
if line.amount_residual_currency == price:
- move_line_found = line.id
+ move_lines_found.append(line.id)
break
total_credit += line.credit and line.amount_currency or 0.0
total_debit += line.debit and line.amount_currency or 0.0
'move_line_id':line.id,
'account_id':line.account_id.id,
'amount_original': amount_original,
- 'amount': (move_line_found == line.id) and min(abs(price), amount_unreconciled) or 0.0,
+ 'amount': (line.id in move_lines_found) and min(abs(price), amount_unreconciled) or 0.0,
'date_original':line.date,
'date_due':line.date_maturity,
'amount_unreconciled': amount_unreconciled,
'currency_id': line_currency_id,
}
+ price -= rs['amount']
#in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
#on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
- if not move_line_found:
+ if not move_lines_found:
if currency_id == line_currency_id:
if line.credit:
amount = min(amount_unreconciled, abs(total_debit))
else:
default['value']['line_dr_ids'].append(rs)
- if ttype == 'payment' and len(default['value']['line_cr_ids']) > 0:
+ if len(default['value']['line_cr_ids']) > 0:
default['value']['pre_line'] = 1
- elif ttype == 'receipt' and len(default['value']['line_dr_ids']) > 0:
+ elif len(default['value']['line_dr_ids']) > 0:
default['value']['pre_line'] = 1
default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price, ttype)
return default
if context is None:
context = {}
res = {'value': {}}
- if currency_id and currency_id == payment_rate_currency_id:
+ if currency_id:
#set the default payment rate of the voucher and compute the paid amount in company currency
ctx = context.copy()
ctx.update({'date': date})
return res
def onchange_journal(self, cr, uid, ids, journal_id, line_ids, tax_id, partner_id, date, amount, ttype, company_id, context=None):
+ if context is None:
+ context = {}
if not journal_id:
return False
journal_pool = self.pool.get('account.journal')
else:
currency_id = journal.company_id.currency_id.id
vals['value'].update({'currency_id': currency_id})
- res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context)
- for key in res.keys():
- vals[key].update(res[key])
+ #in case we want to register the payment directly from an invoice, it's confusing to allow to switch the journal
+ #without seeing that the amount is expressed in the journal currency, and not in the invoice currency. So to avoid
+ #this common mistake, we simply reset the amount to 0 if the currency is not the invoice currency.
+ if context.get('payment_expected_currency') and currency_id != context.get('payment_expected_currency'):
+ vals['value']['amount'] = 0
+ amount = 0
+ if partner_id:
+ res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context)
+ for key in res.keys():
+ vals[key].update(res[key])
return vals
def button_proforma_voucher(self, cr, uid, ids, context=None):
- context = context or {}
- wf_service = netsvc.LocalService("workflow")
- for vid in ids:
- wf_service.trg_validate(uid, 'account.voucher', vid, 'proforma_voucher', cr)
+ self.signal_proforma_voucher(cr, uid, ids)
return {'type': 'ir.actions.act_window_close'}
def proforma_voucher(self, cr, uid, ids, context=None):
return True
def action_cancel_draft(self, cr, uid, ids, context=None):
- wf_service = netsvc.LocalService("workflow")
- for voucher_id in ids:
- wf_service.trg_create(uid, 'account.voucher', voucher_id, cr)
+ self.create_workflow(cr, uid, ids)
self.write(cr, uid, ids, {'state':'draft'})
return True
move_pool = self.pool.get('account.move')
for voucher in self.browse(cr, uid, ids, context=context):
+ # refresh to make sure you don't unlink an already removed move
+ voucher.refresh()
recs = []
for line in voucher.move_ids:
if line.reconcile_id:
res = {}
if not partner_id:
return res
- res = {'account_id':False}
+ res = {}
partner_pool = self.pool.get('res.partner')
journal_pool = self.pool.get('account.journal')
if pay_now == 'pay_later':
account_id = partner.property_account_payable.id
else:
account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
- res['account_id'] = account_id
+ if account_id:
+ res['account_id'] = account_id
return {'value':res}
def _sel_context(self, cr, uid, voucher_id, context=None):
for line in voucher.line_ids:
#create one move line per voucher line where amount is not 0.0
# AND (second part of the clause) only if the original move line was not having debit = credit = 0 (which is a legal value)
- if not line.amount and not (line.move_line_id and not float_compare(line.move_line_id.debit, line.move_line_id.credit, precision_rounding=prec) and not float_compare(line.move_line_id.debit, 0.0, precision_rounding=prec)):
+ if not line.amount and not (line.move_line_id and not float_compare(line.move_line_id.debit, line.move_line_id.credit, precision_digits=prec) and not float_compare(line.move_line_id.debit, 0.0, precision_digits=prec)):
continue
# convert the amount set on the voucher line into the currency of the voucher's company
# this calls res_curreny.compute() with the right context, so that it will take either the rate on the voucher if it is relevant or will use the default behaviour
}
new_id = move_line_obj.create(cr, uid, move_line_foreign_currency, context=context)
rec_ids.append(new_id)
-
if line.move_line_id.id:
rec_lst_ids.append(rec_ids)
-
return (tot_line, rec_lst_ids)
def writeoff_move_line_get(self, cr, uid, voucher_id, line_total, move_id, name, company_currency, current_currency, context=None):
'date': voucher.date,
'credit': diff > 0 and diff or 0.0,
'debit': diff < 0 and -diff or 0.0,
- 'amount_currency': company_currency <> current_currency and (sign * -1 * voucher.writeoff_amount) or False,
+ 'amount_currency': company_currency <> current_currency and (sign * -1 * voucher.writeoff_amount) or 0.0,
'currency_id': company_currency <> current_currency and current_currency or False,
'analytic_account_id': voucher.analytic_id and voucher.analytic_id.id or False,
}
move_pool = self.pool.get('account.move')
move_line_pool = self.pool.get('account.move.line')
for voucher in self.browse(cr, uid, ids, context=context):
+ local_context = dict(context, force_company=voucher.journal_id.company_id.id)
if voucher.move_id:
continue
company_currency = self._get_company_currency(cr, uid, voucher.id, context)
# Get the name of the account_move just created
name = move_pool.browse(cr, uid, move_id, context=context).name
# Create the first line of the voucher
- move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, context), context)
+ move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, local_context), local_context)
move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)
line_total = move_line_brw.debit - move_line_brw.credit
rec_list_ids = []
line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)
# Create the writeoff line if needed
- ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)
+ ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, local_context)
if ml_writeoff:
- move_line_pool.create(cr, uid, ml_writeoff, context)
+ move_line_pool.create(cr, uid, ml_writeoff, local_context)
# We post the voucher.
self.write(cr, uid, [voucher.id], {
'move_id': move_id,
'type':ttype
})
return values
-account_voucher_line()
class account_bank_statement(osv.osv):
_inherit = 'account.bank.statement'
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, next_number, context=None):
voucher_obj = self.pool.get('account.voucher')
- wf_service = netsvc.LocalService("workflow")
move_line_obj = self.pool.get('account.move.line')
bank_st_line_obj = self.pool.get('account.bank.statement.line')
st_line = bank_st_line_obj.browse(cr, uid, st_line_id, context=context)
if st_line.voucher_id:
- voucher_obj.write(cr, uid, [st_line.voucher_id.id], {'number': next_number}, context=context)
+ voucher_obj.write(cr, uid, [st_line.voucher_id.id],
+ {'number': next_number,
+ 'date': st_line.date,
+ 'period_id': st_line.statement_id.period_id.id},
+ context=context)
if st_line.voucher_id.state == 'cancel':
voucher_obj.action_cancel_draft(cr, uid, [st_line.voucher_id.id], context=context)
- wf_service.trg_validate(uid, 'account.voucher', st_line.voucher_id.id, 'proforma_voucher', cr)
+ voucher_obj.signal_proforma_voucher(cr, uid, [st_line.voucher_id.id])
v = voucher_obj.browse(cr, uid, st_line.voucher_id.id, context=context)
bank_st_line_obj.write(cr, uid, [st_line_id], {
for bk_st in self.browse(cr, uid, ids, context=context):
if vals.get('journal_id') and bk_st.line_ids:
if any([x.voucher_id and True or False for x in bk_st.line_ids]):
- raise osv.except_osv(_('Unable to change journal !'), _('You can not change the journal as you already reconciled some statement lines!'))
+ raise osv.except_osv(_('Unable to Change Journal!'), _('You can not change the journal as you already reconciled some statement lines!'))
return super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
-account_bank_statement()
class account_bank_statement_line(osv.osv):
_inherit = 'account.bank.statement.line'
def _check_amount(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
if obj.voucher_id:
- diff = abs(obj.amount) - obj.voucher_id.amount
+ diff = abs(obj.amount) - abs(obj.voucher_id.amount)
if not self.pool.get('res.currency').is_zero(cr, uid, obj.statement_id.currency, diff):
return False
return True
voucher_obj.unlink(cr, uid, unlink_ids, context=context)
return super(account_bank_statement_line, self).unlink(cr, uid, ids, context=context)
-account_bank_statement_line()
def resolve_o2m_operations(cr, uid, target_osv, operations, fields, context):
results = []