[FIX] bugfixed the incoming tax on onchange of product in supplier invoice and refund
[odoo/odoo.git] / addons / account / invoice.py
index fc5dbb6..de343ee 100644 (file)
@@ -1,30 +1,22 @@
 # -*- encoding: utf-8 -*-
 ##############################################################################
 #
-# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    $Id$
 #
-# $Id$
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
 #
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
 #
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
@@ -38,28 +30,37 @@ from mx.DateTime import RelativeDateTime
 from tools import config
 from tools.translate import _
 
-class account_invoice(osv.osv):
-    def _amount_untaxed(self, cr, uid, ids, name, args, context={}):
-        id_set=",".join(map(str,ids))
-        cr.execute("SELECT s.id,COALESCE(SUM(l.price_subtotal),0)::decimal(16,2) AS amount FROM account_invoice s LEFT OUTER JOIN account_invoice_line l ON (s.id=l.invoice_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
-        res=dict(cr.fetchall())
-        return res
+class fiscalyear_seq(osv.osv):
+    _name = "fiscalyear.seq"
+    _description = "Maintains Invoice sequences with Fiscal Year"
+    _rec_name = 'fiscalyear_id'
+    _columns = {
+        'journal_id': fields.many2one('account.journal', 'Journal'),
+        'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year',required=True),
+        'sequence_id':fields.many2one('ir.sequence', 'Sequence',required=True),
+    }
 
-    def _amount_tax(self, cr, uid, ids, name, args, context={}):
-        id_set=",".join(map(str,ids))
-        cr.execute("SELECT s.id,COALESCE(SUM(l.amount),0)::decimal(16,2) AS amount FROM account_invoice s LEFT OUTER JOIN account_invoice_tax l ON (s.id=l.invoice_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
-        res=dict(cr.fetchall())
-        return res
+fiscalyear_seq()
 
-    def _amount_total(self, cr, uid, ids, name, args, context={}):
-        untax = self._amount_untaxed(cr, uid, ids, name, args, context)
-        tax = self._amount_tax(cr, uid, ids, name, args, context)
+class account_invoice(osv.osv):
+    def _amount_all(self, cr, uid, ids, name, args, context=None):
         res = {}
-        for id in ids:
-            res[id] = untax.get(id,0.0) + tax.get(id,0.0)
+        for invoice in self.browse(cr,uid,ids, context=context):
+            res[invoice.id] = {
+                'amount_untaxed': 0.0,
+                'amount_tax': 0.0,
+                'amount_total': 0.0
+            }
+            for line in invoice.invoice_line:
+                res[invoice.id]['amount_untaxed'] += line.price_subtotal
+            for line in invoice.tax_line:
+                res[invoice.id]['amount_tax'] += line.amount
+            res[invoice.id]['amount_total'] = res[invoice.id]['amount_tax'] + res[invoice.id]['amount_untaxed']
         return res
 
     def _get_journal(self, cr, uid, context):
+        if context is None:
+            context = {}
         type_inv = context.get('type', 'out_invoice')
         type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale', 'in_refund': 'purchase'}
         journal_obj = self.pool.get('account.journal')
@@ -76,16 +77,17 @@ class account_invoice(osv.osv):
         else:
             return pooler.get_pool(cr.dbname).get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
 
-    def _get_journal_analytic(self, cr, uid, type_inv, context={}):
+    def _get_journal_analytic(self, cr, uid, type_inv, context=None):
         type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale', 'in_refund': 'purchase'}
         tt = type2journal.get(type_inv, 'sale')
-        cr.execute("select id from account_analytic_journal where type=%s limit 1", (tt,))
-        result = cr.fetchone()
+        result = self.pool.get('account.analytic.journal').search(cr, uid, [('type','=',tt)], context=context)
         if not result:
-            raise osv.except_osv(_('No Analytic Journal !'),("You have to define an analytic journal of type '%s' !") % (tt,))
+            raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal of type '%s' !") % (tt,))
         return result[0]
 
-    def _get_type(self, cr, uid, context={}):
+    def _get_type(self, cr, uid, context=None):
+        if context is None:
+            context = {}
         type = context.get('type', 'out_invoice')
         return type
 
@@ -95,18 +97,18 @@ class account_invoice(osv.osv):
             res[id] = self.test_paid(cr, uid, [id])
         return res
 
-    def _get_reference_type(self, cursor, user, context=None):
-        return [('none', 'Free Reference')]
+    def _get_reference_type(self, cr, uid, context=None):
+        return [('none', _('Free Reference'))]
 
-    def _amount_residual(self, cr, uid, ids, name, args, context={}):
+    def _amount_residual(self, cr, uid, ids, name, args, context=None):
         res = {}
         data_inv = self.browse(cr, uid, ids)
         for inv in data_inv:
             paid_amt = 0.0
             to_pay = inv.amount_total
             for lines in inv.move_lines:
-                paid_amt = paid_amt + lines.credit
-            res[inv.id] = to_pay - paid_amt
+                paid_amt = paid_amt - lines.credit + lines.debit
+            res[inv.id] = to_pay - abs(paid_amt)
         return res
 
     def _get_lines(self, cr, uid, ids, name, arg, context=None):
@@ -127,7 +129,19 @@ class account_invoice(osv.osv):
                 res[id]=[x for x in l if x <> line.id]
         return res
 
-    def _compute_lines(self, cr, uid, ids, name, args, context={}):
+    def _get_invoice_line(self, cr, uid, ids, context=None):
+        result = {}
+        for line in self.pool.get('account.invoice.line').browse(cr, uid, ids, context=context):
+            result[line.invoice_id.id] = True
+        return result.keys()
+
+    def _get_invoice_tax(self, cr, uid, ids, context=None):
+        result = {}
+        for tax in self.pool.get('account.invoice.tax').browse(cr, uid, ids, context=context):
+            result[tax.invoice_id.id] = True
+        return result.keys()
+
+    def _compute_lines(self, cr, uid, ids, name, args, context=None):
         result = {}
         for invoice in self.browse(cr, uid, ids, context):
             moves = self.move_line_id_payment_get(cr, uid, [invoice.id])
@@ -143,12 +157,38 @@ class account_invoice(osv.osv):
             result[invoice.id] = lines
         return result
 
+    def _get_invoice_from_line(self, cr, uid, ids, context={}):
+        move = {}
+        for line in self.pool.get('account.move.line').browse(cr, uid, ids):
+            if line.reconcile_partial_id:
+                for line2 in line.reconcile_partial_id.line_partial_ids:
+                    move[line2.move_id.id] = True
+            if line.reconcile_id:
+                for line2 in line.reconcile_id.line_id:
+                    move[line2.move_id.id] = True
+        invoice_ids = []
+        if move:
+            invoice_ids = self.pool.get('account.invoice').search(cr, uid, [('move_id','in',move.keys())], context=context)
+        return invoice_ids
+
+    def _get_invoice_from_reconcile(self, cr, uid, ids, context={}):
+        move = {}
+        for r in self.pool.get('account.move.reconcile').browse(cr, uid, ids):
+            for line in r.line_partial_ids:
+                move[line.move_id.id] = True
+            for line in r.line_id:
+                move[line.move_id.id] = True
+        invoice_ids = []
+        if move:
+            invoice_ids = self.pool.get('account.invoice').search(cr, uid, [('move_id','in',move.keys())], context=context)
+        return invoice_ids
+
     _name = "account.invoice"
     _description = 'Invoice'
     _order = "number"
     _columns = {
         'name': fields.char('Description', size=64, select=True,readonly=True, states={'draft':[('readonly',False)]}),
-        'origin': fields.char('Origin', size=64),
+        'origin': fields.char('Origin', size=64, help="Reference of the document that produced this invoice."),
         'type': fields.selection([
             ('out_invoice','Customer Invoice'),
             ('in_invoice','Supplier Invoice'),
@@ -156,53 +196,89 @@ class account_invoice(osv.osv):
             ('in_refund','Supplier Refund'),
             ],'Type', readonly=True, select=True),
 
-        'number': fields.char('Invoice Number', size=32, readonly=True),
-        'reference': fields.char('Invoice Reference', size=64),
+        'number': fields.char('Invoice Number', size=32, readonly=True, help="Unique number of the invoice, computed automatically when the invoice is created."),
+        'reference': fields.char('Invoice Reference', size=64, help="The partner reference of this invoice."),
         'reference_type': fields.selection(_get_reference_type, 'Reference Type',
             required=True),
-        'comment': fields.text('Additionnal Information'),
+        'comment': fields.text('Additional Information'),
 
         'state': fields.selection([
             ('draft','Draft'),
             ('proforma','Pro-forma'),
+            ('proforma2','Pro-forma'),
             ('open','Open'),
             ('paid','Done'),
-            ('cancel','Canceled')
+            ('cancel','Cancelled')
         ],'State', select=True, readonly=True),
 
-        'date_invoice': fields.date('Date Invoiced', required=True, states={'open':[('readonly',True)],'close':[('readonly',True)]}),
-        'date_due': fields.date('Due Date', states={'open':[('readonly',True)],'close':[('readonly',True)]}),
-
+        'date_invoice': fields.date('Date Invoiced', states={'open':[('readonly',True)],'close':[('readonly',True)]}),
+        'date_due': fields.date('Due Date', states={'open':[('readonly',True)],'close':[('readonly',True)]},
+            help="If you use payment terms, the due date will be computed automatically at the generation "\
+                "of accounting entries. If you keep the payment term and the due date empty, it means direct payment."),
         'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}),
         'address_contact_id': fields.many2one('res.partner.address', 'Contact Address', readonly=True, states={'draft':[('readonly',False)]}),
         'address_invoice_id': fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft':[('readonly',False)]}),
+        'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]},
+            help="If you use payment terms, the due date will be computed automatically at the generation "\
+                "of accounting entries. If you keep the payment term and the due date empty, it means direct payment. "\
+                "The payment term may compute several due dates: 50% now, 50% in one month."),
+        'period_id': fields.many2one('account.period', 'Force Period', domain=[('state','<>','done')], help="Keep empty to use the period of the validation date."),
 
-        'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]} ),
-
-        'period_id': fields.many2one('account.period', 'Force Period', help="Keep empty to use the period of the validation date."),
-
-        'account_id': fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}),
+        'account_id': fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="The partner account used for this invoice."),
         'invoice_line': fields.one2many('account.invoice.line', 'invoice_id', 'Invoice Lines', readonly=True, states={'draft':[('readonly',False)]}),
         'tax_line': fields.one2many('account.invoice.tax', 'invoice_id', 'Tax Lines', readonly=True, states={'draft':[('readonly',False)]}),
 
-        'move_id': fields.many2one('account.move', 'Invoice Movement', readonly=True),
-        'amount_untaxed': fields.function(_amount_untaxed, method=True, digits=(16,2),string='Untaxed', store=True),
-        'amount_tax': fields.function(_amount_tax, method=True, digits=(16,2), string='Tax', store=True),
-        'amount_total': fields.function(_amount_total, method=True, digits=(16,2), string='Total', store=True),
+        'move_id': fields.many2one('account.move', 'Invoice Movement', readonly=True, help="Link to the automatically generated account moves."),
+        'amount_untaxed': fields.function(_amount_all, method=True, digits=(16,2),string='Untaxed',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, None, 20),
+            },
+            multi='all'),
+        'amount_tax': fields.function(_amount_all, method=True, digits=(16,2), string='Tax',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, None, 20),
+            },
+            multi='all'),
+        'amount_total': fields.function(_amount_all, method=True, digits=(16,2), string='Total',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, None, 20),
+            },
+            multi='all'),
         'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
         'journal_id': fields.many2one('account.journal', 'Journal', required=True,readonly=True, states={'draft':[('readonly',False)]}),
         'company_id': fields.many2one('res.company', 'Company', required=True),
         'check_total': fields.float('Total', digits=(16,2), states={'open':[('readonly',True)],'close':[('readonly',True)]}),
-        'reconciled': fields.function(_reconciled, method=True, string='Paid/Reconciled', type='boolean'),
+        'reconciled': fields.function(_reconciled, method=True, string='Paid/Reconciled', type='boolean',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50),
+                'account.move.line': (_get_invoice_from_line, None, 50),
+                'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
+            }, help="The account moves of the invoice have been reconciled with account moves of the payment(s)."),
         'partner_bank': fields.many2one('res.partner.bank', 'Bank Account',
             help='The bank account to pay to or to be paid from'),
         'move_lines':fields.function(_get_lines , method=True,type='many2many' , relation='account.move.line',string='Move Lines'),
-        'residual': fields.function(_amount_residual, method=True, digits=(16,2),string='Residual', store=True),
+        'residual': fields.function(_amount_residual, method=True, digits=(16,2),string='Residual',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50),
+                'account.invoice.tax': (_get_invoice_tax, None, 50),
+                'account.invoice.line': (_get_invoice_line, None, 50),
+                'account.move.line': (_get_invoice_from_line, None, 50),
+                'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
+            },
+            help="Remaining amount due."),
         'payment_ids': fields.function(_compute_lines, method=True, relation='account.move.line', type="many2many", string='Payments'),
+        'move_name': fields.char('Account Move', size=64),
+        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position')
     }
     _defaults = {
         'type': _get_type,
-        'date_invoice': lambda *a: time.strftime('%Y-%m-%d'),
+        #'date_invoice': lambda *a: time.strftime('%Y-%m-%d'),
         'state': lambda *a: 'draft',
         'journal_id': _get_journal,
         'currency_id': _get_currency,
@@ -212,7 +288,7 @@ class account_invoice(osv.osv):
         'reference_type': lambda *a: 'none',
     }
 
-    def unlink(self, cr, uid, ids):
+    def unlink(self, cr, uid, ids, context=None):
         invoices = self.read(cr, uid, ids, ['state'])
         unlink_ids = []
         for t in invoices:
@@ -220,7 +296,7 @@ class account_invoice(osv.osv):
                 unlink_ids.append(t['id'])
             else:
                 raise osv.except_osv(_('Invalid action !'), _('Cannot delete invoice(s) which are already opened or paid !'))
-        osv.osv.unlink(self, cr, uid, unlink_ids)
+        osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
         return True
 
 #   def get_invoice_address(self, cr, uid, ids):
@@ -234,6 +310,7 @@ class account_invoice(osv.osv):
         partner_payment_term = False
         acc_id = False
         bank_id = False
+        fiscal_position = False
 
         opt = [('uid', str(uid))]
         if partner_id:
@@ -247,7 +324,7 @@ class account_invoice(osv.osv):
                 acc_id = p.property_account_receivable.id
             else:
                 acc_id = p.property_account_payable.id
-
+            fiscal_position = p.property_account_position and p.property_account_position.id or False
             partner_payment_term = p.property_payment_term and p.property_payment_term.id or False
             if p.bank_ids:
                 bank_id = p.bank_ids[0].id
@@ -257,6 +334,7 @@ class account_invoice(osv.osv):
             'address_invoice_id': invoice_addr_id,
             'account_id': acc_id,
             'payment_term': partner_payment_term,
+            'fiscal_position': fiscal_position
             }
         }
 
@@ -286,7 +364,7 @@ class account_invoice(osv.osv):
         pt_obj= self.pool.get('account.payment.term')
 
         if not date_invoice :
-            date_invoice = self._defaults["date_invoice"](cr,uid,{})
+            date_invoice = time.strftime('%Y-%m-%d')
 
         pterm_list= pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
 
@@ -331,9 +409,9 @@ class account_invoice(osv.osv):
         if default is None:
             default = {}
         default = default.copy()
-        default.update({'state':'draft', 'number':False, 'move_id':False,})
+        default.update({'state':'draft', 'number':False, 'move_id':False, 'move_name':False,})
         if 'date_invoice' not in default:
-            default['date_invoice'] = time.strftime('%Y-%m-%d')
+            default['date_invoice'] = False
         if 'date_due' not in default:
             default['date_due'] = False
         return super(account_invoice, self).copy(cr, uid, id, default, context)
@@ -344,43 +422,24 @@ class account_invoice(osv.osv):
             return False
         ok = True
         for id in res:
-            cr.execute('select reconcile_id from account_move_line where id=%d', (id,))
+            cr.execute('select reconcile_id from account_move_line where id=%s', (id,))
             ok = ok and  bool(cr.fetchone()[0])
         return ok
 
-    def button_reset_taxes(self, cr, uid, ids, context={}):
+    def button_reset_taxes(self, cr, uid, ids, context=None):
         ait_obj = self.pool.get('account.invoice.tax')
         for id in ids:
-            cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%d", (id,))
+            cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%s", (id,))
             for taxe in ait_obj.compute(cr, uid, id).values():
                 ait_obj.create(cr, uid, taxe)
+         # Update the stored value (fields.function), so we write to trigger recompute
+        self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context)    
+#        self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context)
         return True
 
-    def button_compute(self, cr, uid, ids, context={}, set_total=False):
-        ait_obj = self.pool.get('account.invoice.tax')
-        cur_obj = self.pool.get('res.currency')
+    def button_compute(self, cr, uid, ids, context=None, set_total=False):
+        self.button_reset_taxes(cr, uid, ids, context)
         for inv in self.browse(cr, uid, ids):
-            company_currency = inv.company_id.currency_id.id
-            compute_taxes = ait_obj.compute(cr, uid, inv.id)
-            if not inv.tax_line:
-                for tax in compute_taxes.values():
-                    ait_obj.create(cr, uid, tax)
-            else:
-                tax_key = []
-                for tax in inv.tax_line:
-                    if tax.manual:
-                        continue
-                    key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id)
-                    tax_key.append(key)
-                    if not key in compute_taxes:
-                        ait_obj.unlink(cr, uid, [tax.id])
-                        continue
-                    compute_taxes[key]['base'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, compute_taxes[key]['base'], context={'date': inv.date_invoice})
-                    if abs(compute_taxes[key]['base'] - tax.base) > inv.company_id.currency_id.rounding:
-                        ait_obj.write(cr, uid, [tax.id], compute_taxes[key])
-                for key in compute_taxes:
-                    if not key in tax_key:
-                        ait_obj.create(cr, uid, compute_taxes[key])
             if set_total:
                 self.pool.get('account.invoice').write(cr, uid, [inv.id], {'check_total': inv.amount_total})
         return True
@@ -388,7 +447,7 @@ class account_invoice(osv.osv):
     def _convert_ref(self, cr, uid, ref):
         return (ref or '').replace('/','')
 
-    def _get_analityc_lines(self, cr, uid, id):
+    def _get_analytic_lines(self, cr, uid, id):
         inv = self.browse(cr, uid, [id])[0]
         cur_obj = self.pool.get('res.currency')
 
@@ -422,17 +481,19 @@ class account_invoice(osv.osv):
     def action_move_create(self, cr, uid, ids, *args):
         ait_obj = self.pool.get('account.invoice.tax')
         cur_obj = self.pool.get('res.currency')
+
         for inv in self.browse(cr, uid, ids):
             if inv.move_id:
                 continue
-            if inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0):
-                raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe real total does not match the computed total.'))
+
+            if not inv.date_invoice:
+                self.write(cr, uid, [inv.id], {'date_invoice':time.strftime('%Y-%m-%d')})
             company_currency = inv.company_id.currency_id.id
             # create the analytical lines
             line_ids = self.read(cr, uid, [inv.id], ['invoice_line'])[0]['invoice_line']
             ils = self.pool.get('account.invoice.line').read(cr, uid, line_ids)
             # one move line per invoice line
-            iml = self._get_analityc_lines(cr, uid, inv.id)
+            iml = self._get_analytic_lines(cr, uid, inv.id)
             # check if taxes are all computed
             compute_taxes = ait_obj.compute(cr, uid, inv.id)
             if not inv.tax_line:
@@ -454,6 +515,9 @@ class account_invoice(osv.osv):
                     if not key in tax_key:
                         raise osv.except_osv(_('Warning !'), _('Taxes missing !'))
 
+            if inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0):
+                raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe real total does not match the computed total.'))
+
             # one move line per tax line
             iml += ait_obj.move_line_get(cr, uid, inv.id)
 
@@ -472,7 +536,7 @@ class account_invoice(osv.osv):
                     i['amount_currency'] = i['price']
                     i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id,
                             company_currency, i['price'],
-                            context={'date': inv.date_invoice})
+                            context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
                 else:
                     i['amount_currency'] = False
                     i['currency_id'] = False
@@ -533,38 +597,57 @@ class account_invoice(osv.osv):
                     'ref': ref
             })
 
-            date = inv.date_invoice
+            date = inv.date_invoice or time.strftime('%Y-%m-%d')
             part = inv.partner_id.id
+
             line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, part, date, context={})) ,iml)
 
+            if inv.journal_id.group_invoice_lines:
+                line2 = {}
+                for x, y, l in line:
+                    tmp = str(l['account_id'])
+                    tmp += '-'+str('tax_code_id' in l and l['tax_code_id'] or "False")
+                    tmp += '-'+str('product_id' in l and l['product_id'] or "False")
+                    tmp += '-'+str('analytic_account_id' in l and l['analytic_account_id'] or "False")
+
+                    if tmp in line2:
+                        am = line2[tmp]['debit'] - line2[tmp]['credit'] + (l['debit'] - l['credit'])
+                        line2[tmp]['debit'] = (am > 0) and am or 0.0
+                        line2[tmp]['credit'] = (am < 0) and -am or 0.0
+                        line2[tmp]['tax_amount'] += l['tax_amount']
+                        line2[tmp]['analytic_lines'] += l['analytic_lines']
+                    else:
+                        line2[tmp] = l
+                line = []
+                for key, val in line2.items():
+                    line.append((0,0,val))
+
             journal_id = inv.journal_id.id #self._get_journal(cr, uid, {'type': inv['type']})
             journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
-            if journal.sequence_id:
-                name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
             if journal.centralisation:
                 raise osv.except_osv(_('UserError'),
-                        _('Can not create invoice move on centralized journal'))
-
-            move = {'name': name, 'line_id': line, 'journal_id': journal_id}
+                        _('Can not create invoice move on centralised journal'))
+            move = {'ref': inv.number, 'line_id': line, 'journal_id': journal_id, 'date': date}
             period_id=inv.period_id and inv.period_id.id or False
             if not period_id:
-                period_ids= self.pool.get('account.period').search(cr,uid,[('date_start','<=',inv.date_invoice),('date_stop','>=',inv.date_invoice)])
+                period_ids= self.pool.get('account.period').search(cr,uid,[('date_start','<=',inv.date_invoice or time.strftime('%Y-%m-%d')),('date_stop','>=',inv.date_invoice or time.strftime('%Y-%m-%d'))])
                 if len(period_ids):
                     period_id=period_ids[0]
             if period_id:
                 move['period_id'] = period_id
                 for i in line:
                     i[2]['period_id'] = period_id
+
             move_id = self.pool.get('account.move').create(cr, uid, move)
+            new_move_name = self.pool.get('account.move').browse(cr, uid, move_id).name
             # make the invoice point to that move
-            self.write(cr, uid, [inv.id], {'move_id': move_id,'period_id':period_id})
+            self.write(cr, uid, [inv.id], {'move_id': move_id,'period_id':period_id, 'move_name':new_move_name})
             self.pool.get('account.move').post(cr, uid, [move_id])
         self._log_event(cr, uid, ids)
         return True
 
-    def line_get_convert(self, cr, uid, x, part, date, context={}):
+    def line_get_convert(self, cr, uid, x, part, date, context=None):
         return {
-            'date':date,
             'date_maturity': x.get('date_maturity', False),
             'partner_id':part,
             'name':x['name'][:64],
@@ -576,29 +659,41 @@ class account_invoice(osv.osv):
             'currency_id':x.get('currency_id', False),
             'tax_code_id': x.get('tax_code_id', False),
             'tax_amount': x.get('tax_amount', False),
-            'ref':x.get('ref',False)
+            'ref':x.get('ref',False),
+            'quantity':x.get('quantity',1.00),
+            'product_id':x.get('product_id', False),
+            'product_uom_id':x.get('uos_id',False),
+            'analytic_account_id':x.get('account_analytic_id',False),
         }
 
     def action_number(self, cr, uid, ids, *args):
         cr.execute('SELECT id, type, number, move_id, reference ' \
                 'FROM account_invoice ' \
                 'WHERE id IN ('+','.join(map(str,ids))+')')
+        obj_inv = self.browse(cr, uid, ids)[0]
         for (id, invtype, number, move_id, reference) in cr.fetchall():
             if not number:
-                number = self.pool.get('ir.sequence').get(cr, uid,
-                        'account.invoice.' + invtype)
+                if obj_inv.journal_id.invoice_sequence_id:
+                    sid = obj_inv.journal_id.invoice_sequence_id.id
+                    number = self.pool.get('ir.sequence').get_id(cr, uid, sid, 'id=%s', {'fiscalyear_id': obj_inv.period_id.fiscalyear_id.id})
+                else:
+                    number = self.pool.get('ir.sequence').get(cr, uid,
+                            'account.invoice.' + invtype)
                 if invtype in ('in_invoice', 'in_refund'):
                     ref = reference
                 else:
                     ref = self._convert_ref(cr, uid, number)
                 cr.execute('UPDATE account_invoice SET number=%s ' \
-                        'WHERE id=%d', (number, id))
+                        'WHERE id=%s', (number, id))
+                cr.execute('UPDATE account_move SET ref=%s ' \
+                        'WHERE id=%s AND (ref is null OR ref = \'\')',
+                        (ref, move_id))
                 cr.execute('UPDATE account_move_line SET ref=%s ' \
-                        'WHERE move_id=%d AND (ref is null OR ref = \'\')',
+                        'WHERE move_id=%s AND (ref is null OR ref = \'\')',
                         (ref, move_id))
                 cr.execute('UPDATE account_analytic_line SET ref=%s ' \
                         'FROM account_move_line ' \
-                        'WHERE account_move_line.move_id = %d ' \
+                        'WHERE account_move_line.move_id = %s ' \
                             'AND account_analytic_line.move_id = account_move_line.id',
                             (ref, move_id))
         return True
@@ -633,7 +728,7 @@ class account_invoice(osv.osv):
         for inv in invs:
             part=inv['partner_id'] and inv['partner_id'][0]
             pc = pr = 0.0
-            cr.execute('select sum(quantity*price_unit) from account_invoice_line where invoice_id=%d', (inv['id'],))
+            cr.execute('select sum(quantity*price_unit) from account_invoice_line where invoice_id=%s', (inv['id'],))
             total = inv['amount_untaxed']
             if inv['type'] in ('in_invoice','in_refund'):
                 partnertype='supplier'
@@ -647,7 +742,7 @@ class account_invoice(osv.osv):
                 self.pool.get('res.partner.event').create(cr, uid, {'name':'Invoice: '+name, 'som':False, 'description':name+' '+str(inv['id']), 'document':name, 'partner_id':part, 'date':time.strftime('%Y-%m-%d %H:%M:%S'), 'canal_id':False, 'user_id':uid, 'partner_type':partnertype, 'probability':1.0, 'planned_revenue':pr, 'planned_cost':pc, 'type':eventtype})
         return len(invs)
 
-    def name_get(self, cr, uid, ids, context={}):
+    def name_get(self, cr, uid, ids, context=None):
         if not len(ids):
             return []
         types = {
@@ -661,7 +756,7 @@ class account_invoice(osv.osv):
     def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
         if not args:
             args=[]
-        if not context:
+        if context is None:
             context={}
         ids = []
         if name:
@@ -684,9 +779,15 @@ class account_invoice(osv.osv):
                 line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ]
             if 'account_analytic_id' in line:
                 line['account_analytic_id'] = line.get('account_analytic_id', False) and line['account_analytic_id'][0]
+            if 'tax_code_id' in line :
+                if isinstance(line['tax_code_id'],tuple)  and len(line['tax_code_id']) >0 :
+                    line['tax_code_id'] = line['tax_code_id'][0]
+            if 'base_code_id' in line :
+                if isinstance(line['base_code_id'],tuple)  and len(line['base_code_id']) >0 :
+                    line['base_code_id'] = line['base_code_id'][0]
         return map(lambda x: (0,0,x), lines)
 
-    def refund(self, cr, uid, ids):
+    def refund(self, cr, uid, ids, date=None, period_id=None, description=None):
         invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'address_contact_id', 'address_invoice_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id'])
 
         new_ids = []
@@ -707,68 +808,69 @@ class account_invoice(osv.osv):
             tax_lines = self.pool.get('account.invoice.tax').read(cr, uid, invoice['tax_line'])
             tax_lines = filter(lambda l: l['manual'], tax_lines)
             tax_lines = self._refund_cleanup_lines(tax_lines)
-
+            if not date :
+                date = time.strftime('%Y-%m-%d')
             invoice.update({
                 'type': type_dict[invoice['type']],
-                'date_invoice': time.strftime('%Y-%m-%d'),
+                'date_invoice': date,
                 'state': 'draft',
                 'number': False,
                 'invoice_line': invoice_lines,
                 'tax_line': tax_lines
             })
-
+            if period_id :
+                invoice.update({
+                    'period_id': period_id,
+                })
+            if description :
+                invoice.update({
+                    'name': description,
+                })
             # take the id part of the tuple returned for many2one fields
             for field in ('address_contact_id', 'address_invoice_id', 'partner_id',
                     'account_id', 'currency_id', 'payment_term', 'journal_id'):
                 invoice[field] = invoice[field] and invoice[field][0]
-
             # create the new invoice
             new_ids.append(self.create(cr, uid, invoice))
         return new_ids
 
-    def pay_and_reconcile(self, cr, uid, ids, pay_amount, pay_account_id, period_id, pay_journal_id, writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context={}, name=''):
+    def pay_and_reconcile(self, cr, uid, ids, pay_amount, pay_account_id, period_id, pay_journal_id, writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context=None, name=''):
+        if context is None:
+            context = {}
         #TODO check if we can use different period for payment and the writeoff line
         assert len(ids)==1, "Can only pay one invoice at a time"
         invoice = self.browse(cr, uid, ids[0])
         src_account_id = invoice.account_id.id
-        journal = self.pool.get('account.journal').browse(cr, uid, pay_journal_id)
-        if journal.sequence_id:
-            name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
-        else:
-            raise osv.except_osv(_('No piece number !'), _('Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.'))
         # Take the seq as name for move
-        if journal.sequence_id:
-            seq = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
-        else:
-            raise osv.except_osv('No piece number !', 'Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')
         types = {'out_invoice': -1, 'in_invoice': 1, 'out_refund': 1, 'in_refund': -1}
         direction = types[invoice.type]
         #take the choosen date
-        if context.has_key('date_p') and context['date_p']:
+        if 'date_p' in context and context['date_p']:
             date=context['date_p']
         else:
             date=time.strftime('%Y-%m-%d')
         l1 = {
-            'name': name,
             'debit': direction * pay_amount>0 and direction * pay_amount,
             'credit': direction * pay_amount<0 and - direction * pay_amount,
             'account_id': src_account_id,
             'partner_id': invoice.partner_id.id,
-            'date': date,
             'ref':invoice.number,
         }
         l2 = {
-            'name':name,
             'debit': direction * pay_amount<0 and - direction * pay_amount,
             'credit': direction * pay_amount>0 and direction * pay_amount,
             'account_id': pay_account_id,
             'partner_id': invoice.partner_id.id,
-            'date': date,
             'ref':invoice.number,
         }
 
+        if not name:
+            name = invoice.invoice_line and invoice.invoice_line[0].name or invoice.number
+        l1['name'] = name
+        l2['name'] = name
+
         lines = [(0, 0, l1), (0, 0, l2)]
-        move = {'name': seq, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id}
+        move = {'ref': invoice.number, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date}
         move_id = self.pool.get('account.move').create(cr, uid, move)
 
         line_ids = []
@@ -776,7 +878,7 @@ class account_invoice(osv.osv):
         line = self.pool.get('account.move.line')
         cr.execute('select id from account_move_line where move_id in ('+str(move_id)+','+str(invoice.move_id.id)+')')
         lines = line.browse(cr, uid, map(lambda x: x[0], cr.fetchall()) )
-        for l in lines:
+        for l in lines+invoice.payment_ids:
             if l.account_id.id==src_account_id:
                 line_ids.append(l.id)
                 total += (l.debit or 0.0) - (l.credit or 0.0)
@@ -784,6 +886,9 @@ class account_invoice(osv.osv):
             self.pool.get('account.move.line').reconcile(cr, uid, line_ids, 'manual', writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context)
         else:
             self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context)
+
+        # Update the stored value (fields.function), so we write to trigger recompute
+        self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context)
         return True
 account_invoice()
 
@@ -794,7 +899,9 @@ class account_invoice_line(osv.osv):
             res[line.id] = round(line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0),2)
         return res
 
-    def _price_unit_default(self, cr, uid, context={}):
+    def _price_unit_default(self, cr, uid, context=None):
+        if context is None:
+            context = {}
         if 'check_total' in context:
             t = context['check_total']
             for l in context.get('invoice_line', {}):
@@ -814,10 +921,11 @@ class account_invoice_line(osv.osv):
     _description = "Invoice line"
     _columns = {
         'name': fields.char('Description', size=256, required=True),
+        'origin': fields.char('Origin', size=256, help="Reference of the document that produced this invoice."),
         'invoice_id': fields.many2one('account.invoice', 'Invoice Ref', ondelete='cascade', select=True),
-        'uos_id': fields.many2one('product.uom', 'Unit', ondelete='set null'),
+        'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'),
         'product_id': fields.many2one('product.product', 'Product', ondelete='set null'),
-        'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')]),
+        'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."),
         'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
         'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',store=True),
         'quantity': fields.float('Quantity', required=True),
@@ -832,7 +940,7 @@ class account_invoice_line(osv.osv):
         'price_unit': _price_unit_default,
     }
 
-    def product_id_change_unit_price_inv(self, cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context={}):
+    def product_id_change_unit_price_inv(self, cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=None):
         tax_obj = self.pool.get('account.tax')
         if price_unit:
             taxes = tax_obj.browse(cr, uid, tax_id)
@@ -840,45 +948,23 @@ class account_invoice_line(osv.osv):
                 price_unit = price_unit - tax['amount']
         return {'price_unit': price_unit,'invoice_line_tax_id': tax_id}
 
-    def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, price_unit=False, address_invoice_id=False, context={}):
+    def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, context=None):
+        if context is None:
+            context = {}
         if not partner_id:
             raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") )
         if not product:
             if type in ('in_invoice', 'in_refund'):
                 return {'domain':{'product_uom':[]}}
             else:
-                return {'value': {'price_unit': 0.0 }, 'domain':{'uos_id': []}}
-        lang=False
+                return {'value': {'price_unit': 0.0}, 'domain':{'product_uom':[]}}
+        part = self.pool.get('res.partner').browse(cr, uid, partner_id)
+        fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
+
+        lang=part.lang
         context.update({'lang': lang})
+        result = {}
         res = self.pool.get('product.product').browse(cr, uid, product, context=context)
-        taxep=None
-        lang=self.pool.get('res.partner').read(cr, uid, [partner_id])[0]['lang']
-        tax_obj = self.pool.get('account.tax')
-        if type in ('out_invoice', 'out_refund'):
-            taxep = self.pool.get('res.partner').browse(cr, uid, partner_id).property_account_tax
-            if not taxep or not taxep.id:
-                tax_id = map(lambda x: x.id, res.taxes_id)
-            else:
-                tax_id = [taxep.id]
-                for t in res.taxes_id:
-                    if not t.tax_group==taxep.tax_group:
-                        tax_id.append(t.id)
-        else:
-            taxep = self.pool.get('res.partner').browse(cr, uid, partner_id).property_account_supplier_tax
-            if not taxep or not taxep.id:
-                tax_id = map(lambda x: x.id, res.supplier_taxes_id)
-            else:
-                tax_id = [taxep.id]
-                for t in res.supplier_taxes_id:
-                    if not t.tax_group==taxep.tax_group:
-                        tax_id.append(t.id)
-        if type in ('in_invoice', 'in_refund'):
-            result = self.product_id_change_unit_price_inv(cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=context)
-        else:
-            result = {'price_unit': res.list_price, 'invoice_line_tax_id': tax_id}
-
-        if not name:
-            result['name'] = res.name
 
         if type in ('out_invoice','out_refund'):
             a =  res.product_tmpl_id.property_account_income.id
@@ -888,19 +974,37 @@ class account_invoice_line(osv.osv):
             a =  res.product_tmpl_id.property_account_expense.id
             if not a:
                 a = res.categ_id.property_account_expense_categ.id
+
+        a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
         if a:
             result['account_id'] = a
 
+        taxep=None
+        tax_obj = self.pool.get('account.tax')
+        if type in ('out_invoice', 'out_refund'):
+            taxes = res.taxes_id and res.taxes_id or (a and self.pool.get('account.account').browse(cr, uid,a).tax_ids or False)
+            tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
+        else:
+            taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid,a).tax_ids or False)
+            tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
+        if type in ('in_invoice', 'in_refund'):
+            to_update = self.product_id_change_unit_price_inv(cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=context)
+            result.update(to_update)
+        else:
+            result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
+
+        if not name:
+            result['name'] = res.name
+
         domain = {}
-        result['uos_id'] = res.uom_id.id or uom or False
+        result['uos_id'] = uom or res.uom_id.id or False
         if result['uos_id']:
             res2 = res.uom_id.category_id.id
             if res2 :
                 domain = {'uos_id':[('category_id','=',res2 )]}
-                result
         return {'value':result, 'domain':domain}
 
-    def move_line_get(self, cr, uid, invoice_id, context={}):
+    def move_line_get(self, cr, uid, invoice_id, context=None):
         res = []
         tax_grouped = {}
         tax_obj = self.pool.get('account.tax')
@@ -942,7 +1046,7 @@ class account_invoice_line(osv.osv):
                 res[-1]['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, tax_amount, context={'date': inv.date_invoice})
         return res
 
-    def move_line_get_item(self, cr, uid, line, context={}):
+    def move_line_get_item(self, cr, uid, line, context=None):
         return {
             'type':'src',
             'name': line.name[:64],
@@ -953,21 +1057,17 @@ class account_invoice_line(osv.osv):
             'product_id':line.product_id.id,
             'uos_id':line.uos_id.id,
             'account_analytic_id':line.account_analytic_id.id,
+            'taxes':line.invoice_line_tax_id,
         }
     #
-    # Set the tax field according to the account and the partner
+    # Set the tax field according to the account and the fiscal position
     #
-    def onchange_account_id(self, cr, uid, ids, partner_id,account_id):
-        if not (partner_id and account_id):
+    def onchange_account_id(self, cr, uid, ids, fposition_id, account_id):
+        if not account_id:
             return {}
         taxes = self.pool.get('account.account').browse(cr, uid, account_id).tax_ids
-        taxep = self.pool.get('res.partner').browse(cr, uid, partner_id).property_account_tax
-        if not taxep.id:
-            return {'value': {'invoice_line_tax_id': map(lambda x: x.id, taxes or []) }}
-        res = [taxep.id]
-        for t in taxes:
-            if not t.tax_group==taxep.tax_group:
-                res.append(t.id)
+        fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
+        res = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
         r = {'value':{'invoice_line_tax_id': res}}
         return r
 account_invoice_line()
@@ -984,9 +1084,9 @@ class account_invoice_tax(osv.osv):
         'manual': fields.boolean('Manual'),
         'sequence': fields.integer('Sequence'),
 
-        'base_code_id': fields.many2one('account.tax.code', 'Base Code'),
+        'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="The case of the tax declaration."),
         'base_amount': fields.float('Base Code Amount', digits=(16,2)),
-        'tax_code_id': fields.many2one('account.tax.code', 'Tax Code'),
+        'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="The case of the tax declaration."),
         'tax_amount': fields.float('Tax Code Amount', digits=(16,2)),
     }
     def base_change(self, cr, uid, ids, base):
@@ -1012,7 +1112,7 @@ class account_invoice_tax(osv.osv):
                 val={}
                 val['invoice_id'] = inv.id
                 val['name'] = tax['name']
-                val['amount'] = cur_obj.round(cr, uid, cur, tax['amount'])
+                val['amount'] = tax['amount']
                 val['manual'] = False
                 val['sequence'] = tax['sequence']
                 val['base'] = tax['price_unit'] * line['quantity']
@@ -1020,14 +1120,14 @@ class account_invoice_tax(osv.osv):
                 if inv.type in ('out_invoice','in_invoice'):
                     val['base_code_id'] = tax['base_code_id']
                     val['tax_code_id'] = tax['tax_code_id']
-                    val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice})
-                    val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice})
+                    val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
+                    val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
                     val['account_id'] = tax['account_collected_id'] or line.account_id.id
                 else:
                     val['base_code_id'] = tax['ref_base_code_id']
                     val['tax_code_id'] = tax['ref_tax_code_id']
-                    val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice})
-                    val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice})
+                    val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
+                    val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
                     val['account_id'] = tax['account_paid_id'] or line.account_id.id
 
                 key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
@@ -1039,11 +1139,13 @@ class account_invoice_tax(osv.osv):
                     tax_grouped[key]['base_amount'] += val['base_amount']
                     tax_grouped[key]['tax_amount'] += val['tax_amount']
 
+        for t in tax_grouped.values():
+            t['amount'] = cur_obj.round(cr, uid, cur, t['amount'])
         return tax_grouped
 
     def move_line_get(self, cr, uid, invoice_id):
         res = []
-        cr.execute('SELECT * FROM account_invoice_tax WHERE invoice_id=%d', (invoice_id,))
+        cr.execute('SELECT * FROM account_invoice_tax WHERE invoice_id=%s', (invoice_id,))
         for t in cr.dictfetchall():
             if not t['amount'] \
                     and not t['tax_code_id'] \