[FIX] bugfixed the incoming tax on onchange of product in supplier invoice and refund
[odoo/odoo.git] / addons / account / invoice.py
index 7f8f1bb..de343ee 100644 (file)
@@ -2,7 +2,7 @@
 ##############################################################################
 #
 #    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -30,8 +30,20 @@ from mx.DateTime import RelativeDateTime
 from tools import config
 from tools.translate import _
 
+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),
+    }
+
+fiscalyear_seq()
+
 class account_invoice(osv.osv):
-    def _amount_all(self, cr, uid, ids, name, args, context={}):
+    def _amount_all(self, cr, uid, ids, name, args, context=None):
         res = {}
         for invoice in self.browse(cr,uid,ids, context=context):
             res[invoice.id] = {
@@ -47,6 +59,8 @@ class account_invoice(osv.osv):
         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')
@@ -63,15 +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')
         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
 
@@ -84,15 +100,15 @@ class account_invoice(osv.osv):
     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):
@@ -113,19 +129,19 @@ class account_invoice(osv.osv):
                 res[id]=[x for x in l if x <> line.id]
         return res
 
-    def _get_invoice_line(self, cr, uid, ids, 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={}):
+    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={}):
+    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])
@@ -141,6 +157,32 @@ 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"
@@ -154,11 +196,11 @@ class account_invoice(osv.osv):
             ('in_refund','Supplier Refund'),
             ],'Type', readonly=True, select=True),
 
-        'number': fields.char('Invoice Number', size=32, readonly=True, help="Uniq number of the invoice, computed automatically when the invoice is created."),
+        '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'),
@@ -166,19 +208,21 @@ class account_invoice(osv.osv):
             ('proforma2','Pro-forma'),
             ('open','Open'),
             ('paid','Done'),
-            ('cancel','Canceled')
+            ('cancel','Cancelled')
         ],'State', select=True, 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)]}),
-
+        '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)]} ),
-
-        'period_id': fields.many2one('account.period', 'Force Period', 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)]},
+            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."),
 
         '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)]}),
@@ -211,7 +255,11 @@ class account_invoice(osv.osv):
         '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',
-            store=True, help="The account moves of the invoice have been reconciled with account moves of the payment(s)."),
+            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'),
@@ -220,10 +268,13 @@ class account_invoice(osv.osv):
                 '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,
@@ -237,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:
@@ -245,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):
@@ -259,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:
@@ -272,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
@@ -282,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
             }
         }
 
@@ -373,39 +426,20 @@ class account_invoice(osv.osv):
             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=%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
@@ -447,13 +481,11 @@ 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')
-        acc_obj = self.pool.get('account.account')
+
         for inv in self.browse(cr, uid, ids):
             if inv.move_id:
                 continue
-            self.button_compute(cr, uid, ids, context={},set_total=True)
-            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
@@ -483,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)
 
@@ -495,11 +530,7 @@ class account_invoice(osv.osv):
             # create one move line for the total and possibly adjust the other lines amount
             total = 0
             total_currency = 0
-            key_line=[]
             for i in iml:
-                if i.has_key('account_id') and i.has_key('taxes'):
-                    if not (i['account_id'],i['taxes']) in key_line:
-                        key_line.append((i['account_id'],i['taxes']))
                 if inv.currency_id.id != company_currency:
                     i['currency_id'] = inv.currency_id.id
                     i['amount_currency'] = i['price']
@@ -520,36 +551,6 @@ class account_invoice(osv.osv):
             acc_id = inv.account_id.id
 
             name = inv['name'] or '/'
-            iml_temp=[]
-            move_list=[]
-
-            for item in key_line:
-                move_temp={}
-                if acc_obj.browse(cr,uid,item[0]).merge_invoice:
-                    repeat=False
-                    for move_line in iml:
-                        if (move_line.has_key('account_id') and move_line['account_id']==item[0]) and (move_line.has_key('taxes') and move_line['taxes']==item[1]):
-                            move_list.append(move_line)
-                            if repeat:
-                                for key in move_line:
-                                    if key in ['name','amount_currency','price_unit','price','quantity']:
-                                        if key=='name':
-                                            move_temp[key]=move_temp[key] + "," +move_line[key]
-                                        else:
-                                            move_temp[key] +=move_line[key]
-                            else:
-                                for key in move_line:
-                                    move_temp[key]=move_line[key]
-                                repeat=True
-                if move_temp:
-                    iml_temp.append(move_temp)
-
-            if len(iml_temp)<len(move_list):
-                for old_elem in move_list:
-                    iml.remove(old_elem)
-                for new_elem in iml_temp:
-                    iml.append(new_elem)
-
             totlines = False
             if inv.payment_term:
                 totlines = self.pool.get('account.payment.term').compute(cr,
@@ -598,19 +599,35 @@ class account_invoice(osv.osv):
 
             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 and not inv.move_name:
-                name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
-            else:
-                name = inv.move_name
             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 or time.strftime('%Y-%m-%d')),('date_stop','>=',inv.date_invoice or time.strftime('%Y-%m-%d'))])
@@ -620,6 +637,7 @@ class account_invoice(osv.osv):
                 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
@@ -628,9 +646,8 @@ class account_invoice(osv.osv):
         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],
@@ -653,16 +670,24 @@ class account_invoice(osv.osv):
         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=%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=%s AND (ref is null OR ref = \'\')',
                         (ref, move_id))
@@ -717,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 = {
@@ -731,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:
@@ -809,49 +834,43 @@ class account_invoice(osv.osv):
             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 = []
@@ -859,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)
@@ -867,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()
 
@@ -877,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', {}):
@@ -916,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)
@@ -924,7 +948,9 @@ 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:
@@ -933,22 +959,12 @@ class account_invoice_line(osv.osv):
             else:
                 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
-        tax_obj = self.pool.get('account.tax')
-        if type in ('out_invoice', 'out_refund'):
-            tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, part, res.taxes_id)
-        else:
-            tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, part, res.supplier_taxes_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
@@ -959,10 +975,27 @@ class account_invoice_line(osv.osv):
             if not a:
                 a = res.categ_id.property_account_expense_categ.id
 
-        a = self.pool.get('account.fiscal.position').map_account(cr, uid, part, a)
+        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'] = uom or res.uom_id.id or False
         if result['uos_id']:
@@ -971,7 +1004,7 @@ class account_invoice_line(osv.osv):
                 domain = {'uos_id':[('category_id','=',res2 )]}
         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')
@@ -1013,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],
@@ -1027,15 +1060,14 @@ class account_invoice_line(osv.osv):
             '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
-        part = self.pool.get('res.partner').browse(cr, uid, partner_id)
-
-        res = self.pool.get('account.fiscal.position').map_tax(cr, uid, part, taxes)
+        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()