[FIX] /web/login restore request.uid in case of authentication failure
[odoo/odoo.git] / addons / account_voucher / account_voucher.py
index cb4d702..771c6e1 100644 (file)
 import time
 from lxml import etree
 
-import netsvc
-from osv import osv, fields
-import decimal_precision as dp
-from tools.translate import _
+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 _get_current_rate(self, cr, uid, ids, raise_on_no_rate=True, context=None):
+        if context is None:
+            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
+
 
 class res_company(osv.osv):
     _inherit = "res.company"
@@ -40,7 +53,6 @@ class res_company(osv.osv):
             domain="[('type', '=', 'other')]",),
     }
 
-res_company()
 
 class account_config_settings(osv.osv_memory):
     _inherit = 'account.config.settings'
@@ -49,13 +61,25 @@ class account_config_settings(osv.osv_memory):
             'company_id', 'income_currency_exchange_account_id',
             type='many2one',
             relation='account.account',
-            string="Gain Exchange Rate Account"),
+            string="Gain Exchange Rate Account", 
+            domain="[('type', '=', 'other')]"),
         'expense_currency_exchange_account_id': fields.related(
             'company_id', 'expense_currency_exchange_account_id',
             type="many2one",
             relation='account.account',
-            string="Loss Exchange Rate Account"),
+            string="Loss Exchange Rate Account",
+            domain="[('type', '=', 'other')]"),
     }
+    def onchange_company_id(self, cr, uid, ids, company_id, context=None):
+        res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context)
+        if company_id:
+            company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
+            res['value'].update({'income_currency_exchange_account_id': company.income_currency_exchange_account_id and company.income_currency_exchange_account_id.id or False, 
+                                 'expense_currency_exchange_account_id': company.expense_currency_exchange_account_id and company.expense_currency_exchange_account_id.id or False})
+        else: 
+            res['value'].update({'income_currency_exchange_account_id': False, 
+                                 'expense_currency_exchange_account_id': False})
+        return res
 
 class account_voucher(osv.osv):
     def _check_paid(self, cr, uid, ids, name, args, context=None):
@@ -73,7 +97,7 @@ class account_voucher(osv.osv):
         if context is None: context = {}
         if context.get('period_id', False):
             return context.get('period_id')
-        periods = self.pool.get('account.period').find(cr, uid)
+        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):
@@ -142,7 +166,7 @@ class account_voucher(osv.osv):
             journal = journal_pool.browse(cr, uid, journal_id, context=context)
             if journal.currency:
                 return journal.currency.id
-        return False
+        return self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
     def _get_partner(self, cr, uid, context=None):
         if context is None: context = {}
@@ -193,7 +217,9 @@ class account_voucher(osv.osv):
         if context.get('type', 'sale') in ('purchase', 'payment'):
             nodes = doc.xpath("//field[@name='partner_id']")
             for node in nodes:
-                node.set('domain', "[('supplier', '=', True)]")
+                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)
         return res
 
@@ -209,26 +235,26 @@ class account_voucher(osv.osv):
     def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, voucher_currency, type, context=None):
         context = context or {}
         if not line_dr_ids and not line_cr_ids:
-            return {'value':{}}
+            return {'value':{'writeoff_amount': 0.0}}
         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
-        if voucher_currency:
-            # if the voucher currency is not False, it means it is different than the company currency and we need to display the options
-            is_multi_currency = True
-        else:
-            #loop on the voucher lines to see if one of these has a secondary currency. If yes, we need to define the options
-            for voucher_line in line_dr_ids+line_cr_ids:
-                company_currency = False
-                company_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).company_id.currency_id.id
-                if voucher_line.get('currency_id', company_currency) != company_currency:
-                    is_multi_currency = True
-                    break
+        #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_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}}
 
+    def _get_journal_currency(self, cr, uid, ids, name, args, context=None):
+        res = {}
+        for voucher in self.browse(cr, uid, ids, context=context):
+            res[voucher.id] = voucher.journal_id.currency and voucher.journal_id.currency.id or voucher.company_id.currency_id.id
+        return res
+
     def _get_writeoff_amount(self, cr, uid, ids, name, args, context=None):
         if not ids: return {}
         currency_obj = self.pool.get('res.currency')
@@ -245,20 +271,48 @@ class account_voucher(osv.osv):
         return res
 
     def _paid_amount_in_company_currency(self, cr, uid, ids, name, args, context=None):
-        if not ids: return {}
+        if context is None:
+            context = {}
+        res = {}
+        ctx = context.copy()
+        for v in self.browse(cr, uid, ids, context=context):
+            ctx.update({'date': v.date})
+            #make a new call to browse in order to have the right date in the context, to get the right currency rate
+            voucher = self.browse(cr, uid, v.id, context=ctx)
+            ctx.update({
+              'voucher_special_currency': voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id or False,
+              'voucher_special_currency_rate': voucher.currency_id.rate * voucher.payment_rate,})
+            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 = {}
-        rate = 1.0
         for voucher in self.browse(cr, uid, ids, context=context):
-            if voucher.currency_id:
-                if voucher.company_id.currency_id.id == voucher.payment_rate_currency_id.id:
-                    rate =  1 / voucher.payment_rate
-                else:
-                    ctx = context.copy()
-                    ctx.update({'date': voucher.date})
-                    voucher_rate = self.browse(cr, uid, voucher.id, context=ctx).currency_id.rate
-                    company_currency_rate = voucher.company_id.currency_id.rate
-                    rate = voucher_rate * company_currency_rate
-            res[voucher.id] =  voucher.amount / rate
+            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'
@@ -266,7 +320,14 @@ class account_voucher(osv.osv):
     _inherit = ['mail.thread']
     _order = "date desc, id desc"
 #    _rec_name = 'number'
+    _track = {
+        'state': {
+            'account_voucher.mt_voucher_state_change': lambda self, cr, uid, obj, ctx=None: True,
+        },
+    }
+
     _columns = {
+        'active': fields.boolean('Active', help="By default, reconciliation vouchers made on draft bank statements are set as inactive, which allow to hide the customer/supplier payment while the bank statement isn't confirmed."),
         'type':fields.selection([
             ('sale','Sale'),
             ('purchase','Purchase'),
@@ -284,15 +345,14 @@ class account_voucher(osv.osv):
             domain=[('type','=','dr')], context={'default_type':'dr'}, readonly=True, states={'draft':[('readonly',False)]}),
         'period_id': fields.many2one('account.period', 'Period', required=True, readonly=True, states={'draft':[('readonly',False)]}),
         'narration':fields.text('Notes', readonly=True, states={'draft':[('readonly',False)]}),
-#        'currency_id':fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
-        'currency_id': fields.related('journal_id','currency', type='many2one', relation='res.currency', string='Currency', readonly=True),
+        'currency_id': fields.function(_get_journal_currency, type='many2one', relation='res.currency', string='Currency', readonly=True, required=True),
         'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}),
         'state':fields.selection(
             [('draft','Draft'),
              ('cancel','Cancelled'),
              ('proforma','Pro-forma'),
              ('posted','Posted')
-            ], 'Status', readonly=True, size=32,
+            ], 'Status', readonly=True, size=32, track_visibility='onchange',
             help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Voucher. \
                         \n* The \'Pro-forma\' when voucher is in Pro-forma status,voucher does not have an voucher number. \
                         \n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \
@@ -326,8 +386,10 @@ class account_voucher(osv.osv):
             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,
         'period_id': _get_period,
         'partner_id': _get_partner,
         'journal_id':_get_journal,
@@ -348,11 +410,6 @@ class account_voucher(osv.osv):
         'payment_rate_currency_id': _get_payment_rate_currency,
     }
 
-    def create(self, cr, uid, vals, context=None):
-        voucher =  super(account_voucher, self).create(cr, uid, vals, context=context)
-        self.create_send_note(cr, uid, [voucher], context=context)
-        return voucher
-
     def compute_tax(self, cr, uid, ids, context=None):
         tax_pool = self.pool.get('account.tax')
         partner_pool = self.pool.get('res.partner')
@@ -384,7 +441,7 @@ class account_voucher(osv.osv):
                 for line in voucher.line_ids:
                     for tax_line in tax_pool.compute_all(cr, uid, tax, line.amount, 1).get('taxes', []):
                         total_tax += tax_line.get('amount', 0.0)
-                    total += total_tax
+                total += total_tax
             else:
                 for line in voucher.line_ids:
                     line_total = 0.0
@@ -406,6 +463,8 @@ class account_voucher(osv.osv):
         partner_pool = self.pool.get('res.partner')
         position_pool = self.pool.get('account.fiscal.position')
         line_pool = self.pool.get('account.voucher.line')
+        if not line_ids:
+            line_ids = []
         res = {
             'tax_amount': False,
             'amount': False,
@@ -500,23 +559,26 @@ class account_voucher(osv.osv):
         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}}
-        company_currency = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id
-        if rate and amount and currency_id:# and currency_id == payment_rate_currency_id:
-            voucher_rate = self.pool.get('res.currency').browse(cr, uid, currency_id, context).rate
-            if company_currency.id == payment_rate_currency_id:
-                company_rate = rate
-            else:
-                company_rate = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.rate
-            res['value']['paid_amount_in_company_currency'] = amount / voucher_rate * company_rate
+        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
+            amount_in_company_currency = self.pool.get('res.currency').compute(cr, uid, currency_id, company_currency.id, amount, context=context)
+            res['value']['paid_amount_in_company_currency'] = amount_in_company_currency
         return res
 
     def onchange_amount(self, cr, uid, ids, amount, rate, partner_id, journal_id, currency_id, ttype, date, payment_rate_currency_id, company_id, context=None):
         if context is None:
             context = {}
-        res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
         ctx = context.copy()
         ctx.update({'date': date})
+        #read the voucher rate with the right date in the context
+        currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
+        voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+        ctx.update({
+            'voucher_special_currency': payment_rate_currency_id,
+            'voucher_special_currency_rate': rate * voucher_rate})
+        res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=ctx)
         vals = self.onchange_rate(cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
         for key in vals.keys():
             res[key].update(vals[key])
@@ -530,6 +592,7 @@ class account_voucher(osv.osv):
         journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
         company_id = journal.company_id.id
         payment_rate = 1.0
+        currency_id = currency_id or journal.company_id.currency_id.id
         payment_rate_currency_id = currency_id
         ctx = context.copy()
         ctx.update({'date': date})
@@ -545,24 +608,62 @@ class account_voucher(osv.osv):
                     # is not in the voucher currency
                     payment_rate_currency_id = voucher_line['currency_id']
                     tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
-                    voucher_currency_id = currency_id or journal.company_id.currency_id.id
-                    payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
+                    payment_rate = tmp / currency_obj.browse(cr, uid, currency_id, context=ctx).rate
                     break
+        vals['value'].update({
+            'payment_rate': payment_rate,
+            'currency_id': currency_id,
+            'payment_rate_currency_id': payment_rate_currency_id
+        })
+        #read the voucher rate with the right date in the context
+        voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+        ctx.update({
+            'voucher_special_currency_rate': payment_rate * voucher_rate,
+            'voucher_special_currency': payment_rate_currency_id})
         res = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
         for key in res.keys():
             vals[key].update(res[key])
-        vals['value'].update({'payment_rate': payment_rate})
-        if payment_rate_currency_id:
-            vals['value'].update({'payment_rate_currency_id': payment_rate_currency_id})
         return vals
 
+    def basic_onchange_partner(self, cr, uid, ids, partner_id, journal_id, ttype, context=None):
+        partner_pool = self.pool.get('res.partner')
+        journal_pool = self.pool.get('account.journal')
+        res = {'value': {'account_id': False}}
+        if not partner_id or not journal_id:
+            return res
+
+        journal = journal_pool.browse(cr, uid, journal_id, context=context)
+        partner = partner_pool.browse(cr, uid, partner_id, context=context)
+        account_id = False
+        if journal.type in ('sale','sale_refund'):
+            account_id = partner.property_account_receivable.id
+        elif journal.type in ('purchase', 'purchase_refund','expense'):
+            account_id = partner.property_account_payable.id
+        else:
+            account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
+
+        res['value']['account_id'] = account_id
+        return res
+
     def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=None):
         if not journal_id:
             return {}
-        res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
-        vals = self.recompute_payment_rate(cr, uid, ids, res, currency_id, date, ttype, journal_id, amount, context=context)
+        if context is None:
+            context = {}
+        #TODO: comment me and use me directly in the sales/purchases views
+        res = self.basic_onchange_partner(cr, uid, ids, partner_id, journal_id, ttype, context=context)
+        if ttype in ['sale', 'purchase']:
+            return res
+        ctx = context.copy()
+        # not passing the payment_rate currency and the payment_rate in the context but it's ok because they are reset in recompute_payment_rate
+        ctx.update({'date': date})
+        vals = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=ctx)
+        vals2 = self.recompute_payment_rate(cr, uid, ids, vals, currency_id, date, ttype, journal_id, amount, context=context)
         for key in vals.keys():
             res[key].update(vals[key])
+        for key in vals2.keys():
+            res[key].update(vals2[key])
+        #TODO: can probably be removed now
         #TODO: onchange_partner_id() should not returns [pre_line, line_dr_ids, payment_rate...] for type sale, and not 
         # [pre_line, line_cr_ids, payment_rate...] for type purchase.
         # We should definitively split account.voucher object in two and make distinct on_change functions. In the 
@@ -594,20 +695,17 @@ class account_voucher(osv.osv):
                 This function returns True if the line is considered as noise and should not be displayed
             """
             if line.reconcile_partial_id:
-                sign = 1 if ttype == 'receipt' else -1
                 if currency_id == line.currency_id.id:
-                    if line.amount_residual_currency * sign <= 0:
+                    if line.amount_residual_currency <= 0:
                         return True
                 else:
-                    if line.amount_residual * sign <= 0:
+                    if line.amount_residual <= 0:
                         return True
             return False
 
         if context is None:
             context = {}
         context_multi_currency = context.copy()
-        if date:
-            context_multi_currency.update({'date': date})
 
         currency_pool = self.pool.get('res.currency')
         move_line_pool = self.pool.get('account.move.line')
@@ -631,28 +729,20 @@ class account_voucher(osv.osv):
         journal = journal_pool.browse(cr, uid, journal_id, context=context)
         partner = partner_pool.browse(cr, uid, partner_id, context=context)
         currency_id = currency_id or journal.company_id.currency_id.id
-        account_id = False
-        if journal.type in ('sale','sale_refund'):
-            account_id = partner.property_account_receivable.id
-        elif journal.type in ('purchase', 'purchase_refund','expense'):
-            account_id = partner.property_account_payable.id
-        else:
-            account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
-
-        default['value']['account_id'] = account_id
-
-        if journal.type not in ('cash', 'bank'):
-            return default
 
         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)
@@ -660,7 +750,7 @@ class account_voucher(osv.osv):
             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()
@@ -675,21 +765,20 @@ class account_voucher(osv.osv):
                 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
@@ -700,12 +789,13 @@ class account_voucher(osv.osv):
             if _remove_noise_in_o2m():
                 continue
 
-            if line.currency_id and currency_id==line.currency_id.id:
+            if line.currency_id and currency_id == line.currency_id.id:
                 amount_original = abs(line.amount_currency)
                 amount_unreconciled = abs(line.amount_residual_currency)
             else:
-                amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0)
-                amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual))
+                #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
+                amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0, context=context_multi_currency)
+                amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual), context=context_multi_currency)
             line_currency_id = line.currency_id and line.currency_id.id or company_currency
             rs = {
                 'name':line.move_id.name,
@@ -713,15 +803,16 @@ class account_voucher(osv.osv):
                 'move_line_id':line.id,
                 'account_id':line.account_id.id,
                 'amount_original': amount_original,
-                'amount': (move_line_found == line.id) and min(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,
             }
-
-            #split voucher amount by most old first, but only for lines in the same currency
-            if not move_line_found:
+            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_lines_found:
                 if currency_id == line_currency_id:
                     if line.credit:
                         amount = min(amount_unreconciled, abs(total_debit))
@@ -740,9 +831,9 @@ class account_voucher(osv.osv):
             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
@@ -751,10 +842,15 @@ class account_voucher(osv.osv):
         if context is None:
             context = {}
         res = {'value': {}}
-        #set the default payment rate of the voucher and compute the paid amount in company currency
-        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})
+            #read the voucher rate with the right date in the context
+            voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+            ctx.update({
+                'voucher_special_currency_rate': payment_rate * voucher_rate, 
+                'voucher_special_currency': payment_rate_currency_id})
             vals = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
             for key in vals.keys():
                 res[key].update(vals[key])
@@ -774,7 +870,8 @@ class account_voucher(osv.osv):
         period_pool = self.pool.get('account.period')
         currency_obj = self.pool.get('res.currency')
         ctx = context.copy()
-        ctx.update({'company_id': company_id})
+        ctx.update({'company_id': company_id, 'account_period_prefer_normal': True})
+        voucher_currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
         pids = period_pool.find(cr, uid, date, context=ctx)
         if pids:
             res['value'].update({'period_id':pids[0]})
@@ -783,15 +880,16 @@ class account_voucher(osv.osv):
             payment_rate = 1.0
             if payment_rate_currency_id != currency_id:
                 tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
-                voucher_currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
                 payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
-            vals = self.onchange_payment_rate_currency(cr, uid, ids, currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=context)
+            vals = self.onchange_payment_rate_currency(cr, uid, ids, voucher_currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=context)
             vals['value'].update({'payment_rate': payment_rate})
             for key in vals.keys():
                 res[key].update(vals[key])
         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')
@@ -808,17 +906,23 @@ class account_voucher(osv.osv):
         currency_id = False
         if journal.currency:
             currency_id = journal.currency.id
+        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):
@@ -826,9 +930,7 @@ class account_voucher(osv.osv):
         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
 
@@ -837,6 +939,8 @@ class account_voucher(osv.osv):
         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:
@@ -866,7 +970,7 @@ class account_voucher(osv.osv):
         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':
@@ -878,7 +982,8 @@ class account_voucher(osv.osv):
                 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):
@@ -895,8 +1000,8 @@ class account_voucher(osv.osv):
         current_currency = self._get_current_currency(cr, uid, voucher_id, context)
         if current_currency <> company_currency:
             context_multi_currency = context.copy()
-            voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
-            context_multi_currency.update({'date': voucher_brw.date})
+            voucher = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
+            context_multi_currency.update({'date': voucher.date})
             return context_multi_currency
         return context
 
@@ -911,33 +1016,33 @@ class account_voucher(osv.osv):
         :return: mapping between fieldname and value of account move line to create
         :rtype: dict
         '''
-        voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+        voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
         debit = credit = 0.0
         # TODO: is there any other alternative then the voucher type ??
         # ANSWER: We can have payment and receipt "In Advance".
         # TODO: Make this logic available.
         # -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
-        if voucher_brw.type in ('purchase', 'payment'):
-            credit = voucher_brw.paid_amount_in_company_currency
-        elif voucher_brw.type in ('sale', 'receipt'):
-            debit = voucher_brw.paid_amount_in_company_currency
+        if voucher.type in ('purchase', 'payment'):
+            credit = voucher.paid_amount_in_company_currency
+        elif voucher.type in ('sale', 'receipt'):
+            debit = voucher.paid_amount_in_company_currency
         if debit < 0: credit = -debit; debit = 0.0
         if credit < 0: debit = -credit; credit = 0.0
         sign = debit - credit < 0 and -1 or 1
         #set the first line of the voucher
         move_line = {
-                'name': voucher_brw.name or '/',
+                'name': voucher.name or '/',
                 'debit': debit,
                 'credit': credit,
-                'account_id': voucher_brw.account_id.id,
+                'account_id': voucher.account_id.id,
                 'move_id': move_id,
-                'journal_id': voucher_brw.journal_id.id,
-                'period_id': voucher_brw.period_id.id,
-                'partner_id': voucher_brw.partner_id.id,
+                'journal_id': voucher.journal_id.id,
+                'period_id': voucher.period_id.id,
+                'partner_id': voucher.partner_id.id,
                 'currency_id': company_currency <> current_currency and  current_currency or False,
-                'amount_currency': company_currency <> current_currency and sign * voucher_brw.amount or 0.0,
-                'date': voucher_brw.date,
-                'date_maturity': voucher_brw.date_due
+                'amount_currency': company_currency <> current_currency and sign * voucher.amount or 0.0,
+                'date': voucher.date,
+                'date_maturity': voucher.date_due
             }
         return move_line
 
@@ -950,26 +1055,31 @@ class account_voucher(osv.osv):
         :rtype: dict
         '''
         seq_obj = self.pool.get('ir.sequence')
-        voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
-        if voucher_brw.number:
-            name = voucher_brw.number
-        elif voucher_brw.journal_id.sequence_id:
-            name = seq_obj.next_by_id(cr, uid, voucher_brw.journal_id.sequence_id.id, context=context)
+        voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+        if voucher.number:
+            name = voucher.number
+        elif voucher.journal_id.sequence_id:
+            if not voucher.journal_id.sequence_id.active:
+                raise osv.except_osv(_('Configuration Error !'),
+                    _('Please activate the sequence of selected journal !'))
+            c = dict(context)
+            c.update({'fiscalyear_id': voucher.period_id.fiscalyear_id.id})
+            name = seq_obj.next_by_id(cr, uid, voucher.journal_id.sequence_id.id, context=c)
         else:
             raise osv.except_osv(_('Error!'),
                         _('Please define a sequence on the journal.'))
-        if not voucher_brw.reference:
+        if not voucher.reference:
             ref = name.replace('/','')
         else:
-            ref = voucher_brw.reference
+            ref = voucher.reference
 
         move = {
             'name': name,
-            'journal_id': voucher_brw.journal_id.id,
-            'narration': voucher_brw.narration,
-            'date': voucher_brw.date,
+            'journal_id': voucher.journal_id.id,
+            'narration': voucher.narration,
+            'date': voucher.date,
             'ref': ref,
-            'period_id': voucher_brw.period_id and voucher_brw.period_id.id or False
+            'period_id': voucher.period_id.id,
         }
         return move
 
@@ -996,7 +1106,10 @@ class account_voucher(osv.osv):
                 raise osv.except_osv(_('Insufficient Configuration!'),_("You should configure the 'Gain Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
         # Even if the amount_currency is never filled, we need to pass the foreign currency because otherwise
         # the receivable/payable account may have a secondary currency, which render this field mandatory
-        account_currency_id = company_currency <> current_currency and current_currency or False
+        if line.account_id.currency_id:
+            account_currency_id = line.account_id.currency_id.id
+        else:
+            account_currency_id = company_currency <> current_currency and current_currency or False
         move_line = {
             'journal_id': line.voucher_id.journal_id.id,
             'period_id': line.voucher_id.period_id.id,
@@ -1039,16 +1152,11 @@ class account_voucher(osv.osv):
         :return: the amount in the currency of the voucher's company
         :rtype: float
         '''
+        if context is None:
+            context = {}
         currency_obj = self.pool.get('res.currency')
         voucher = self.browse(cr, uid, voucher_id, context=context)
-        res = amount
-        if voucher.payment_rate_currency_id.id == voucher.company_id.currency_id.id:
-            # the rate specified on the voucher is for the company currency
-            res = currency_obj.round(cr, uid, voucher.company_id.currency_id, (amount * voucher.payment_rate))
-        else:
-            # the rate specified on the voucher is not relevant, we use all the rates in the system
-            res = currency_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=context)
-        return res
+        return currency_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=context)
 
     def voucher_move_line_create(self, cr, uid, voucher_id, line_total, move_id, company_currency, current_currency, context=None):
         '''
@@ -1072,37 +1180,45 @@ class account_voucher(osv.osv):
         tot_line = line_total
         rec_lst_ids = []
 
-        voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
+        date = self.read(cr, uid, voucher_id, ['date'], context=context)['date']
         ctx = context.copy()
-        ctx.update({'date': voucher_brw.date})
-        for line in voucher_brw.line_ids:
+        ctx.update({'date': date})
+        voucher = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context=ctx)
+        voucher_currency = voucher.journal_id.currency or voucher.company_id.currency_id
+        ctx.update({
+            'voucher_special_currency_rate': voucher_currency.rate * voucher.payment_rate ,
+            'voucher_special_currency': voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id or False,})
+        prec = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
+        for line in voucher.line_ids:
             #create one move line per voucher line where amount is not 0.0
-            if not line.amount:
+            # 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_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
-            amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher_brw.id, context=ctx)
+            # 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
+            amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher.id, context=ctx)
             # if the amount encoded in voucher is equal to the amount unreconciled, we need to compute the
             # currency rate difference
             if line.amount == line.amount_unreconciled:
-                if not line.move_line_id.amount_residual:
-                    raise osv.except_osv(_('Wrong bank statement line'),_("You have to delete the bank statement line which the payment was reconciled to manually. Please check the payment of the partner %s by the amount of %s.")%(line.voucher_id.partner_id.name, line.voucher_id.amount))
-                sign = voucher_brw.type in ('payment', 'purchase') and -1 or 1
+                if not line.move_line_id:
+                    raise osv.except_osv(_('Wrong voucher line'),_("The invoice you are willing to pay is not valid anymore."))
+                sign = voucher.type in ('payment', 'purchase') and -1 or 1
                 currency_rate_difference = sign * (line.move_line_id.amount_residual - amount)
             else:
                 currency_rate_difference = 0.0
             move_line = {
-                'journal_id': voucher_brw.journal_id.id,
-                'period_id': voucher_brw.period_id.id,
+                'journal_id': voucher.journal_id.id,
+                'period_id': voucher.period_id.id,
                 'name': line.name or '/',
                 'account_id': line.account_id.id,
                 'move_id': move_id,
-                'partner_id': voucher_brw.partner_id.id,
+                'partner_id': voucher.partner_id.id,
                 'currency_id': line.move_line_id and (company_currency <> line.move_line_id.currency_id.id and line.move_line_id.currency_id.id) or False,
                 'analytic_account_id': line.account_analytic_id and line.account_analytic_id.id or False,
                 'quantity': 1,
                 'credit': 0.0,
                 'debit': 0.0,
-                'date': voucher_brw.date
+                'date': voucher.date
             }
             if amount < 0:
                 amount = -amount
@@ -1118,9 +1234,9 @@ class account_voucher(osv.osv):
                 tot_line -= amount
                 move_line['credit'] = amount
 
-            if voucher_brw.tax_id and voucher_brw.type in ('sale', 'purchase'):
+            if voucher.tax_id and voucher.type in ('sale', 'purchase'):
                 move_line.update({
-                    'account_tax_id': voucher_brw.tax_id.id,
+                    'account_tax_id': voucher.tax_id.id,
                 })
 
             if move_line.get('account_tax_id', False):
@@ -1132,7 +1248,6 @@ class account_voucher(osv.osv):
             foreign_currency_diff = 0.0
             amount_currency = False
             if line.move_line_id:
-                voucher_currency = voucher_brw.currency_id and voucher_brw.currency_id.id or voucher_brw.journal_id.company_id.currency_id.id
                 # We want to set it on the account move line as soon as the original line had a foreign currency
                 if line.move_line_id.currency_id and line.move_line_id.currency_id.id != company_currency:
                     # we compute the amount in that foreign currency.
@@ -1140,22 +1255,19 @@ class account_voucher(osv.osv):
                         # if the voucher and the voucher line share the same currency, there is no computation to do
                         sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
                         amount_currency = sign * (line.amount)
-                    elif line.move_line_id.currency_id.id == voucher_brw.payment_rate_currency_id.id:
-                        # if the rate is specified on the voucher, we must use it
-                        voucher_rate = currency_obj.browse(cr, uid, voucher_currency, context=ctx).rate
-                        amount_currency = (move_line['debit'] - move_line['credit']) * voucher_brw.payment_rate * voucher_rate
                     else:
-                        # otherwise we use the rates of the system (giving the voucher date in the context)
+                        # if the rate is specified on the voucher, it will be used thanks to the special keys in the context
+                        # otherwise we use the rates of the system
                         amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
-                if line.amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:
-                    sign = voucher_brw.type in ('payment', 'purchase') and -1 or 1
+                if line.amount == line.amount_unreconciled:
+                    sign = voucher.type in ('payment', 'purchase') and -1 or 1
                     foreign_currency_diff = sign * line.move_line_id.amount_residual_currency + amount_currency
 
             move_line['amount_currency'] = amount_currency
             voucher_line = move_line_obj.create(cr, uid, move_line)
             rec_ids = [voucher_line, line.move_line_id.id]
 
-            if not currency_obj.is_zero(cr, uid, voucher_brw.company_id.currency_id, currency_rate_difference):
+            if not currency_obj.is_zero(cr, uid, voucher.company_id.currency_id, currency_rate_difference):
                 # Change difference entry in company currency
                 exch_lines = self._get_exchange_lines(cr, uid, line, move_id, currency_rate_difference, company_currency, current_currency, context=context)
                 new_id = move_line_obj.create(cr, uid, exch_lines[0],context)
@@ -1180,10 +1292,8 @@ class account_voucher(osv.osv):
                 }
                 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):
@@ -1202,32 +1312,32 @@ class account_voucher(osv.osv):
         currency_obj = self.pool.get('res.currency')
         move_line = {}
 
-        voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
-        current_currency_obj = voucher_brw.currency_id or voucher_brw.journal_id.company_id.currency_id
+        voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+        current_currency_obj = voucher.currency_id or voucher.journal_id.company_id.currency_id
 
         if not currency_obj.is_zero(cr, uid, current_currency_obj, line_total):
             diff = line_total
             account_id = False
             write_off_name = ''
-            if voucher_brw.payment_option == 'with_writeoff':
-                account_id = voucher_brw.writeoff_acc_id.id
-                write_off_name = voucher_brw.comment
-            elif voucher_brw.type in ('sale', 'receipt'):
-                account_id = voucher_brw.partner_id.property_account_receivable.id
+            if voucher.payment_option == 'with_writeoff':
+                account_id = voucher.writeoff_acc_id.id
+                write_off_name = voucher.comment
+            elif voucher.type in ('sale', 'receipt'):
+                account_id = voucher.partner_id.property_account_receivable.id
             else:
-                account_id = voucher_brw.partner_id.property_account_payable.id
-            sign = voucher_brw.type == 'payment' and -1 or 1
+                account_id = voucher.partner_id.property_account_payable.id
+            sign = voucher.type == 'payment' and -1 or 1
             move_line = {
                 'name': write_off_name or name,
                 'account_id': account_id,
                 'move_id': move_id,
-                'partner_id': voucher_brw.partner_id.id,
-                'date': voucher_brw.date,
+                'partner_id': voucher.partner_id.id,
+                '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_brw.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_brw.analytic_id and voucher_brw.analytic_id.id or False,
+                'analytic_account_id': voucher.analytic_id and voucher.analytic_id.id or False,
             }
 
         return move_line
@@ -1262,6 +1372,7 @@ class account_voucher(osv.osv):
         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)
@@ -1276,7 +1387,7 @@ class account_voucher(osv.osv):
             # 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 = []
@@ -1288,16 +1399,15 @@ class account_voucher(osv.osv):
             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,
                 'state': 'posted',
                 'number': name,
             })
-            self.post_send_note(cr, uid, [voucher.id], context=context)
             if voucher.journal_id.entry_posted:
                 move_pool.post(cr, uid, [move_id], context={})
             # We automatically reconcile the account move lines.
@@ -1305,8 +1415,6 @@ class account_voucher(osv.osv):
             for rec_ids in rec_list_ids:
                 if len(rec_ids) >= 2:
                     reconcile = move_line_pool.reconcile_partial(cr, uid, rec_ids, writeoff_acc_id=voucher.writeoff_acc_id.id, writeoff_period_id=voucher.period_id.id, writeoff_journal_id=voucher.journal_id.id)
-            if reconcile:
-                self.reconcile_send_note(cr, uid, [voucher.id], context=context)
         return True
 
     def copy(self, cr, uid, id, default=None, context=None):
@@ -1324,33 +1432,6 @@ class account_voucher(osv.osv):
             default['date'] = time.strftime('%Y-%m-%d')
         return super(account_voucher, self).copy(cr, uid, id, default, context)
 
-    # -----------------------------------------
-    # OpenChatter notifications and need_action
-    # -----------------------------------------
-    _document_type = {
-        'sale': 'Sales Receipt',
-        'purchase': 'Purchase Receipt',
-        'payment': 'Supplier Payment',
-        'receipt': 'Customer Payment',
-        False: 'Payment',
-    }
-
-    def create_send_note(self, cr, uid, ids, context=None):
-        for obj in self.browse(cr, uid, ids, context=context):
-            message = "%s <b>created</b>." % self._document_type[obj.type or False]
-            self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
-
-    def post_send_note(self, cr, uid, ids, context=None):
-        for obj in self.browse(cr, uid, ids, context=context):
-            message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
-            self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
-
-    def reconcile_send_note(self, cr, uid, ids, context=None):
-        for obj in self.browse(cr, uid, ids, context=context):
-            message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
-            self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
-
-account_voucher()
 
 class account_voucher_line(osv.osv):
     _name = 'account.voucher.line'
@@ -1358,13 +1439,17 @@ class account_voucher_line(osv.osv):
     _order = "move_line_id"
 
     # If the payment is in the same currency than the invoice, we keep the same amount
-    # Otherwise, we compute from company currency to payment currency
+    # Otherwise, we compute from invoice currency to payment currency
     def _compute_balance(self, cr, uid, ids, name, args, context=None):
         currency_pool = self.pool.get('res.currency')
         rs_data = {}
         for line in self.browse(cr, uid, ids, context=context):
             ctx = context.copy()
             ctx.update({'date': line.voucher_id.date})
+            voucher_rate = self.pool.get('res.currency').read(cr, uid, line.voucher_id.currency_id.id, ['rate'], context=ctx)['rate']
+            ctx.update({
+                'voucher_special_currency': line.voucher_id.payment_rate_currency_id and line.voucher_id.payment_rate_currency_id.id or False,
+                'voucher_special_currency_rate': line.voucher_id.payment_rate * voucher_rate})
             res = {}
             company_currency = line.voucher_id.journal_id.company_id.currency_id.id
             voucher_currency = line.voucher_id.currency_id and line.voucher_id.currency_id.id or company_currency
@@ -1374,13 +1459,11 @@ class account_voucher_line(osv.osv):
                 res['amount_original'] = 0.0
                 res['amount_unreconciled'] = 0.0
             elif move_line.currency_id and voucher_currency==move_line.currency_id.id:
-                res['amount_original'] = currency_pool.compute(cr, uid, move_line.currency_id.id, voucher_currency, abs(move_line.amount_currency), context=ctx)
-                res['amount_unreconciled'] = currency_pool.compute(cr, uid, move_line.currency_id and move_line.currency_id.id or company_currency, voucher_currency, abs(move_line.amount_residual_currency), context=ctx)
-            elif move_line and move_line.credit > 0:
-                res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit, context=ctx)
-                res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, abs(move_line.amount_residual), context=ctx)
+                res['amount_original'] = abs(move_line.amount_currency)
+                res['amount_unreconciled'] = abs(move_line.amount_residual_currency)
             else:
-                res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.debit, context=ctx)
+                #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
+                res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit or move_line.debit or 0.0, context=ctx)
                 res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, abs(move_line.amount_residual), context=ctx)
 
             rs_data[line.id] = res
@@ -1500,11 +1583,19 @@ class account_voucher_line(osv.osv):
             'type':ttype
         })
         return values
-account_voucher_line()
 
 class account_bank_statement(osv.osv):
     _inherit = 'account.bank.statement'
 
+    def button_confirm_bank(self, cr, uid, ids, context=None):
+        voucher_obj = self.pool.get('account.voucher')
+        voucher_ids = []
+        for statement in self.browse(cr, uid, ids, context=context):
+            voucher_ids += [line.voucher_id.id for line in statement.line_ids if line.voucher_id]
+        if voucher_ids:
+            voucher_obj.write(cr, uid, voucher_ids, {'active': True}, context=context)
+        return super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
+
     def button_cancel(self, cr, uid, ids, context=None):
         voucher_obj = self.pool.get('account.voucher')
         for st in self.browse(cr, uid, ids, context=context):
@@ -1517,15 +1608,18 @@ class account_bank_statement(osv.osv):
 
     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], {
@@ -1535,11 +1629,29 @@ class account_bank_statement(osv.osv):
             return move_line_obj.write(cr, uid, [x.id for x in v.move_ids], {'statement_id': st_line.statement_id.id}, context=context)
         return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line.id, company_currency_id, next_number, context=context)
 
-account_bank_statement()
+    def write(self, cr, uid, ids, vals, context=None):
+        # Restrict to modify the journal if we already have some voucher of reconciliation created/generated.
+        # Because the voucher keeps in memory the journal it was created with.
+        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!'))
+        return super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
+
 
 class account_bank_statement_line(osv.osv):
     _inherit = 'account.bank.statement.line'
 
+    def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
+        res = super(account_bank_statement_line, self).onchange_partner_id(cr, uid, ids, partner_id, context=context)
+        if 'value' not in res:
+            res['value'] = {}
+        res['value'].update({'voucher_id' : False})
+        return res
+
+    def onchange_amount(self, cr, uid, ids, amount, context=None):
+        return {'value' :  {'voucher_id' : False}}
+
     def _amount_reconciled(self, cursor, user, ids, name, args, context=None):
         if not ids:
             return {}
@@ -1554,7 +1666,7 @@ class account_bank_statement_line(osv.osv):
     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
@@ -1566,7 +1678,7 @@ class account_bank_statement_line(osv.osv):
     _columns = {
         'amount_reconciled': fields.function(_amount_reconciled,
             string='Amount reconciled', type='float'),
-        'voucher_id': fields.many2one('account.voucher', 'Payment'),
+        'voucher_id': fields.many2one('account.voucher', 'Reconciliation'),
     }
 
     def unlink(self, cr, uid, ids, context=None):
@@ -1579,7 +1691,6 @@ class account_bank_statement_line(osv.osv):
         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 = []