[IMP] rename invoice into account_invoice
authorAntony Lesuisse <al@openerp.com>
Sat, 1 Oct 2011 09:57:20 +0000 (11:57 +0200)
committerAntony Lesuisse <al@openerp.com>
Sat, 1 Oct 2011 09:57:20 +0000 (11:57 +0200)
bzr revid: al@openerp.com-20111001095720-h2prjp5due7rukir

addons/account/__init__.py
addons/account/account_invoice.py [new file with mode: 0644]
addons/account/invoice.py [deleted file]

index 1b64386..36cc1c8 100644 (file)
@@ -23,7 +23,7 @@ import account
 import installer
 import project
 import partner
-import invoice
+import account_invoice
 import account_bank_statement
 import account_bank
 import account_cash_statement
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
new file mode 100644 (file)
index 0000000..834da02
--- /dev/null
@@ -0,0 +1,1641 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import time
+from lxml import etree
+import decimal_precision as dp
+
+import netsvc
+import pooler
+from osv import fields, osv, orm
+from tools.translate import _
+
+class account_invoice(osv.osv):
+    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] = {
+                '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=None):
+        if context is None:
+            context = {}
+        type_inv = context.get('type', 'out_invoice')
+        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+        company_id = context.get('company_id', user.company_id.id)
+        type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale_refund', 'in_refund': 'purchase_refund'}
+        journal_obj = self.pool.get('account.journal')
+        res = journal_obj.search(cr, uid, [('type', '=', type2journal.get(type_inv, 'sale')),
+                                            ('company_id', '=', company_id)],
+                                                limit=1)
+        return res and res[0] or False
+
+    def _get_currency(self, cr, uid, context=None):
+        user = pooler.get_pool(cr.dbname).get('res.users').browse(cr, uid, [uid], context=context)[0]
+        if user.company_id:
+            return user.company_id.currency_id.id
+        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=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 must define an analytic journal of type '%s' !") % (tt,))
+        return result[0]
+
+    def _get_type(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        return context.get('type', 'out_invoice')
+
+    def _reconciled(self, cr, uid, ids, name, args, context=None):
+        res = {}
+        for id in ids:
+            res[id] = self.test_paid(cr, uid, [id])
+        return res
+
+    def _get_reference_type(self, cr, uid, context=None):
+        return [('none', _('Free Reference'))]
+
+    def _amount_residual(self, cr, uid, ids, name, args, context=None):
+        result = {}
+        for invoice in self.browse(cr, uid, ids, context=context):
+            result[invoice.id] = 0.0
+            if invoice.move_id:
+                for m in invoice.move_id.line_id:
+                    if m.account_id.type in ('receivable','payable'):
+                        result[invoice.id] += m.amount_residual_currency
+        return result
+
+    # Give Journal Items related to the payment reconciled to this invoice
+    # Return ids of partial and total payments related to the selected invoices
+    def _get_lines(self, cr, uid, ids, name, arg, context=None):
+        res = {}
+        for invoice in self.browse(cr, uid, ids, context=context):
+            id = invoice.id
+            res[id] = []
+            if not invoice.move_id:
+                continue
+            data_lines = [x for x in invoice.move_id.line_id if x.account_id.id == invoice.account_id.id]
+            partial_ids = []
+            for line in data_lines:
+                ids_line = []
+                if line.reconcile_id:
+                    ids_line = line.reconcile_id.line_id
+                elif line.reconcile_partial_id:
+                    ids_line = line.reconcile_partial_id.line_partial_ids
+                l = map(lambda x: x.id, ids_line)
+                partial_ids.append(line.id)
+                res[id] =[x for x in l if x <> line.id and x not in partial_ids]
+        return res
+
+    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=context):
+            src = []
+            lines = []
+            if invoice.move_id:
+                for m in invoice.move_id.line_id:
+                    temp_lines = []
+                    if m.reconcile_id:
+                        temp_lines = map(lambda x: x.id, m.reconcile_id.line_id)
+                    elif m.reconcile_partial_id:
+                        temp_lines = map(lambda x: x.id, m.reconcile_partial_id.line_partial_ids)
+                    lines += [x for x in temp_lines if x not in lines]
+                    src.append(m.id)
+
+            lines = filter(lambda x: x not in src, lines)
+            result[invoice.id] = lines
+        return result
+
+    def _get_invoice_from_line(self, cr, uid, ids, context=None):
+        move = {}
+        for line in self.pool.get('account.move.line').browse(cr, uid, ids, context=context):
+            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=None):
+        move = {}
+        for r in self.pool.get('account.move.reconcile').browse(cr, uid, ids, context=context):
+            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 = "id desc"
+
+    _columns = {
+        'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}),
+        'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}),
+        'type': fields.selection([
+            ('out_invoice','Customer Invoice'),
+            ('in_invoice','Supplier Invoice'),
+            ('out_refund','Customer Refund'),
+            ('in_refund','Supplier Refund'),
+            ],'Type', readonly=True, select=True, change_default=True),
+
+        'number': fields.related('move_id','name', type='char', readonly=True, size=64, relation='account.move', store=True, string='Number'),
+        'internal_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, readonly=True, states={'draft':[('readonly',False)]}),
+        'comment': fields.text('Additional Information'),
+
+        'state': fields.selection([
+            ('draft','Draft'),
+            ('proforma','Pro-forma'),
+            ('proforma2','Pro-forma'),
+            ('open','Open'),
+            ('paid','Paid'),
+            ('cancel','Cancelled')
+            ],'State', select=True, readonly=True,
+            help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \
+            \n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \
+            \n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \
+            \n* The \'Paid\' state is set automatically when invoice is paid.\
+            \n* The \'Cancelled\' state is used when user cancel invoice.'),
+        'date_invoice': fields.date('Invoice Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True, help="Keep empty to use the current date"),
+        'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=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. The payment term may compute several due dates, for example 50% now, 50% in one month."),
+        '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, for example 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(invoice) date.", 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', 'Journal Entry', readonly=True, select=1, ondelete='restrict', help="Link to the automatically generated Journal Items."),
+        'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Untaxed',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 20),
+            },
+            multi='all'),
+        'amount_tax': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Tax',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 20),
+            },
+            multi='all'),
+        'amount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
+                'account.invoice.tax': (_get_invoice_tax, None, 20),
+                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 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, change_default=True, readonly=True, states={'draft':[('readonly',False)]}),
+        'check_total': fields.float('Total', digits_compute=dp.get_precision('Account'), states={'open':[('readonly',True)],'close':[('readonly',True)]}),
+        'reconciled': fields.function(_reconciled, string='Paid/Reconciled', type='boolean',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
+                'account.move.line': (_get_invoice_from_line, None, 50),
+                'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
+            }, help="The Journal Entry of the invoice have been totally reconciled with one or several Journal Entries of payment."),
+        'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',
+            help='Bank Account Number, Company bank account if Invoice is customer or supplier refund, otherwise Partner bank account number.', readonly=True, states={'draft':[('readonly',False)]}),
+        'move_lines':fields.function(_get_lines, type='many2many', relation='account.move.line', string='Entry Lines'),
+        'residual': fields.function(_amount_residual, digits_compute=dp.get_precision('Account'), string='Residual',
+            store={
+                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line','move_id'], 50),
+                'account.invoice.tax': (_get_invoice_tax, None, 50),
+                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 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, relation='account.move.line', type="many2many", string='Payments'),
+        'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}),
+        'user_id': fields.many2one('res.users', 'Salesman', readonly=True, states={'draft':[('readonly',False)]}),
+        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]})
+    }
+    _defaults = {
+        'type': _get_type,
+        'state': 'draft',
+        'journal_id': _get_journal,
+        'currency_id': _get_currency,
+        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.invoice', context=c),
+        'reference_type': 'none',
+        'check_total': 0.0,
+        'internal_number': False,
+        'user_id': lambda s, cr, u, c: u,
+    }
+
+    def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
+        journal_obj = self.pool.get('account.journal')
+        if context is None:
+            context = {}
+
+        if context.get('active_model', '') in ['res.partner'] and context.get('active_ids', False) and context['active_ids']:
+            partner = self.pool.get(context['active_model']).read(cr, uid, context['active_ids'], ['supplier','customer'])[0]
+            if not view_type:
+                view_id = self.pool.get('ir.ui.view').search(cr, uid, [('name', '=', 'account.invoice.tree')])
+                view_type = 'tree'
+            if view_type == 'form':
+                if partner['supplier'] and not partner['customer']:
+                    view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.supplier.form')])
+                else:
+                    view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.form')])
+        if view_id and isinstance(view_id, (list, tuple)):
+            view_id = view_id[0]
+        res = super(account_invoice,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
+
+        type = context.get('journal_type', 'sale')
+        for field in res['fields']:
+            if field == 'journal_id':
+                journal_select = journal_obj._name_search(cr, uid, '', [('type', '=', type)], context=context, limit=None, name_get_uid=1)
+                res['fields'][field]['selection'] = journal_select
+
+        doc = etree.XML(res['arch'])
+        if view_type == 'search':
+            if context.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
+                for node in doc.xpath("//group[@name='extended filter']"):
+                    doc.remove(node)
+            res['arch'] = etree.tostring(doc)
+
+        if view_type == 'tree':
+            partner_string = _('Customer')
+            if context.get('type', 'out_invoice') in ('in_invoice', 'in_refund'):
+                partner_string = _('Supplier')
+                for node in doc.xpath("//field[@name='reference']"):
+                    node.set('invisible', '0')
+            for node in doc.xpath("//field[@name='partner_id']"):
+                node.set('string', partner_string)
+            res['arch'] = etree.tostring(doc)
+        return res
+
+    def get_log_context(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'invoice_form')
+        view_id = res and res[1] or False
+        context.update({'view_id': view_id})
+        return context
+
+    def create(self, cr, uid, vals, context=None):
+        if context is None:
+            context = {}
+        try:
+            res = super(account_invoice, self).create(cr, uid, vals, context)
+            for inv_id, name in self.name_get(cr, uid, [res], context=context):
+                ctx = context.copy()
+                if vals.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
+                    ctx = self.get_log_context(cr, uid, context=ctx)
+                message = _("Invoice '%s' is waiting for validation.") % name
+                self.log(cr, uid, inv_id, message, context=ctx)
+            return res
+        except Exception, e:
+            if '"journal_id" viol' in e.args[0]:
+                raise orm.except_orm(_('Configuration Error!'),
+                     _('There is no Accounting Journal of type Sale/Purchase defined!'))
+            else:
+                raise orm.except_orm(_('Unknown Error'), str(e))
+
+    def confirm_paid(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        self.write(cr, uid, ids, {'state':'paid'}, context=context)
+        for inv_id, name in self.name_get(cr, uid, ids, context=context):
+            message = _("Invoice '%s' is paid.") % name
+            self.log(cr, uid, inv_id, message)
+        return True
+
+    def unlink(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        invoices = self.read(cr, uid, ids, ['state','internal_number'], context=context)
+        unlink_ids = []
+        for t in invoices:
+            if t['state'] in ('draft', 'cancel') and t['internal_number']== False:
+                unlink_ids.append(t['id'])
+            else:
+                raise osv.except_osv(_('Invalid action !'), _('You can not delete an invoice which is open or paid. We suggest you to refund it instead.'))
+        osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
+        return True
+
+    def onchange_partner_id(self, cr, uid, ids, type, partner_id,\
+            date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
+        invoice_addr_id = False
+        contact_addr_id = False
+        partner_payment_term = False
+        acc_id = False
+        bank_id = False
+        fiscal_position = False
+
+        opt = [('uid', str(uid))]
+        if partner_id:
+
+            opt.insert(0, ('id', partner_id))
+            res = self.pool.get('res.partner').address_get(cr, uid, [partner_id], ['contact', 'invoice'])
+            contact_addr_id = res['contact']
+            invoice_addr_id = res['invoice']
+            p = self.pool.get('res.partner').browse(cr, uid, partner_id)
+            if company_id:
+                if p.property_account_receivable.company_id.id != company_id and p.property_account_payable.company_id.id != company_id:
+                    property_obj = self.pool.get('ir.property')
+                    rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
+                    pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
+                    if not rec_pro_id:
+                        rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('company_id','=',company_id)])
+                    if not pay_pro_id:
+                        pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('company_id','=',company_id)])
+                    rec_line_data = property_obj.read(cr,uid,rec_pro_id,['name','value_reference','res_id'])
+                    pay_line_data = property_obj.read(cr,uid,pay_pro_id,['name','value_reference','res_id'])
+                    rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
+                    pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
+                    if not rec_res_id and not pay_res_id:
+                        raise osv.except_osv(_('Configuration Error !'),
+                            _('Can not find account chart for this company, Please Create account.'))
+                    account_obj = self.pool.get('account.account')
+                    rec_obj_acc = account_obj.browse(cr, uid, [rec_res_id])
+                    pay_obj_acc = account_obj.browse(cr, uid, [pay_res_id])
+                    p.property_account_receivable = rec_obj_acc[0]
+                    p.property_account_payable = pay_obj_acc[0]
+
+            if type in ('out_invoice', 'out_refund'):
+                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
+
+        result = {'value': {
+            'address_contact_id': contact_addr_id,
+            'address_invoice_id': invoice_addr_id,
+            'account_id': acc_id,
+            'payment_term': partner_payment_term,
+            'fiscal_position': fiscal_position
+            }
+        }
+
+        if type in ('in_invoice', 'in_refund'):
+            result['value']['partner_bank_id'] = bank_id
+
+        if payment_term != partner_payment_term:
+            if partner_payment_term:
+                to_update = self.onchange_payment_term_date_invoice(
+                    cr, uid, ids, partner_payment_term, date_invoice)
+                result['value'].update(to_update['value'])
+            else:
+                result['value']['date_due'] = False
+
+        if partner_bank_id != bank_id:
+            to_update = self.onchange_partner_bank(cr, uid, ids, bank_id)
+            result['value'].update(to_update['value'])
+        return result
+
+    def onchange_journal_id(self, cr, uid, ids, journal_id=False):
+        result = {}
+        if journal_id:
+            journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
+            currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id
+            result = {'value': {
+                    'currency_id': currency_id,
+                    }
+                }
+        return result
+
+    def onchange_payment_term_date_invoice(self, cr, uid, ids, payment_term_id, date_invoice):
+        if not payment_term_id:
+            return {}
+        res = {}
+        pt_obj = self.pool.get('account.payment.term')
+        if not date_invoice:
+            date_invoice = time.strftime('%Y-%m-%d')
+
+        pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
+
+        if pterm_list:
+            pterm_list = [line[0] for line in pterm_list]
+            pterm_list.sort()
+            res = {'value':{'date_due': pterm_list[-1]}}
+        else:
+             raise osv.except_osv(_('Data Insufficient !'), _('The Payment Term of Supplier does not have Payment Term Lines(Computation) defined !'))
+        return res
+
+    def onchange_invoice_line(self, cr, uid, ids, lines):
+        return {}
+
+    def onchange_partner_bank(self, cursor, user, ids, partner_bank_id=False):
+        return {'value': {}}
+
+    def onchange_company_id(self, cr, uid, ids, company_id, part_id, type, invoice_line, currency_id):
+        val = {}
+        dom = {}
+        obj_journal = self.pool.get('account.journal')
+        account_obj = self.pool.get('account.account')
+        inv_line_obj = self.pool.get('account.invoice.line')
+        if company_id and part_id and type:
+            acc_id = False
+            partner_obj = self.pool.get('res.partner').browse(cr,uid,part_id)
+            if partner_obj.property_account_payable and partner_obj.property_account_receivable:
+                if partner_obj.property_account_payable.company_id.id != company_id and partner_obj.property_account_receivable.company_id.id != company_id:
+                    property_obj = self.pool.get('ir.property')
+                    rec_pro_id = property_obj.search(cr, uid, [('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
+                    pay_pro_id = property_obj.search(cr, uid, [('name','=','property_account_payable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
+                    if not rec_pro_id:
+                        rec_pro_id = property_obj.search(cr, uid, [('name','=','property_account_receivable'),('company_id','=',company_id)])
+                    if not pay_pro_id:
+                        pay_pro_id = property_obj.search(cr, uid, [('name','=','property_account_payable'),('company_id','=',company_id)])
+                    rec_line_data = property_obj.read(cr, uid, rec_pro_id, ['name','value_reference','res_id'])
+                    pay_line_data = property_obj.read(cr, uid, pay_pro_id, ['name','value_reference','res_id'])
+                    rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
+                    pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
+                    if not rec_res_id and not pay_res_id:
+                        raise osv.except_osv(_('Configuration Error !'),
+                            _('Can not find account chart for this company, Please Create account.'))
+                    if type in ('out_invoice', 'out_refund'):
+                        acc_id = rec_res_id
+                    else:
+                        acc_id = pay_res_id
+                    val= {'account_id': acc_id}
+            if ids:
+                if company_id:
+                    inv_obj = self.browse(cr,uid,ids)
+                    for line in inv_obj[0].invoice_line:
+                        if line.account_id:
+                            if line.account_id.company_id.id != company_id:
+                                result_id = account_obj.search(cr, uid, [('name','=',line.account_id.name),('company_id','=',company_id)])
+                                if not result_id:
+                                    raise osv.except_osv(_('Configuration Error !'),
+                                        _('Can not find account chart for this company in invoice line account, Please Create account.'))
+                                inv_line_obj.write(cr, uid, [line.id], {'account_id': result_id[-1]})
+            else:
+                if invoice_line:
+                    for inv_line in invoice_line:
+                        obj_l = account_obj.browse(cr, uid, inv_line[2]['account_id'])
+                        if obj_l.company_id.id != company_id:
+                            raise osv.except_osv(_('Configuration Error !'),
+                                _('Invoice line account company does not match with invoice company.'))
+                        else:
+                            continue
+        if company_id and type:
+            if type in ('out_invoice'):
+                journal_type = 'sale'
+            elif type in ('out_refund'):
+                journal_type = 'sale_refund'
+            elif type in ('in_refund'):
+                journal_type = 'purchase_refund'
+            else:
+                journal_type = 'purchase'
+            journal_ids = obj_journal.search(cr, uid, [('company_id','=',company_id), ('type', '=', journal_type)])
+            if journal_ids:
+                val['journal_id'] = journal_ids[0]
+            ir_values_obj = self.pool.get('ir.values')
+            res_journal_default = ir_values_obj.get(cr, uid, 'default', 'type=%s' % (type), ['account.invoice'])
+            for r in res_journal_default:
+                if r[1] == 'journal_id' and r[2] in journal_ids:
+                    val['journal_id'] = r[2]
+            if not val.get('journal_id', False):
+                raise osv.except_osv(_('Configuration Error !'), (_('Can\'t find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Financial Accounting\Accounts\Journals.') % (journal_type)))
+            dom = {'journal_id':  [('id', 'in', journal_ids)]}
+        else:
+            journal_ids = obj_journal.search(cr, uid, [])
+
+        if currency_id and company_id:
+            currency = self.pool.get('res.currency').browse(cr, uid, currency_id)
+            if currency.company_id and currency.company_id.id != company_id:
+                val['currency_id'] = False
+            else:
+                val['currency_id'] = currency.id
+        if company_id:
+            company = self.pool.get('res.company').browse(cr, uid, company_id)
+            if company.currency_id.company_id and company.currency_id.company_id.id != company_id:
+                val['currency_id'] = False
+            else:
+                val['currency_id'] = company.currency_id.id
+        return {'value': val, 'domain': dom}
+
+    # go from canceled state to draft state
+    def action_cancel_draft(self, cr, uid, ids, *args):
+        self.write(cr, uid, ids, {'state':'draft'})
+        wf_service = netsvc.LocalService("workflow")
+        for inv_id in ids:
+            wf_service.trg_delete(uid, 'account.invoice', inv_id, cr)
+            wf_service.trg_create(uid, 'account.invoice', inv_id, cr)
+        return True
+
+    # Workflow stuff
+    #################
+
+    # return the ids of the move lines which has the same account than the invoice
+    # whose id is in ids
+    def move_line_id_payment_get(self, cr, uid, ids, *args):
+        if not ids: return []
+        result = self.move_line_id_payment_gets(cr, uid, ids, *args)
+        return result.get(ids[0], [])
+
+    def move_line_id_payment_gets(self, cr, uid, ids, *args):
+        res = {}
+        if not ids: return res
+        cr.execute('SELECT i.id, l.id '\
+                   'FROM account_move_line l '\
+                   'LEFT JOIN account_invoice i ON (i.move_id=l.move_id) '\
+                   'WHERE i.id IN %s '\
+                   'AND l.account_id=i.account_id',
+                   (tuple(ids),))
+        for r in cr.fetchall():
+            res.setdefault(r[0], [])
+            res[r[0]].append( r[1] )
+        return res
+
+    def copy(self, cr, uid, id, default={}, context=None):
+        if context is None:
+            context = {}
+        default.update({
+            'state':'draft',
+            'number':False,
+            'move_id':False,
+            'move_name':False,
+            'internal_number': False,
+        })
+        if 'date_invoice' not in default:
+            default.update({
+                'date_invoice':False
+            })
+        if 'date_due' not in default:
+            default.update({
+                'date_due':False
+            })
+        return super(account_invoice, self).copy(cr, uid, id, default, context)
+
+    def test_paid(self, cr, uid, ids, *args):
+        res = self.move_line_id_payment_get(cr, uid, ids)
+        if not res:
+            return False
+        ok = True
+        for id in res:
+            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=None):
+        if context is None:
+            context = {}
+        ctx = context.copy()
+        ait_obj = self.pool.get('account.invoice.tax')
+        for id in ids:
+            cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%s AND manual is False", (id,))
+            partner = self.browse(cr, uid, id, context=ctx).partner_id
+            if partner.lang:
+                ctx.update({'lang': partner.lang})
+            for taxe in ait_obj.compute(cr, uid, id, context=ctx).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, {'invoice_line':[]}, context=ctx)
+        return True
+
+    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, context=context):
+            if set_total:
+                self.pool.get('account.invoice').write(cr, uid, [inv.id], {'check_total': inv.amount_total})
+        return True
+
+    def _convert_ref(self, cr, uid, ref):
+        return (ref or '').replace('/','')
+
+    def _get_analytic_lines(self, cr, uid, id, context=None):
+        if context is None:
+            context = {}
+        inv = self.browse(cr, uid, id)
+        cur_obj = self.pool.get('res.currency')
+
+        company_currency = inv.company_id.currency_id.id
+        if inv.type in ('out_invoice', 'in_refund'):
+            sign = 1
+        else:
+            sign = -1
+
+        iml = self.pool.get('account.invoice.line').move_line_get(cr, uid, inv.id, context=context)
+        for il in iml:
+            if il['account_analytic_id']:
+                if inv.type in ('in_invoice', 'in_refund'):
+                    ref = inv.reference
+                else:
+                    ref = self._convert_ref(cr, uid, inv.number)
+                if not inv.journal_id.analytic_journal_id:
+                    raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,))
+                il['analytic_lines'] = [(0,0, {
+                    'name': il['name'],
+                    'date': inv['date_invoice'],
+                    'account_id': il['account_analytic_id'],
+                    'unit_amount': il['quantity'],
+                    'amount': cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, il['price'], context={'date': inv.date_invoice}) * sign,
+                    'product_id': il['product_id'],
+                    'product_uom_id': il['uos_id'],
+                    'general_account_id': il['account_id'],
+                    'journal_id': inv.journal_id.analytic_journal_id.id,
+                    'ref': ref,
+                })]
+        return iml
+
+    def action_date_assign(self, cr, uid, ids, *args):
+        for inv in self.browse(cr, uid, ids):
+            res = self.onchange_payment_term_date_invoice(cr, uid, inv.id, inv.payment_term.id, inv.date_invoice)
+            if res and res['value']:
+                self.write(cr, uid, [inv.id], res['value'])
+        return True
+
+    def finalize_invoice_move_lines(self, cr, uid, invoice_browse, move_lines):
+        """finalize_invoice_move_lines(cr, uid, invoice, move_lines) -> move_lines
+        Hook method to be overridden in additional modules to verify and possibly alter the
+        move lines to be created by an invoice, for special cases.
+        :param invoice_browse: browsable record of the invoice that is generating the move lines
+        :param move_lines: list of dictionaries with the account.move.lines (as for create())
+        :return: the (possibly updated) final move_lines to create for this invoice
+        """
+        return move_lines
+
+    def check_tax_lines(self, cr, uid, inv, compute_taxes, ait_obj):
+        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:
+                    raise osv.except_osv(_('Warning !'), _('Global taxes defined, but are not in invoice lines !'))
+                base = compute_taxes[key]['base']
+                if abs(base - tax.base) > inv.company_id.currency_id.rounding:
+                    raise osv.except_osv(_('Warning !'), _('Tax base different !\nClick on compute to update tax base'))
+            for key in compute_taxes:
+                if not key in tax_key:
+                    raise osv.except_osv(_('Warning !'), _('Taxes missing !'))
+
+    def compute_invoice_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines):
+        total = 0
+        total_currency = 0
+        cur_obj = self.pool.get('res.currency')
+        for i in invoice_move_lines:
+            if inv.currency_id.id != company_currency:
+                i['currency_id'] = inv.currency_id.id
+                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 or time.strftime('%Y-%m-%d')})
+            else:
+                i['amount_currency'] = False
+                i['currency_id'] = False
+            i['ref'] = ref
+            if inv.type in ('out_invoice','in_refund'):
+                total += i['price']
+                total_currency += i['amount_currency'] or i['price']
+                i['price'] = - i['price']
+            else:
+                total -= i['price']
+                total_currency -= i['amount_currency'] or i['price']
+        return total, total_currency, invoice_move_lines
+
+    def inv_line_characteristic_hashcode(self, invoice, invoice_line):
+        """Overridable hashcode generation for invoice lines. Lines having the same hashcode
+        will be grouped together if the journal has the 'group line' option. Of course a module
+        can add fields to invoice lines that would need to be tested too before merging lines
+        or not."""
+        return "%s-%s-%s-%s-%s"%(
+            invoice_line['account_id'],
+            invoice_line.get('tax_code_id',"False"),
+            invoice_line.get('product_id',"False"),
+            invoice_line.get('analytic_account_id',"False"),
+            invoice_line.get('date_maturity',"False"))
+
+    def group_lines(self, cr, uid, iml, line, inv):
+        """Merge account move lines (and hence analytic lines) if invoice line hashcodes are equals"""
+        if inv.journal_id.group_invoice_lines:
+            line2 = {}
+            for x, y, l in line:
+                tmp = self.inv_line_characteristic_hashcode(inv, l)
+
+                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))
+        return line
+
+    def action_move_create(self, cr, uid, ids, *args):
+        """Creates invoice related analytics and financial move lines"""
+        ait_obj = self.pool.get('account.invoice.tax')
+        cur_obj = self.pool.get('res.currency')
+        context = {}
+        for inv in self.browse(cr, uid, ids):
+            if not inv.journal_id.sequence_id:
+                raise osv.except_osv(_('Error !'), _('Please define sequence on invoice journal'))
+            if not inv.invoice_line:
+                raise osv.except_osv(_('No Invoice Lines !'), _('Please create some invoice lines.'))
+            if inv.move_id:
+                continue
+
+            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
+            # one move line per invoice line
+            iml = self._get_analytic_lines(cr, uid, inv.id)
+            # check if taxes are all computed
+            ctx = context.copy()
+            ctx.update({'lang': inv.partner_id.lang})
+            compute_taxes = ait_obj.compute(cr, uid, inv.id, context=ctx)
+            self.check_tax_lines(cr, uid, inv, compute_taxes, ait_obj)
+
+            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 inv.payment_term:
+                total_fixed = total_percent = 0
+                for line in inv.payment_term.line_ids:
+                    if line.value == 'fixed':
+                        total_fixed += line.value_amount
+                    if line.value == 'procent':
+                        total_percent += line.value_amount
+                total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0)
+                if (total_fixed + total_percent) > 100:
+                    raise osv.except_osv(_('Error !'), _("Can not create the invoice !\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount."))
+
+            # one move line per tax line
+            iml += ait_obj.move_line_get(cr, uid, inv.id)
+
+            entry_type = ''
+            if inv.type in ('in_invoice', 'in_refund'):
+                ref = inv.reference
+                entry_type = 'journal_pur_voucher'
+                if inv.type == 'in_refund':
+                    entry_type = 'cont_voucher'
+            else:
+                ref = self._convert_ref(cr, uid, inv.number)
+                entry_type = 'journal_sale_vou'
+                if inv.type == 'out_refund':
+                    entry_type = 'cont_voucher'
+
+            diff_currency_p = inv.currency_id.id <> company_currency
+            # create one move line for the total and possibly adjust the other lines amount
+            total = 0
+            total_currency = 0
+            total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml)
+            acc_id = inv.account_id.id
+
+            name = inv['name'] or '/'
+            totlines = False
+            if inv.payment_term:
+                totlines = self.pool.get('account.payment.term').compute(cr,
+                        uid, inv.payment_term.id, total, inv.date_invoice or False)
+            if totlines:
+                res_amount_currency = total_currency
+                i = 0
+                ctx.update({'date': inv.date_invoice})
+                for t in totlines:
+                    if inv.currency_id.id != company_currency:
+                        amount_currency = cur_obj.compute(cr, uid, company_currency, inv.currency_id.id, t[1], context=ctx)
+                    else:
+                        amount_currency = False
+
+                    # last line add the diff
+                    res_amount_currency -= amount_currency or 0
+                    i += 1
+                    if i == len(totlines):
+                        amount_currency += res_amount_currency
+
+                    iml.append({
+                        'type': 'dest',
+                        'name': name,
+                        'price': t[1],
+                        'account_id': acc_id,
+                        'date_maturity': t[0],
+                        'amount_currency': diff_currency_p \
+                                and  amount_currency or False,
+                        'currency_id': diff_currency_p \
+                                and inv.currency_id.id or False,
+                        'ref': ref,
+                    })
+            else:
+                iml.append({
+                    'type': 'dest',
+                    'name': name,
+                    'price': total,
+                    'account_id': acc_id,
+                    'date_maturity': inv.date_due or False,
+                    'amount_currency': diff_currency_p \
+                            and total_currency or False,
+                    'currency_id': diff_currency_p \
+                            and inv.currency_id.id or False,
+                    'ref': ref
+            })
+
+            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)
+
+            line = self.group_lines(cr, uid, iml, line, inv)
+
+            journal_id = inv.journal_id.id
+            journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
+            if journal.centralisation:
+                raise osv.except_osv(_('UserError'),
+                        _('You cannot create an invoice on a centralised journal. Uncheck the centralised counterpart box in the related journal from the configuration menu.'))
+
+            line = self.finalize_invoice_move_lines(cr, uid, inv, line)
+
+            move = {
+                'ref': inv.reference and inv.reference or inv.name,
+                'line_id': line,
+                'journal_id': journal_id,
+                'date': date,
+                'type': entry_type,
+                'narration':inv.comment
+            }
+            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')), ('company_id', '=', inv.company_id.id)])
+                if 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, context=context)
+            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, 'move_name':new_move_name})
+            # Pass invoice in context in method post: used if you want to get the same
+            # account move reference when creating the same invoice after a cancelled one:
+            self.pool.get('account.move').post(cr, uid, [move_id], context={'invoice':inv})
+        self._log_event(cr, uid, ids)
+        return True
+
+    def line_get_convert(self, cr, uid, x, part, date, context=None):
+        return {
+            'date_maturity': x.get('date_maturity', False),
+            'partner_id': part,
+            'name': x['name'][:64],
+            'date': date,
+            'debit': x['price']>0 and x['price'],
+            'credit': x['price']<0 and -x['price'],
+            'account_id': x['account_id'],
+            'analytic_lines': x.get('analytic_lines', []),
+            'amount_currency': x['price']>0 and abs(x.get('amount_currency', False)) or -abs(x.get('amount_currency', False)),
+            '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),
+            '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, context=None):
+        if context is None:
+            context = {}
+        #TODO: not correct fix but required a frech values before reading it.
+        self.write(cr, uid, ids, {})
+
+        for obj_inv in self.browse(cr, uid, ids, context=context):
+            id = obj_inv.id
+            invtype = obj_inv.type
+            number = obj_inv.number
+            move_id = obj_inv.move_id and obj_inv.move_id.id or False
+            reference = obj_inv.reference or ''
+
+            self.write(cr, uid, ids, {'internal_number':number})
+
+            if invtype in ('in_invoice', 'in_refund'):
+                if not reference:
+                    ref = self._convert_ref(cr, uid, number)
+                else:
+                    ref = reference
+            else:
+                ref = self._convert_ref(cr, uid, number)
+
+            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))
+            cr.execute('UPDATE account_analytic_line SET ref=%s ' \
+                    'FROM account_move_line ' \
+                    'WHERE account_move_line.move_id = %s ' \
+                        'AND account_analytic_line.move_id = account_move_line.id',
+                        (ref, move_id))
+
+            for inv_id, name in self.name_get(cr, uid, [id]):
+                ctx = context.copy()
+                if obj_inv.type in ('out_invoice', 'out_refund'):
+                    ctx = self.get_log_context(cr, uid, context=ctx)
+                message = _("Invoice  '%s' is validated.") % name
+                self.log(cr, uid, inv_id, message, context=ctx)
+        return True
+
+    def action_cancel(self, cr, uid, ids, *args):
+        context = {} # TODO: Use context from arguments
+        account_move_obj = self.pool.get('account.move')
+        invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids'])
+        move_ids = [] # ones that we will need to remove
+        for i in invoices:
+            if i['move_id']:
+                move_ids.append(i['move_id'][0])
+            if i['payment_ids']:
+                account_move_line_obj = self.pool.get('account.move.line')
+                pay_ids = account_move_line_obj.browse(cr, uid, i['payment_ids'])
+                for move_line in pay_ids:
+                    if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids:
+                        raise osv.except_osv(_('Error !'), _('You can not cancel an invoice which is partially paid! You need to unreconcile related payment entries first!'))
+
+        # First, set the invoices as cancelled and detach the move ids
+        self.write(cr, uid, ids, {'state':'cancel', 'move_id':False})
+        if move_ids:
+            # second, invalidate the move(s)
+            account_move_obj.button_cancel(cr, uid, move_ids, context=context)
+            # delete the move this invoice was pointing to
+            # Note that the corresponding move_lines and move_reconciles
+            # will be automatically deleted too
+            account_move_obj.unlink(cr, uid, move_ids, context=context)
+        self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice')
+        return True
+
+    ###################
+
+    def list_distinct_taxes(self, cr, uid, ids):
+        invoices = self.browse(cr, uid, ids)
+        taxes = {}
+        for inv in invoices:
+            for tax in inv.tax_line:
+                if not tax['name'] in taxes:
+                    taxes[tax['name']] = {'name': tax['name']}
+        return taxes.values()
+
+    def _log_event(self, cr, uid, ids, factor=1.0, name='Open Invoice'):
+        #TODO: implement messages system
+        return True
+
+    def name_get(self, cr, uid, ids, context=None):
+        if not ids:
+            return []
+        types = {
+                'out_invoice': 'CI: ',
+                'in_invoice': 'SI: ',
+                'out_refund': 'OR: ',
+                'in_refund': 'SR: ',
+                }
+        return [(r['id'], (r['number']) or types[r['type']] + (r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
+
+    def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
+        if not args:
+            args = []
+        if context is None:
+            context = {}
+        ids = []
+        if name:
+            ids = self.search(cr, user, [('number','=',name)] + args, limit=limit, context=context)
+        if not ids:
+            ids = self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context)
+        return self.name_get(cr, user, ids, context)
+
+    def _refund_cleanup_lines(self, cr, uid, lines):
+        for line in lines:
+            del line['id']
+            del line['invoice_id']
+            for field in ('company_id', 'partner_id', 'account_id', 'product_id',
+                          'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id'):
+                line[field] = line.get(field, False) and line[field][0]
+            if 'invoice_line_tax_id' in line:
+                line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ]
+        return map(lambda x: (0,0,x), lines)
+
+    def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=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'])
+        obj_invoice_line = self.pool.get('account.invoice.line')
+        obj_invoice_tax = self.pool.get('account.invoice.tax')
+        obj_journal = self.pool.get('account.journal')
+        new_ids = []
+        for invoice in invoices:
+            del invoice['id']
+
+            type_dict = {
+                'out_invoice': 'out_refund', # Customer Invoice
+                'in_invoice': 'in_refund',   # Supplier Invoice
+                'out_refund': 'out_invoice', # Customer Refund
+                'in_refund': 'in_invoice',   # Supplier Refund
+            }
+
+            invoice_lines = obj_invoice_line.read(cr, uid, invoice['invoice_line'])
+            invoice_lines = self._refund_cleanup_lines(cr, uid, invoice_lines)
+
+            tax_lines = obj_invoice_tax.read(cr, uid, invoice['tax_line'])
+            tax_lines = filter(lambda l: l['manual'], tax_lines)
+            tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines)
+            if journal_id:
+                refund_journal_ids = [journal_id]
+            elif invoice['type'] == 'in_invoice':
+                refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')])
+            else:
+                refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')])
+
+            if not date:
+                date = time.strftime('%Y-%m-%d')
+            invoice.update({
+                'type': type_dict[invoice['type']],
+                'date_invoice': date,
+                'state': 'draft',
+                'number': False,
+                'invoice_line': invoice_lines,
+                'tax_line': tax_lines,
+                'journal_id': refund_journal_ids
+            })
+            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=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], context=context)
+        src_account_id = invoice.account_id.id
+        # Take the seq as name for move
+        types = {'out_invoice': -1, 'in_invoice': 1, 'out_refund': 1, 'in_refund': -1}
+        direction = types[invoice.type]
+        #take the choosen date
+        if 'date_p' in context and context['date_p']:
+            date=context['date_p']
+        else:
+            date=time.strftime('%Y-%m-%d')
+
+        # Take the amount in currency and the currency of the payment
+        if 'amount_currency' in context and context['amount_currency'] and 'currency_id' in context and context['currency_id']:
+            amount_currency = context['amount_currency']
+            currency_id = context['currency_id']
+        else:
+            amount_currency = False
+            currency_id = False
+
+        pay_journal = self.pool.get('account.journal').read(cr, uid, pay_journal_id, ['type'], context=context)
+        if invoice.type in ('in_invoice', 'out_invoice'):
+            if pay_journal['type'] == 'bank':
+                entry_type = 'bank_pay_voucher' # Bank payment
+            else:
+                entry_type = 'pay_voucher' # Cash payment
+        else:
+            entry_type = 'cont_voucher'
+        if invoice.type in ('in_invoice', 'in_refund'):
+            ref = invoice.reference
+        else:
+            ref = self._convert_ref(cr, uid, invoice.number)
+        # Pay attention to the sign for both debit/credit AND amount_currency
+        l1 = {
+            '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,
+            'ref':ref,
+            'date': date,
+            'currency_id':currency_id,
+            'amount_currency':amount_currency and direction * amount_currency or 0.0,
+            'company_id': invoice.company_id.id,
+        }
+        l2 = {
+            '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,
+            'ref':ref,
+            'date': date,
+            'currency_id':currency_id,
+            'amount_currency':amount_currency and - direction * amount_currency or 0.0,
+            'company_id': invoice.company_id.id,
+        }
+
+        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 = {'ref': ref, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date, 'type': entry_type}
+        move_id = self.pool.get('account.move').create(cr, uid, move, context=context)
+
+        line_ids = []
+        total = 0.0
+        line = self.pool.get('account.move.line')
+        move_ids = [move_id,]
+        if invoice.move_id:
+            move_ids.append(invoice.move_id.id)
+        cr.execute('SELECT id FROM account_move_line '\
+                   'WHERE move_id IN %s',
+                   ((move_id, invoice.move_id.id),))
+        lines = line.browse(cr, uid, map(lambda x: x[0], cr.fetchall()) )
+        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)
+
+        inv_id, name = self.name_get(cr, uid, [invoice.id], context=context)[0]
+        if (not round(total,self.pool.get('decimal.precision').precision_get(cr, uid, 'Account'))) or writeoff_acc_id:
+            self.pool.get('account.move.line').reconcile(cr, uid, line_ids, 'manual', writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context)
+        else:
+            code = invoice.currency_id.symbol
+            # TODO: use currency's formatting function
+            msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining)") % \
+                    (name, pay_amount, code, invoice.amount_total, code, total, code)
+            self.log(cr, uid, inv_id,  msg)
+            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()
+
+class account_invoice_line(osv.osv):
+
+    def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict):
+        res = {}
+        tax_obj = self.pool.get('account.tax')
+        cur_obj = self.pool.get('res.currency')
+        for line in self.browse(cr, uid, ids):
+            price = line.price_unit * (1-(line.discount or 0.0)/100.0)
+            taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, address_id=line.invoice_id.address_invoice_id, partner=line.invoice_id.partner_id)
+            res[line.id] = taxes['total']
+            if line.invoice_id:
+                cur = line.invoice_id.currency_id
+                res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
+        return res
+
+    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', {}):
+                if isinstance(l, (list, tuple)) and len(l) >= 3 and l[2]:
+                    tax_obj = self.pool.get('account.tax')
+                    p = l[2].get('price_unit', 0) * (1-l[2].get('discount', 0)/100.0)
+                    t = t - (p * l[2].get('quantity'))
+                    taxes = l[2].get('invoice_line_tax_id')
+                    if len(taxes[0]) >= 3 and taxes[0][2]:
+                        taxes = tax_obj.browse(cr, uid, list(taxes[0][2]))
+                        for tax in tax_obj.compute_all(cr, uid, taxes, p,l[2].get('quantity'), context.get('address_invoice_id', False), l[2].get('product_id', False), context.get('partner_id', False))['taxes']:
+                            t = t - tax['amount']
+            return t
+        return 0
+
+    _name = "account.invoice.line"
+    _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 Reference', ondelete='cascade', select=True),
+        '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')], help="The income or expense account related to the selected product."),
+        'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')),
+        'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float",
+            digits_compute= dp.get_precision('Account'), store=True),
+        'quantity': fields.float('Quantity', required=True),
+        'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Account')),
+        'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]),
+        'note': fields.text('Notes'),
+        'account_analytic_id':  fields.many2one('account.analytic.account', 'Analytic Account'),
+        'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
+        'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
+    }
+    _defaults = {
+        'quantity': 1,
+        'discount': 0.0,
+        'price_unit': _price_unit_default,
+    }
+
+    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
+        if context is None:
+            context = {}
+        res = super(account_invoice_line,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
+        if context.get('type', False):
+            doc = etree.XML(res['arch'])
+            for node in doc.xpath("//field[@name='product_id']"):
+                if context['type'] in ('in_invoice', 'in_refund'):
+                    node.set('domain', "[('purchase_ok', '=', True)]")
+                else:
+                    node.set('domain', "[('sale_ok', '=', True)]")
+            res['arch'] = etree.tostring(doc)
+        return res
+
+    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, currency_id=False, context=None, company_id=None):
+        if context is None:
+            context = {}
+        company_id = company_id if company_id != None else context.get('company_id',False)
+        context = dict(context)
+        context.update({'company_id': company_id})
+        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 {'value': {'categ_id': False}, 'domain':{'product_uom':[]}}
+            else:
+                return {'value': {'price_unit': 0.0, 'categ_id': False}, 'domain':{'product_uom':[]}}
+        part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
+        fpos_obj = self.pool.get('account.fiscal.position')
+        fpos = fposition_id and fpos_obj.browse(cr, uid, fposition_id, context=context) or False
+
+        if part.lang:
+            context.update({'lang': part.lang})
+        result = {}
+        res = self.pool.get('product.product').browse(cr, uid, product, context=context)
+
+        if type in ('out_invoice','out_refund'):
+            a = res.product_tmpl_id.property_account_income.id
+            if not a:
+                a = res.categ_id.property_account_income_categ.id
+        else:
+            a = res.product_tmpl_id.property_account_expense.id
+            if not a:
+                a = res.categ_id.property_account_expense_categ.id
+        a = fpos_obj.map_account(cr, uid, fpos, a)
+        if a:
+            result['account_id'] = a
+
+        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, context=context).tax_ids or False)
+        else:
+            taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False)
+        tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
+
+        if type in ('in_invoice', 'in_refund'):
+            result.update( {'price_unit': price_unit or res.standard_price,'invoice_line_tax_id': tax_id} )
+        else:
+            result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
+        result['name'] = res.partner_ref
+
+        domain = {}
+        result['uos_id'] = res.uom_id.id or uom or False
+        result['note'] = res.description
+        if result['uos_id']:
+            res2 = res.uom_id.category_id.id
+            if res2:
+                domain = {'uos_id':[('category_id','=',res2 )]}
+
+        result['categ_id'] = res.categ_id.id
+        res_final = {'value':result, 'domain':domain}
+
+        if not company_id or not currency_id:
+            return res_final
+
+        company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
+        currency = self.pool.get('res.currency').browse(cr, uid, currency_id, context=context)
+
+        if company.currency_id.id != currency.id:
+            if type in ('in_invoice', 'in_refund'):
+                res_final['value']['price_unit'] = res.standard_price
+            new_price = res_final['value']['price_unit'] * currency.rate
+            res_final['value']['price_unit'] = new_price
+
+        if uom:
+            uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context)
+            if res.uom_id.category_id.id == uom.category_id.id:
+                new_price = res_final['value']['price_unit'] * uom.factor_inv
+                res_final['value']['price_unit'] = new_price
+        return res_final
+
+    def uos_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, currency_id=False, context=None, company_id=None):
+        if context is None:
+            context = {}
+        company_id = company_id if company_id != None else context.get('company_id',False)
+        context = dict(context)
+        context.update({'company_id': company_id})
+        warning = {}
+        res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context=context)
+        if 'uos_id' in res['value']:
+            del res['value']['uos_id']
+        if not uom:
+            res['value']['price_unit'] = 0.0
+        if product and uom:
+            prod = self.pool.get('product.product').browse(cr, uid, product, context=context)
+            prod_uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context)
+            if prod.uom_id.category_id.id != prod_uom.category_id.id:
+                 warning = {
+                    'title': _('Warning!'),
+                    'message': _('You selected an Unit of Measure which is not compatible with the product.')
+            }
+            return {'value': res['value'], 'warning': warning}
+        return res
+
+    def move_line_get(self, cr, uid, invoice_id, context=None):
+        res = []
+        tax_obj = self.pool.get('account.tax')
+        cur_obj = self.pool.get('res.currency')
+        if context is None:
+            context = {}
+        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
+        company_currency = inv.company_id.currency_id.id
+
+        for line in inv.invoice_line:
+            mres = self.move_line_get_item(cr, uid, line, context)
+            if not mres:
+                continue
+            res.append(mres)
+            tax_code_found= False
+            for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id,
+                    (line.price_unit * (1.0 - (line['discount'] or 0.0) / 100.0)),
+                    line.quantity, inv.address_invoice_id.id, line.product_id,
+                    inv.partner_id)['taxes']:
+
+                if inv.type in ('out_invoice', 'in_invoice'):
+                    tax_code_id = tax['base_code_id']
+                    tax_amount = line.price_subtotal * tax['base_sign']
+                else:
+                    tax_code_id = tax['ref_base_code_id']
+                    tax_amount = line.price_subtotal * tax['ref_base_sign']
+
+                if tax_code_found:
+                    if not tax_code_id:
+                        continue
+                    res.append(self.move_line_get_item(cr, uid, line, context))
+                    res[-1]['price'] = 0.0
+                    res[-1]['account_analytic_id'] = False
+                elif not tax_code_id:
+                    continue
+                tax_code_found = True
+
+                res[-1]['tax_code_id'] = tax_code_id
+                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=None):
+        return {
+            'type':'src',
+            'name': line.name[:64],
+            'price_unit':line.price_unit,
+            'quantity':line.quantity,
+            'price':line.price_subtotal,
+            'account_id':line.account_id.id,
+            '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 fiscal position
+    #
+    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
+        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)
+        return {'value':{'invoice_line_tax_id': res}}
+
+account_invoice_line()
+
+class account_invoice_tax(osv.osv):
+    _name = "account.invoice.tax"
+    _description = "Invoice Tax"
+
+    def _count_factor(self, cr, uid, ids, name, args, context=None):
+        res = {}
+        for invoice_tax in self.browse(cr, uid, ids, context=context):
+            res[invoice_tax.id] = {
+                'factor_base': 1.0,
+                'factor_tax': 1.0,
+            }
+            if invoice_tax.amount <> 0.0:
+                factor_tax = invoice_tax.tax_amount / invoice_tax.amount
+                res[invoice_tax.id]['factor_tax'] = factor_tax
+
+            if invoice_tax.base <> 0.0:
+                factor_base = invoice_tax.base_amount / invoice_tax.base
+                res[invoice_tax.id]['factor_base'] = factor_base
+
+        return res
+
+    _columns = {
+        'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),
+        'name': fields.char('Tax Description', size=64, required=True),
+        'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),
+        'base': fields.float('Base', digits_compute=dp.get_precision('Account')),
+        'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
+        'manual': fields.boolean('Manual'),
+        'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of invoice tax."),
+        'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="The account basis of the tax declaration."),
+        'base_amount': fields.float('Base Code Amount', digits_compute=dp.get_precision('Account')),
+        'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="The tax basis of the tax declaration."),
+        'tax_amount': fields.float('Tax Code Amount', digits_compute=dp.get_precision('Account')),
+        'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
+        'factor_base': fields.function(_count_factor, string='Multipication factor for Base code', type='float', multi="all"),
+        'factor_tax': fields.function(_count_factor, string='Multipication factor Tax code', type='float', multi="all")
+    }
+
+    def base_change(self, cr, uid, ids, base, currency_id=False, company_id=False, date_invoice=False):
+        cur_obj = self.pool.get('res.currency')
+        company_obj = self.pool.get('res.company')
+        company_currency = False
+        factor = 1
+        if ids:
+            factor = self.read(cr, uid, ids[0], ['factor_base'])['factor_base']
+        if company_id:
+            company_currency = company_obj.read(cr, uid, [company_id], ['currency_id'])[0]['currency_id'][0]
+        if currency_id and company_currency:
+            base = cur_obj.compute(cr, uid, currency_id, company_currency, base*factor, context={'date': date_invoice or time.strftime('%Y-%m-%d')}, round=False)
+        return {'value': {'base_amount':base}}
+
+    def amount_change(self, cr, uid, ids, amount, currency_id=False, company_id=False, date_invoice=False):
+        cur_obj = self.pool.get('res.currency')
+        company_obj = self.pool.get('res.company')
+        company_currency = False
+        factor = 1
+        if ids:
+            factor = self.read(cr, uid, ids[0], ['factor_tax'])['factor_tax']
+        if company_id:
+            company_currency = company_obj.read(cr, uid, [company_id], ['currency_id'])[0]['currency_id'][0]
+        if currency_id and company_currency:
+            amount = cur_obj.compute(cr, uid, currency_id, company_currency, amount*factor, context={'date': date_invoice or time.strftime('%Y-%m-%d')}, round=False)
+        return {'value': {'tax_amount': amount}}
+
+    _order = 'sequence'
+    _defaults = {
+        'manual': 1,
+        'base_amount': 0.0,
+        'tax_amount': 0.0,
+    }
+    def compute(self, cr, uid, invoice_id, context=None):
+        tax_grouped = {}
+        tax_obj = self.pool.get('account.tax')
+        cur_obj = self.pool.get('res.currency')
+        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
+        cur = inv.currency_id
+        company_currency = inv.company_id.currency_id.id
+
+        for line in inv.invoice_line:
+            for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id)['taxes']:
+                val={}
+                val['invoice_id'] = inv.id
+                val['name'] = tax['name']
+                val['amount'] = tax['amount']
+                val['manual'] = False
+                val['sequence'] = tax['sequence']
+                val['base'] = tax['price_unit'] * line['quantity']
+
+                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 or time.strftime('%Y-%m-%d')}, round=False)
+                    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')}, round=False)
+                    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 or time.strftime('%Y-%m-%d')}, round=False)
+                    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')}, round=False)
+                    val['account_id'] = tax['account_paid_id'] or line.account_id.id
+
+                key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
+                if not key in tax_grouped:
+                    tax_grouped[key] = val
+                else:
+                    tax_grouped[key]['amount'] += val['amount']
+                    tax_grouped[key]['base'] += val['base']
+                    tax_grouped[key]['base_amount'] += val['base_amount']
+                    tax_grouped[key]['tax_amount'] += val['tax_amount']
+
+        for t in tax_grouped.values():
+            t['base'] = cur_obj.round(cr, uid, cur, t['base'])
+            t['amount'] = cur_obj.round(cr, uid, cur, t['amount'])
+            t['base_amount'] = cur_obj.round(cr, uid, cur, t['base_amount'])
+            t['tax_amount'] = cur_obj.round(cr, uid, cur, t['tax_amount'])
+        return tax_grouped
+
+    def move_line_get(self, cr, uid, invoice_id):
+        res = []
+        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'] \
+                    and not t['tax_amount']:
+                continue
+            res.append({
+                'type':'tax',
+                'name':t['name'],
+                'price_unit': t['amount'],
+                'quantity': 1,
+                'price': t['amount'] or 0.0,
+                'account_id': t['account_id'],
+                'tax_code_id': t['tax_code_id'],
+                'tax_amount': t['tax_amount']
+            })
+        return res
+
+account_invoice_tax()
+
+
+class res_partner(osv.osv):
+    """ Inherits partner and adds invoice information in the partner form """
+    _inherit = 'res.partner'
+    _columns = {
+        'invoice_ids': fields.one2many('account.invoice.line', 'partner_id', 'Invoices', readonly=True),
+    }
+
+    def copy(self, cr, uid, id, default=None, context=None):
+        if default is None:
+            default = {}
+
+        if context is None:
+            context = {}
+
+        default.update({'invoice_ids' : []})
+        return super(res_partner, self).copy(cr, uid, id, default, context)
+
+res_partner()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account/invoice.py b/addons/account/invoice.py
deleted file mode 100644 (file)
index 834da02..0000000
+++ /dev/null
@@ -1,1641 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-import time
-from lxml import etree
-import decimal_precision as dp
-
-import netsvc
-import pooler
-from osv import fields, osv, orm
-from tools.translate import _
-
-class account_invoice(osv.osv):
-    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] = {
-                '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=None):
-        if context is None:
-            context = {}
-        type_inv = context.get('type', 'out_invoice')
-        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
-        company_id = context.get('company_id', user.company_id.id)
-        type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale_refund', 'in_refund': 'purchase_refund'}
-        journal_obj = self.pool.get('account.journal')
-        res = journal_obj.search(cr, uid, [('type', '=', type2journal.get(type_inv, 'sale')),
-                                            ('company_id', '=', company_id)],
-                                                limit=1)
-        return res and res[0] or False
-
-    def _get_currency(self, cr, uid, context=None):
-        user = pooler.get_pool(cr.dbname).get('res.users').browse(cr, uid, [uid], context=context)[0]
-        if user.company_id:
-            return user.company_id.currency_id.id
-        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=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 must define an analytic journal of type '%s' !") % (tt,))
-        return result[0]
-
-    def _get_type(self, cr, uid, context=None):
-        if context is None:
-            context = {}
-        return context.get('type', 'out_invoice')
-
-    def _reconciled(self, cr, uid, ids, name, args, context=None):
-        res = {}
-        for id in ids:
-            res[id] = self.test_paid(cr, uid, [id])
-        return res
-
-    def _get_reference_type(self, cr, uid, context=None):
-        return [('none', _('Free Reference'))]
-
-    def _amount_residual(self, cr, uid, ids, name, args, context=None):
-        result = {}
-        for invoice in self.browse(cr, uid, ids, context=context):
-            result[invoice.id] = 0.0
-            if invoice.move_id:
-                for m in invoice.move_id.line_id:
-                    if m.account_id.type in ('receivable','payable'):
-                        result[invoice.id] += m.amount_residual_currency
-        return result
-
-    # Give Journal Items related to the payment reconciled to this invoice
-    # Return ids of partial and total payments related to the selected invoices
-    def _get_lines(self, cr, uid, ids, name, arg, context=None):
-        res = {}
-        for invoice in self.browse(cr, uid, ids, context=context):
-            id = invoice.id
-            res[id] = []
-            if not invoice.move_id:
-                continue
-            data_lines = [x for x in invoice.move_id.line_id if x.account_id.id == invoice.account_id.id]
-            partial_ids = []
-            for line in data_lines:
-                ids_line = []
-                if line.reconcile_id:
-                    ids_line = line.reconcile_id.line_id
-                elif line.reconcile_partial_id:
-                    ids_line = line.reconcile_partial_id.line_partial_ids
-                l = map(lambda x: x.id, ids_line)
-                partial_ids.append(line.id)
-                res[id] =[x for x in l if x <> line.id and x not in partial_ids]
-        return res
-
-    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=context):
-            src = []
-            lines = []
-            if invoice.move_id:
-                for m in invoice.move_id.line_id:
-                    temp_lines = []
-                    if m.reconcile_id:
-                        temp_lines = map(lambda x: x.id, m.reconcile_id.line_id)
-                    elif m.reconcile_partial_id:
-                        temp_lines = map(lambda x: x.id, m.reconcile_partial_id.line_partial_ids)
-                    lines += [x for x in temp_lines if x not in lines]
-                    src.append(m.id)
-
-            lines = filter(lambda x: x not in src, lines)
-            result[invoice.id] = lines
-        return result
-
-    def _get_invoice_from_line(self, cr, uid, ids, context=None):
-        move = {}
-        for line in self.pool.get('account.move.line').browse(cr, uid, ids, context=context):
-            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=None):
-        move = {}
-        for r in self.pool.get('account.move.reconcile').browse(cr, uid, ids, context=context):
-            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 = "id desc"
-
-    _columns = {
-        'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}),
-        'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}),
-        'type': fields.selection([
-            ('out_invoice','Customer Invoice'),
-            ('in_invoice','Supplier Invoice'),
-            ('out_refund','Customer Refund'),
-            ('in_refund','Supplier Refund'),
-            ],'Type', readonly=True, select=True, change_default=True),
-
-        'number': fields.related('move_id','name', type='char', readonly=True, size=64, relation='account.move', store=True, string='Number'),
-        'internal_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, readonly=True, states={'draft':[('readonly',False)]}),
-        'comment': fields.text('Additional Information'),
-
-        'state': fields.selection([
-            ('draft','Draft'),
-            ('proforma','Pro-forma'),
-            ('proforma2','Pro-forma'),
-            ('open','Open'),
-            ('paid','Paid'),
-            ('cancel','Cancelled')
-            ],'State', select=True, readonly=True,
-            help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \
-            \n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \
-            \n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \
-            \n* The \'Paid\' state is set automatically when invoice is paid.\
-            \n* The \'Cancelled\' state is used when user cancel invoice.'),
-        'date_invoice': fields.date('Invoice Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True, help="Keep empty to use the current date"),
-        'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=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. The payment term may compute several due dates, for example 50% now, 50% in one month."),
-        '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, for example 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(invoice) date.", 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', 'Journal Entry', readonly=True, select=1, ondelete='restrict', help="Link to the automatically generated Journal Items."),
-        'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Untaxed',
-            store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
-                'account.invoice.tax': (_get_invoice_tax, None, 20),
-                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 20),
-            },
-            multi='all'),
-        'amount_tax': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Tax',
-            store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
-                'account.invoice.tax': (_get_invoice_tax, None, 20),
-                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 20),
-            },
-            multi='all'),
-        'amount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total',
-            store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20),
-                'account.invoice.tax': (_get_invoice_tax, None, 20),
-                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 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, change_default=True, readonly=True, states={'draft':[('readonly',False)]}),
-        'check_total': fields.float('Total', digits_compute=dp.get_precision('Account'), states={'open':[('readonly',True)],'close':[('readonly',True)]}),
-        'reconciled': fields.function(_reconciled, string='Paid/Reconciled', type='boolean',
-            store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
-                'account.move.line': (_get_invoice_from_line, None, 50),
-                'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
-            }, help="The Journal Entry of the invoice have been totally reconciled with one or several Journal Entries of payment."),
-        'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',
-            help='Bank Account Number, Company bank account if Invoice is customer or supplier refund, otherwise Partner bank account number.', readonly=True, states={'draft':[('readonly',False)]}),
-        'move_lines':fields.function(_get_lines, type='many2many', relation='account.move.line', string='Entry Lines'),
-        'residual': fields.function(_amount_residual, digits_compute=dp.get_precision('Account'), string='Residual',
-            store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line','move_id'], 50),
-                'account.invoice.tax': (_get_invoice_tax, None, 50),
-                'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 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, relation='account.move.line', type="many2many", string='Payments'),
-        'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}),
-        'user_id': fields.many2one('res.users', 'Salesman', readonly=True, states={'draft':[('readonly',False)]}),
-        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]})
-    }
-    _defaults = {
-        'type': _get_type,
-        'state': 'draft',
-        'journal_id': _get_journal,
-        'currency_id': _get_currency,
-        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.invoice', context=c),
-        'reference_type': 'none',
-        'check_total': 0.0,
-        'internal_number': False,
-        'user_id': lambda s, cr, u, c: u,
-    }
-
-    def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
-        journal_obj = self.pool.get('account.journal')
-        if context is None:
-            context = {}
-
-        if context.get('active_model', '') in ['res.partner'] and context.get('active_ids', False) and context['active_ids']:
-            partner = self.pool.get(context['active_model']).read(cr, uid, context['active_ids'], ['supplier','customer'])[0]
-            if not view_type:
-                view_id = self.pool.get('ir.ui.view').search(cr, uid, [('name', '=', 'account.invoice.tree')])
-                view_type = 'tree'
-            if view_type == 'form':
-                if partner['supplier'] and not partner['customer']:
-                    view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.supplier.form')])
-                else:
-                    view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.form')])
-        if view_id and isinstance(view_id, (list, tuple)):
-            view_id = view_id[0]
-        res = super(account_invoice,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
-
-        type = context.get('journal_type', 'sale')
-        for field in res['fields']:
-            if field == 'journal_id':
-                journal_select = journal_obj._name_search(cr, uid, '', [('type', '=', type)], context=context, limit=None, name_get_uid=1)
-                res['fields'][field]['selection'] = journal_select
-
-        doc = etree.XML(res['arch'])
-        if view_type == 'search':
-            if context.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
-                for node in doc.xpath("//group[@name='extended filter']"):
-                    doc.remove(node)
-            res['arch'] = etree.tostring(doc)
-
-        if view_type == 'tree':
-            partner_string = _('Customer')
-            if context.get('type', 'out_invoice') in ('in_invoice', 'in_refund'):
-                partner_string = _('Supplier')
-                for node in doc.xpath("//field[@name='reference']"):
-                    node.set('invisible', '0')
-            for node in doc.xpath("//field[@name='partner_id']"):
-                node.set('string', partner_string)
-            res['arch'] = etree.tostring(doc)
-        return res
-
-    def get_log_context(self, cr, uid, context=None):
-        if context is None:
-            context = {}
-        res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'invoice_form')
-        view_id = res and res[1] or False
-        context.update({'view_id': view_id})
-        return context
-
-    def create(self, cr, uid, vals, context=None):
-        if context is None:
-            context = {}
-        try:
-            res = super(account_invoice, self).create(cr, uid, vals, context)
-            for inv_id, name in self.name_get(cr, uid, [res], context=context):
-                ctx = context.copy()
-                if vals.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
-                    ctx = self.get_log_context(cr, uid, context=ctx)
-                message = _("Invoice '%s' is waiting for validation.") % name
-                self.log(cr, uid, inv_id, message, context=ctx)
-            return res
-        except Exception, e:
-            if '"journal_id" viol' in e.args[0]:
-                raise orm.except_orm(_('Configuration Error!'),
-                     _('There is no Accounting Journal of type Sale/Purchase defined!'))
-            else:
-                raise orm.except_orm(_('Unknown Error'), str(e))
-
-    def confirm_paid(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        self.write(cr, uid, ids, {'state':'paid'}, context=context)
-        for inv_id, name in self.name_get(cr, uid, ids, context=context):
-            message = _("Invoice '%s' is paid.") % name
-            self.log(cr, uid, inv_id, message)
-        return True
-
-    def unlink(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        invoices = self.read(cr, uid, ids, ['state','internal_number'], context=context)
-        unlink_ids = []
-        for t in invoices:
-            if t['state'] in ('draft', 'cancel') and t['internal_number']== False:
-                unlink_ids.append(t['id'])
-            else:
-                raise osv.except_osv(_('Invalid action !'), _('You can not delete an invoice which is open or paid. We suggest you to refund it instead.'))
-        osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
-        return True
-
-    def onchange_partner_id(self, cr, uid, ids, type, partner_id,\
-            date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
-        invoice_addr_id = False
-        contact_addr_id = False
-        partner_payment_term = False
-        acc_id = False
-        bank_id = False
-        fiscal_position = False
-
-        opt = [('uid', str(uid))]
-        if partner_id:
-
-            opt.insert(0, ('id', partner_id))
-            res = self.pool.get('res.partner').address_get(cr, uid, [partner_id], ['contact', 'invoice'])
-            contact_addr_id = res['contact']
-            invoice_addr_id = res['invoice']
-            p = self.pool.get('res.partner').browse(cr, uid, partner_id)
-            if company_id:
-                if p.property_account_receivable.company_id.id != company_id and p.property_account_payable.company_id.id != company_id:
-                    property_obj = self.pool.get('ir.property')
-                    rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
-                    pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
-                    if not rec_pro_id:
-                        rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('company_id','=',company_id)])
-                    if not pay_pro_id:
-                        pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('company_id','=',company_id)])
-                    rec_line_data = property_obj.read(cr,uid,rec_pro_id,['name','value_reference','res_id'])
-                    pay_line_data = property_obj.read(cr,uid,pay_pro_id,['name','value_reference','res_id'])
-                    rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
-                    pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
-                    if not rec_res_id and not pay_res_id:
-                        raise osv.except_osv(_('Configuration Error !'),
-                            _('Can not find account chart for this company, Please Create account.'))
-                    account_obj = self.pool.get('account.account')
-                    rec_obj_acc = account_obj.browse(cr, uid, [rec_res_id])
-                    pay_obj_acc = account_obj.browse(cr, uid, [pay_res_id])
-                    p.property_account_receivable = rec_obj_acc[0]
-                    p.property_account_payable = pay_obj_acc[0]
-
-            if type in ('out_invoice', 'out_refund'):
-                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
-
-        result = {'value': {
-            'address_contact_id': contact_addr_id,
-            'address_invoice_id': invoice_addr_id,
-            'account_id': acc_id,
-            'payment_term': partner_payment_term,
-            'fiscal_position': fiscal_position
-            }
-        }
-
-        if type in ('in_invoice', 'in_refund'):
-            result['value']['partner_bank_id'] = bank_id
-
-        if payment_term != partner_payment_term:
-            if partner_payment_term:
-                to_update = self.onchange_payment_term_date_invoice(
-                    cr, uid, ids, partner_payment_term, date_invoice)
-                result['value'].update(to_update['value'])
-            else:
-                result['value']['date_due'] = False
-
-        if partner_bank_id != bank_id:
-            to_update = self.onchange_partner_bank(cr, uid, ids, bank_id)
-            result['value'].update(to_update['value'])
-        return result
-
-    def onchange_journal_id(self, cr, uid, ids, journal_id=False):
-        result = {}
-        if journal_id:
-            journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
-            currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id
-            result = {'value': {
-                    'currency_id': currency_id,
-                    }
-                }
-        return result
-
-    def onchange_payment_term_date_invoice(self, cr, uid, ids, payment_term_id, date_invoice):
-        if not payment_term_id:
-            return {}
-        res = {}
-        pt_obj = self.pool.get('account.payment.term')
-        if not date_invoice:
-            date_invoice = time.strftime('%Y-%m-%d')
-
-        pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
-
-        if pterm_list:
-            pterm_list = [line[0] for line in pterm_list]
-            pterm_list.sort()
-            res = {'value':{'date_due': pterm_list[-1]}}
-        else:
-             raise osv.except_osv(_('Data Insufficient !'), _('The Payment Term of Supplier does not have Payment Term Lines(Computation) defined !'))
-        return res
-
-    def onchange_invoice_line(self, cr, uid, ids, lines):
-        return {}
-
-    def onchange_partner_bank(self, cursor, user, ids, partner_bank_id=False):
-        return {'value': {}}
-
-    def onchange_company_id(self, cr, uid, ids, company_id, part_id, type, invoice_line, currency_id):
-        val = {}
-        dom = {}
-        obj_journal = self.pool.get('account.journal')
-        account_obj = self.pool.get('account.account')
-        inv_line_obj = self.pool.get('account.invoice.line')
-        if company_id and part_id and type:
-            acc_id = False
-            partner_obj = self.pool.get('res.partner').browse(cr,uid,part_id)
-            if partner_obj.property_account_payable and partner_obj.property_account_receivable:
-                if partner_obj.property_account_payable.company_id.id != company_id and partner_obj.property_account_receivable.company_id.id != company_id:
-                    property_obj = self.pool.get('ir.property')
-                    rec_pro_id = property_obj.search(cr, uid, [('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
-                    pay_pro_id = property_obj.search(cr, uid, [('name','=','property_account_payable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
-                    if not rec_pro_id:
-                        rec_pro_id = property_obj.search(cr, uid, [('name','=','property_account_receivable'),('company_id','=',company_id)])
-                    if not pay_pro_id:
-                        pay_pro_id = property_obj.search(cr, uid, [('name','=','property_account_payable'),('company_id','=',company_id)])
-                    rec_line_data = property_obj.read(cr, uid, rec_pro_id, ['name','value_reference','res_id'])
-                    pay_line_data = property_obj.read(cr, uid, pay_pro_id, ['name','value_reference','res_id'])
-                    rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
-                    pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
-                    if not rec_res_id and not pay_res_id:
-                        raise osv.except_osv(_('Configuration Error !'),
-                            _('Can not find account chart for this company, Please Create account.'))
-                    if type in ('out_invoice', 'out_refund'):
-                        acc_id = rec_res_id
-                    else:
-                        acc_id = pay_res_id
-                    val= {'account_id': acc_id}
-            if ids:
-                if company_id:
-                    inv_obj = self.browse(cr,uid,ids)
-                    for line in inv_obj[0].invoice_line:
-                        if line.account_id:
-                            if line.account_id.company_id.id != company_id:
-                                result_id = account_obj.search(cr, uid, [('name','=',line.account_id.name),('company_id','=',company_id)])
-                                if not result_id:
-                                    raise osv.except_osv(_('Configuration Error !'),
-                                        _('Can not find account chart for this company in invoice line account, Please Create account.'))
-                                inv_line_obj.write(cr, uid, [line.id], {'account_id': result_id[-1]})
-            else:
-                if invoice_line:
-                    for inv_line in invoice_line:
-                        obj_l = account_obj.browse(cr, uid, inv_line[2]['account_id'])
-                        if obj_l.company_id.id != company_id:
-                            raise osv.except_osv(_('Configuration Error !'),
-                                _('Invoice line account company does not match with invoice company.'))
-                        else:
-                            continue
-        if company_id and type:
-            if type in ('out_invoice'):
-                journal_type = 'sale'
-            elif type in ('out_refund'):
-                journal_type = 'sale_refund'
-            elif type in ('in_refund'):
-                journal_type = 'purchase_refund'
-            else:
-                journal_type = 'purchase'
-            journal_ids = obj_journal.search(cr, uid, [('company_id','=',company_id), ('type', '=', journal_type)])
-            if journal_ids:
-                val['journal_id'] = journal_ids[0]
-            ir_values_obj = self.pool.get('ir.values')
-            res_journal_default = ir_values_obj.get(cr, uid, 'default', 'type=%s' % (type), ['account.invoice'])
-            for r in res_journal_default:
-                if r[1] == 'journal_id' and r[2] in journal_ids:
-                    val['journal_id'] = r[2]
-            if not val.get('journal_id', False):
-                raise osv.except_osv(_('Configuration Error !'), (_('Can\'t find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Financial Accounting\Accounts\Journals.') % (journal_type)))
-            dom = {'journal_id':  [('id', 'in', journal_ids)]}
-        else:
-            journal_ids = obj_journal.search(cr, uid, [])
-
-        if currency_id and company_id:
-            currency = self.pool.get('res.currency').browse(cr, uid, currency_id)
-            if currency.company_id and currency.company_id.id != company_id:
-                val['currency_id'] = False
-            else:
-                val['currency_id'] = currency.id
-        if company_id:
-            company = self.pool.get('res.company').browse(cr, uid, company_id)
-            if company.currency_id.company_id and company.currency_id.company_id.id != company_id:
-                val['currency_id'] = False
-            else:
-                val['currency_id'] = company.currency_id.id
-        return {'value': val, 'domain': dom}
-
-    # go from canceled state to draft state
-    def action_cancel_draft(self, cr, uid, ids, *args):
-        self.write(cr, uid, ids, {'state':'draft'})
-        wf_service = netsvc.LocalService("workflow")
-        for inv_id in ids:
-            wf_service.trg_delete(uid, 'account.invoice', inv_id, cr)
-            wf_service.trg_create(uid, 'account.invoice', inv_id, cr)
-        return True
-
-    # Workflow stuff
-    #################
-
-    # return the ids of the move lines which has the same account than the invoice
-    # whose id is in ids
-    def move_line_id_payment_get(self, cr, uid, ids, *args):
-        if not ids: return []
-        result = self.move_line_id_payment_gets(cr, uid, ids, *args)
-        return result.get(ids[0], [])
-
-    def move_line_id_payment_gets(self, cr, uid, ids, *args):
-        res = {}
-        if not ids: return res
-        cr.execute('SELECT i.id, l.id '\
-                   'FROM account_move_line l '\
-                   'LEFT JOIN account_invoice i ON (i.move_id=l.move_id) '\
-                   'WHERE i.id IN %s '\
-                   'AND l.account_id=i.account_id',
-                   (tuple(ids),))
-        for r in cr.fetchall():
-            res.setdefault(r[0], [])
-            res[r[0]].append( r[1] )
-        return res
-
-    def copy(self, cr, uid, id, default={}, context=None):
-        if context is None:
-            context = {}
-        default.update({
-            'state':'draft',
-            'number':False,
-            'move_id':False,
-            'move_name':False,
-            'internal_number': False,
-        })
-        if 'date_invoice' not in default:
-            default.update({
-                'date_invoice':False
-            })
-        if 'date_due' not in default:
-            default.update({
-                'date_due':False
-            })
-        return super(account_invoice, self).copy(cr, uid, id, default, context)
-
-    def test_paid(self, cr, uid, ids, *args):
-        res = self.move_line_id_payment_get(cr, uid, ids)
-        if not res:
-            return False
-        ok = True
-        for id in res:
-            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=None):
-        if context is None:
-            context = {}
-        ctx = context.copy()
-        ait_obj = self.pool.get('account.invoice.tax')
-        for id in ids:
-            cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%s AND manual is False", (id,))
-            partner = self.browse(cr, uid, id, context=ctx).partner_id
-            if partner.lang:
-                ctx.update({'lang': partner.lang})
-            for taxe in ait_obj.compute(cr, uid, id, context=ctx).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, {'invoice_line':[]}, context=ctx)
-        return True
-
-    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, context=context):
-            if set_total:
-                self.pool.get('account.invoice').write(cr, uid, [inv.id], {'check_total': inv.amount_total})
-        return True
-
-    def _convert_ref(self, cr, uid, ref):
-        return (ref or '').replace('/','')
-
-    def _get_analytic_lines(self, cr, uid, id, context=None):
-        if context is None:
-            context = {}
-        inv = self.browse(cr, uid, id)
-        cur_obj = self.pool.get('res.currency')
-
-        company_currency = inv.company_id.currency_id.id
-        if inv.type in ('out_invoice', 'in_refund'):
-            sign = 1
-        else:
-            sign = -1
-
-        iml = self.pool.get('account.invoice.line').move_line_get(cr, uid, inv.id, context=context)
-        for il in iml:
-            if il['account_analytic_id']:
-                if inv.type in ('in_invoice', 'in_refund'):
-                    ref = inv.reference
-                else:
-                    ref = self._convert_ref(cr, uid, inv.number)
-                if not inv.journal_id.analytic_journal_id:
-                    raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,))
-                il['analytic_lines'] = [(0,0, {
-                    'name': il['name'],
-                    'date': inv['date_invoice'],
-                    'account_id': il['account_analytic_id'],
-                    'unit_amount': il['quantity'],
-                    'amount': cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, il['price'], context={'date': inv.date_invoice}) * sign,
-                    'product_id': il['product_id'],
-                    'product_uom_id': il['uos_id'],
-                    'general_account_id': il['account_id'],
-                    'journal_id': inv.journal_id.analytic_journal_id.id,
-                    'ref': ref,
-                })]
-        return iml
-
-    def action_date_assign(self, cr, uid, ids, *args):
-        for inv in self.browse(cr, uid, ids):
-            res = self.onchange_payment_term_date_invoice(cr, uid, inv.id, inv.payment_term.id, inv.date_invoice)
-            if res and res['value']:
-                self.write(cr, uid, [inv.id], res['value'])
-        return True
-
-    def finalize_invoice_move_lines(self, cr, uid, invoice_browse, move_lines):
-        """finalize_invoice_move_lines(cr, uid, invoice, move_lines) -> move_lines
-        Hook method to be overridden in additional modules to verify and possibly alter the
-        move lines to be created by an invoice, for special cases.
-        :param invoice_browse: browsable record of the invoice that is generating the move lines
-        :param move_lines: list of dictionaries with the account.move.lines (as for create())
-        :return: the (possibly updated) final move_lines to create for this invoice
-        """
-        return move_lines
-
-    def check_tax_lines(self, cr, uid, inv, compute_taxes, ait_obj):
-        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:
-                    raise osv.except_osv(_('Warning !'), _('Global taxes defined, but are not in invoice lines !'))
-                base = compute_taxes[key]['base']
-                if abs(base - tax.base) > inv.company_id.currency_id.rounding:
-                    raise osv.except_osv(_('Warning !'), _('Tax base different !\nClick on compute to update tax base'))
-            for key in compute_taxes:
-                if not key in tax_key:
-                    raise osv.except_osv(_('Warning !'), _('Taxes missing !'))
-
-    def compute_invoice_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines):
-        total = 0
-        total_currency = 0
-        cur_obj = self.pool.get('res.currency')
-        for i in invoice_move_lines:
-            if inv.currency_id.id != company_currency:
-                i['currency_id'] = inv.currency_id.id
-                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 or time.strftime('%Y-%m-%d')})
-            else:
-                i['amount_currency'] = False
-                i['currency_id'] = False
-            i['ref'] = ref
-            if inv.type in ('out_invoice','in_refund'):
-                total += i['price']
-                total_currency += i['amount_currency'] or i['price']
-                i['price'] = - i['price']
-            else:
-                total -= i['price']
-                total_currency -= i['amount_currency'] or i['price']
-        return total, total_currency, invoice_move_lines
-
-    def inv_line_characteristic_hashcode(self, invoice, invoice_line):
-        """Overridable hashcode generation for invoice lines. Lines having the same hashcode
-        will be grouped together if the journal has the 'group line' option. Of course a module
-        can add fields to invoice lines that would need to be tested too before merging lines
-        or not."""
-        return "%s-%s-%s-%s-%s"%(
-            invoice_line['account_id'],
-            invoice_line.get('tax_code_id',"False"),
-            invoice_line.get('product_id',"False"),
-            invoice_line.get('analytic_account_id',"False"),
-            invoice_line.get('date_maturity',"False"))
-
-    def group_lines(self, cr, uid, iml, line, inv):
-        """Merge account move lines (and hence analytic lines) if invoice line hashcodes are equals"""
-        if inv.journal_id.group_invoice_lines:
-            line2 = {}
-            for x, y, l in line:
-                tmp = self.inv_line_characteristic_hashcode(inv, l)
-
-                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))
-        return line
-
-    def action_move_create(self, cr, uid, ids, *args):
-        """Creates invoice related analytics and financial move lines"""
-        ait_obj = self.pool.get('account.invoice.tax')
-        cur_obj = self.pool.get('res.currency')
-        context = {}
-        for inv in self.browse(cr, uid, ids):
-            if not inv.journal_id.sequence_id:
-                raise osv.except_osv(_('Error !'), _('Please define sequence on invoice journal'))
-            if not inv.invoice_line:
-                raise osv.except_osv(_('No Invoice Lines !'), _('Please create some invoice lines.'))
-            if inv.move_id:
-                continue
-
-            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
-            # one move line per invoice line
-            iml = self._get_analytic_lines(cr, uid, inv.id)
-            # check if taxes are all computed
-            ctx = context.copy()
-            ctx.update({'lang': inv.partner_id.lang})
-            compute_taxes = ait_obj.compute(cr, uid, inv.id, context=ctx)
-            self.check_tax_lines(cr, uid, inv, compute_taxes, ait_obj)
-
-            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 inv.payment_term:
-                total_fixed = total_percent = 0
-                for line in inv.payment_term.line_ids:
-                    if line.value == 'fixed':
-                        total_fixed += line.value_amount
-                    if line.value == 'procent':
-                        total_percent += line.value_amount
-                total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0)
-                if (total_fixed + total_percent) > 100:
-                    raise osv.except_osv(_('Error !'), _("Can not create the invoice !\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount."))
-
-            # one move line per tax line
-            iml += ait_obj.move_line_get(cr, uid, inv.id)
-
-            entry_type = ''
-            if inv.type in ('in_invoice', 'in_refund'):
-                ref = inv.reference
-                entry_type = 'journal_pur_voucher'
-                if inv.type == 'in_refund':
-                    entry_type = 'cont_voucher'
-            else:
-                ref = self._convert_ref(cr, uid, inv.number)
-                entry_type = 'journal_sale_vou'
-                if inv.type == 'out_refund':
-                    entry_type = 'cont_voucher'
-
-            diff_currency_p = inv.currency_id.id <> company_currency
-            # create one move line for the total and possibly adjust the other lines amount
-            total = 0
-            total_currency = 0
-            total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml)
-            acc_id = inv.account_id.id
-
-            name = inv['name'] or '/'
-            totlines = False
-            if inv.payment_term:
-                totlines = self.pool.get('account.payment.term').compute(cr,
-                        uid, inv.payment_term.id, total, inv.date_invoice or False)
-            if totlines:
-                res_amount_currency = total_currency
-                i = 0
-                ctx.update({'date': inv.date_invoice})
-                for t in totlines:
-                    if inv.currency_id.id != company_currency:
-                        amount_currency = cur_obj.compute(cr, uid, company_currency, inv.currency_id.id, t[1], context=ctx)
-                    else:
-                        amount_currency = False
-
-                    # last line add the diff
-                    res_amount_currency -= amount_currency or 0
-                    i += 1
-                    if i == len(totlines):
-                        amount_currency += res_amount_currency
-
-                    iml.append({
-                        'type': 'dest',
-                        'name': name,
-                        'price': t[1],
-                        'account_id': acc_id,
-                        'date_maturity': t[0],
-                        'amount_currency': diff_currency_p \
-                                and  amount_currency or False,
-                        'currency_id': diff_currency_p \
-                                and inv.currency_id.id or False,
-                        'ref': ref,
-                    })
-            else:
-                iml.append({
-                    'type': 'dest',
-                    'name': name,
-                    'price': total,
-                    'account_id': acc_id,
-                    'date_maturity': inv.date_due or False,
-                    'amount_currency': diff_currency_p \
-                            and total_currency or False,
-                    'currency_id': diff_currency_p \
-                            and inv.currency_id.id or False,
-                    'ref': ref
-            })
-
-            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)
-
-            line = self.group_lines(cr, uid, iml, line, inv)
-
-            journal_id = inv.journal_id.id
-            journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
-            if journal.centralisation:
-                raise osv.except_osv(_('UserError'),
-                        _('You cannot create an invoice on a centralised journal. Uncheck the centralised counterpart box in the related journal from the configuration menu.'))
-
-            line = self.finalize_invoice_move_lines(cr, uid, inv, line)
-
-            move = {
-                'ref': inv.reference and inv.reference or inv.name,
-                'line_id': line,
-                'journal_id': journal_id,
-                'date': date,
-                'type': entry_type,
-                'narration':inv.comment
-            }
-            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')), ('company_id', '=', inv.company_id.id)])
-                if 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, context=context)
-            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, 'move_name':new_move_name})
-            # Pass invoice in context in method post: used if you want to get the same
-            # account move reference when creating the same invoice after a cancelled one:
-            self.pool.get('account.move').post(cr, uid, [move_id], context={'invoice':inv})
-        self._log_event(cr, uid, ids)
-        return True
-
-    def line_get_convert(self, cr, uid, x, part, date, context=None):
-        return {
-            'date_maturity': x.get('date_maturity', False),
-            'partner_id': part,
-            'name': x['name'][:64],
-            'date': date,
-            'debit': x['price']>0 and x['price'],
-            'credit': x['price']<0 and -x['price'],
-            'account_id': x['account_id'],
-            'analytic_lines': x.get('analytic_lines', []),
-            'amount_currency': x['price']>0 and abs(x.get('amount_currency', False)) or -abs(x.get('amount_currency', False)),
-            '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),
-            '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, context=None):
-        if context is None:
-            context = {}
-        #TODO: not correct fix but required a frech values before reading it.
-        self.write(cr, uid, ids, {})
-
-        for obj_inv in self.browse(cr, uid, ids, context=context):
-            id = obj_inv.id
-            invtype = obj_inv.type
-            number = obj_inv.number
-            move_id = obj_inv.move_id and obj_inv.move_id.id or False
-            reference = obj_inv.reference or ''
-
-            self.write(cr, uid, ids, {'internal_number':number})
-
-            if invtype in ('in_invoice', 'in_refund'):
-                if not reference:
-                    ref = self._convert_ref(cr, uid, number)
-                else:
-                    ref = reference
-            else:
-                ref = self._convert_ref(cr, uid, number)
-
-            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))
-            cr.execute('UPDATE account_analytic_line SET ref=%s ' \
-                    'FROM account_move_line ' \
-                    'WHERE account_move_line.move_id = %s ' \
-                        'AND account_analytic_line.move_id = account_move_line.id',
-                        (ref, move_id))
-
-            for inv_id, name in self.name_get(cr, uid, [id]):
-                ctx = context.copy()
-                if obj_inv.type in ('out_invoice', 'out_refund'):
-                    ctx = self.get_log_context(cr, uid, context=ctx)
-                message = _("Invoice  '%s' is validated.") % name
-                self.log(cr, uid, inv_id, message, context=ctx)
-        return True
-
-    def action_cancel(self, cr, uid, ids, *args):
-        context = {} # TODO: Use context from arguments
-        account_move_obj = self.pool.get('account.move')
-        invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids'])
-        move_ids = [] # ones that we will need to remove
-        for i in invoices:
-            if i['move_id']:
-                move_ids.append(i['move_id'][0])
-            if i['payment_ids']:
-                account_move_line_obj = self.pool.get('account.move.line')
-                pay_ids = account_move_line_obj.browse(cr, uid, i['payment_ids'])
-                for move_line in pay_ids:
-                    if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids:
-                        raise osv.except_osv(_('Error !'), _('You can not cancel an invoice which is partially paid! You need to unreconcile related payment entries first!'))
-
-        # First, set the invoices as cancelled and detach the move ids
-        self.write(cr, uid, ids, {'state':'cancel', 'move_id':False})
-        if move_ids:
-            # second, invalidate the move(s)
-            account_move_obj.button_cancel(cr, uid, move_ids, context=context)
-            # delete the move this invoice was pointing to
-            # Note that the corresponding move_lines and move_reconciles
-            # will be automatically deleted too
-            account_move_obj.unlink(cr, uid, move_ids, context=context)
-        self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice')
-        return True
-
-    ###################
-
-    def list_distinct_taxes(self, cr, uid, ids):
-        invoices = self.browse(cr, uid, ids)
-        taxes = {}
-        for inv in invoices:
-            for tax in inv.tax_line:
-                if not tax['name'] in taxes:
-                    taxes[tax['name']] = {'name': tax['name']}
-        return taxes.values()
-
-    def _log_event(self, cr, uid, ids, factor=1.0, name='Open Invoice'):
-        #TODO: implement messages system
-        return True
-
-    def name_get(self, cr, uid, ids, context=None):
-        if not ids:
-            return []
-        types = {
-                'out_invoice': 'CI: ',
-                'in_invoice': 'SI: ',
-                'out_refund': 'OR: ',
-                'in_refund': 'SR: ',
-                }
-        return [(r['id'], (r['number']) or types[r['type']] + (r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
-
-    def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
-        if not args:
-            args = []
-        if context is None:
-            context = {}
-        ids = []
-        if name:
-            ids = self.search(cr, user, [('number','=',name)] + args, limit=limit, context=context)
-        if not ids:
-            ids = self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context)
-        return self.name_get(cr, user, ids, context)
-
-    def _refund_cleanup_lines(self, cr, uid, lines):
-        for line in lines:
-            del line['id']
-            del line['invoice_id']
-            for field in ('company_id', 'partner_id', 'account_id', 'product_id',
-                          'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id'):
-                line[field] = line.get(field, False) and line[field][0]
-            if 'invoice_line_tax_id' in line:
-                line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ]
-        return map(lambda x: (0,0,x), lines)
-
-    def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=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'])
-        obj_invoice_line = self.pool.get('account.invoice.line')
-        obj_invoice_tax = self.pool.get('account.invoice.tax')
-        obj_journal = self.pool.get('account.journal')
-        new_ids = []
-        for invoice in invoices:
-            del invoice['id']
-
-            type_dict = {
-                'out_invoice': 'out_refund', # Customer Invoice
-                'in_invoice': 'in_refund',   # Supplier Invoice
-                'out_refund': 'out_invoice', # Customer Refund
-                'in_refund': 'in_invoice',   # Supplier Refund
-            }
-
-            invoice_lines = obj_invoice_line.read(cr, uid, invoice['invoice_line'])
-            invoice_lines = self._refund_cleanup_lines(cr, uid, invoice_lines)
-
-            tax_lines = obj_invoice_tax.read(cr, uid, invoice['tax_line'])
-            tax_lines = filter(lambda l: l['manual'], tax_lines)
-            tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines)
-            if journal_id:
-                refund_journal_ids = [journal_id]
-            elif invoice['type'] == 'in_invoice':
-                refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')])
-            else:
-                refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')])
-
-            if not date:
-                date = time.strftime('%Y-%m-%d')
-            invoice.update({
-                'type': type_dict[invoice['type']],
-                'date_invoice': date,
-                'state': 'draft',
-                'number': False,
-                'invoice_line': invoice_lines,
-                'tax_line': tax_lines,
-                'journal_id': refund_journal_ids
-            })
-            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=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], context=context)
-        src_account_id = invoice.account_id.id
-        # Take the seq as name for move
-        types = {'out_invoice': -1, 'in_invoice': 1, 'out_refund': 1, 'in_refund': -1}
-        direction = types[invoice.type]
-        #take the choosen date
-        if 'date_p' in context and context['date_p']:
-            date=context['date_p']
-        else:
-            date=time.strftime('%Y-%m-%d')
-
-        # Take the amount in currency and the currency of the payment
-        if 'amount_currency' in context and context['amount_currency'] and 'currency_id' in context and context['currency_id']:
-            amount_currency = context['amount_currency']
-            currency_id = context['currency_id']
-        else:
-            amount_currency = False
-            currency_id = False
-
-        pay_journal = self.pool.get('account.journal').read(cr, uid, pay_journal_id, ['type'], context=context)
-        if invoice.type in ('in_invoice', 'out_invoice'):
-            if pay_journal['type'] == 'bank':
-                entry_type = 'bank_pay_voucher' # Bank payment
-            else:
-                entry_type = 'pay_voucher' # Cash payment
-        else:
-            entry_type = 'cont_voucher'
-        if invoice.type in ('in_invoice', 'in_refund'):
-            ref = invoice.reference
-        else:
-            ref = self._convert_ref(cr, uid, invoice.number)
-        # Pay attention to the sign for both debit/credit AND amount_currency
-        l1 = {
-            '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,
-            'ref':ref,
-            'date': date,
-            'currency_id':currency_id,
-            'amount_currency':amount_currency and direction * amount_currency or 0.0,
-            'company_id': invoice.company_id.id,
-        }
-        l2 = {
-            '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,
-            'ref':ref,
-            'date': date,
-            'currency_id':currency_id,
-            'amount_currency':amount_currency and - direction * amount_currency or 0.0,
-            'company_id': invoice.company_id.id,
-        }
-
-        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 = {'ref': ref, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date, 'type': entry_type}
-        move_id = self.pool.get('account.move').create(cr, uid, move, context=context)
-
-        line_ids = []
-        total = 0.0
-        line = self.pool.get('account.move.line')
-        move_ids = [move_id,]
-        if invoice.move_id:
-            move_ids.append(invoice.move_id.id)
-        cr.execute('SELECT id FROM account_move_line '\
-                   'WHERE move_id IN %s',
-                   ((move_id, invoice.move_id.id),))
-        lines = line.browse(cr, uid, map(lambda x: x[0], cr.fetchall()) )
-        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)
-
-        inv_id, name = self.name_get(cr, uid, [invoice.id], context=context)[0]
-        if (not round(total,self.pool.get('decimal.precision').precision_get(cr, uid, 'Account'))) or writeoff_acc_id:
-            self.pool.get('account.move.line').reconcile(cr, uid, line_ids, 'manual', writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context)
-        else:
-            code = invoice.currency_id.symbol
-            # TODO: use currency's formatting function
-            msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining)") % \
-                    (name, pay_amount, code, invoice.amount_total, code, total, code)
-            self.log(cr, uid, inv_id,  msg)
-            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()
-
-class account_invoice_line(osv.osv):
-
-    def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict):
-        res = {}
-        tax_obj = self.pool.get('account.tax')
-        cur_obj = self.pool.get('res.currency')
-        for line in self.browse(cr, uid, ids):
-            price = line.price_unit * (1-(line.discount or 0.0)/100.0)
-            taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, address_id=line.invoice_id.address_invoice_id, partner=line.invoice_id.partner_id)
-            res[line.id] = taxes['total']
-            if line.invoice_id:
-                cur = line.invoice_id.currency_id
-                res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
-        return res
-
-    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', {}):
-                if isinstance(l, (list, tuple)) and len(l) >= 3 and l[2]:
-                    tax_obj = self.pool.get('account.tax')
-                    p = l[2].get('price_unit', 0) * (1-l[2].get('discount', 0)/100.0)
-                    t = t - (p * l[2].get('quantity'))
-                    taxes = l[2].get('invoice_line_tax_id')
-                    if len(taxes[0]) >= 3 and taxes[0][2]:
-                        taxes = tax_obj.browse(cr, uid, list(taxes[0][2]))
-                        for tax in tax_obj.compute_all(cr, uid, taxes, p,l[2].get('quantity'), context.get('address_invoice_id', False), l[2].get('product_id', False), context.get('partner_id', False))['taxes']:
-                            t = t - tax['amount']
-            return t
-        return 0
-
-    _name = "account.invoice.line"
-    _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 Reference', ondelete='cascade', select=True),
-        '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')], help="The income or expense account related to the selected product."),
-        'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')),
-        'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float",
-            digits_compute= dp.get_precision('Account'), store=True),
-        'quantity': fields.float('Quantity', required=True),
-        'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Account')),
-        'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]),
-        'note': fields.text('Notes'),
-        'account_analytic_id':  fields.many2one('account.analytic.account', 'Analytic Account'),
-        'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
-        'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
-    }
-    _defaults = {
-        'quantity': 1,
-        'discount': 0.0,
-        'price_unit': _price_unit_default,
-    }
-
-    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
-        if context is None:
-            context = {}
-        res = super(account_invoice_line,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
-        if context.get('type', False):
-            doc = etree.XML(res['arch'])
-            for node in doc.xpath("//field[@name='product_id']"):
-                if context['type'] in ('in_invoice', 'in_refund'):
-                    node.set('domain', "[('purchase_ok', '=', True)]")
-                else:
-                    node.set('domain', "[('sale_ok', '=', True)]")
-            res['arch'] = etree.tostring(doc)
-        return res
-
-    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, currency_id=False, context=None, company_id=None):
-        if context is None:
-            context = {}
-        company_id = company_id if company_id != None else context.get('company_id',False)
-        context = dict(context)
-        context.update({'company_id': company_id})
-        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 {'value': {'categ_id': False}, 'domain':{'product_uom':[]}}
-            else:
-                return {'value': {'price_unit': 0.0, 'categ_id': False}, 'domain':{'product_uom':[]}}
-        part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
-        fpos_obj = self.pool.get('account.fiscal.position')
-        fpos = fposition_id and fpos_obj.browse(cr, uid, fposition_id, context=context) or False
-
-        if part.lang:
-            context.update({'lang': part.lang})
-        result = {}
-        res = self.pool.get('product.product').browse(cr, uid, product, context=context)
-
-        if type in ('out_invoice','out_refund'):
-            a = res.product_tmpl_id.property_account_income.id
-            if not a:
-                a = res.categ_id.property_account_income_categ.id
-        else:
-            a = res.product_tmpl_id.property_account_expense.id
-            if not a:
-                a = res.categ_id.property_account_expense_categ.id
-        a = fpos_obj.map_account(cr, uid, fpos, a)
-        if a:
-            result['account_id'] = a
-
-        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, context=context).tax_ids or False)
-        else:
-            taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False)
-        tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
-
-        if type in ('in_invoice', 'in_refund'):
-            result.update( {'price_unit': price_unit or res.standard_price,'invoice_line_tax_id': tax_id} )
-        else:
-            result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
-        result['name'] = res.partner_ref
-
-        domain = {}
-        result['uos_id'] = res.uom_id.id or uom or False
-        result['note'] = res.description
-        if result['uos_id']:
-            res2 = res.uom_id.category_id.id
-            if res2:
-                domain = {'uos_id':[('category_id','=',res2 )]}
-
-        result['categ_id'] = res.categ_id.id
-        res_final = {'value':result, 'domain':domain}
-
-        if not company_id or not currency_id:
-            return res_final
-
-        company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
-        currency = self.pool.get('res.currency').browse(cr, uid, currency_id, context=context)
-
-        if company.currency_id.id != currency.id:
-            if type in ('in_invoice', 'in_refund'):
-                res_final['value']['price_unit'] = res.standard_price
-            new_price = res_final['value']['price_unit'] * currency.rate
-            res_final['value']['price_unit'] = new_price
-
-        if uom:
-            uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context)
-            if res.uom_id.category_id.id == uom.category_id.id:
-                new_price = res_final['value']['price_unit'] * uom.factor_inv
-                res_final['value']['price_unit'] = new_price
-        return res_final
-
-    def uos_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, currency_id=False, context=None, company_id=None):
-        if context is None:
-            context = {}
-        company_id = company_id if company_id != None else context.get('company_id',False)
-        context = dict(context)
-        context.update({'company_id': company_id})
-        warning = {}
-        res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context=context)
-        if 'uos_id' in res['value']:
-            del res['value']['uos_id']
-        if not uom:
-            res['value']['price_unit'] = 0.0
-        if product and uom:
-            prod = self.pool.get('product.product').browse(cr, uid, product, context=context)
-            prod_uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context)
-            if prod.uom_id.category_id.id != prod_uom.category_id.id:
-                 warning = {
-                    'title': _('Warning!'),
-                    'message': _('You selected an Unit of Measure which is not compatible with the product.')
-            }
-            return {'value': res['value'], 'warning': warning}
-        return res
-
-    def move_line_get(self, cr, uid, invoice_id, context=None):
-        res = []
-        tax_obj = self.pool.get('account.tax')
-        cur_obj = self.pool.get('res.currency')
-        if context is None:
-            context = {}
-        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
-        company_currency = inv.company_id.currency_id.id
-
-        for line in inv.invoice_line:
-            mres = self.move_line_get_item(cr, uid, line, context)
-            if not mres:
-                continue
-            res.append(mres)
-            tax_code_found= False
-            for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id,
-                    (line.price_unit * (1.0 - (line['discount'] or 0.0) / 100.0)),
-                    line.quantity, inv.address_invoice_id.id, line.product_id,
-                    inv.partner_id)['taxes']:
-
-                if inv.type in ('out_invoice', 'in_invoice'):
-                    tax_code_id = tax['base_code_id']
-                    tax_amount = line.price_subtotal * tax['base_sign']
-                else:
-                    tax_code_id = tax['ref_base_code_id']
-                    tax_amount = line.price_subtotal * tax['ref_base_sign']
-
-                if tax_code_found:
-                    if not tax_code_id:
-                        continue
-                    res.append(self.move_line_get_item(cr, uid, line, context))
-                    res[-1]['price'] = 0.0
-                    res[-1]['account_analytic_id'] = False
-                elif not tax_code_id:
-                    continue
-                tax_code_found = True
-
-                res[-1]['tax_code_id'] = tax_code_id
-                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=None):
-        return {
-            'type':'src',
-            'name': line.name[:64],
-            'price_unit':line.price_unit,
-            'quantity':line.quantity,
-            'price':line.price_subtotal,
-            'account_id':line.account_id.id,
-            '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 fiscal position
-    #
-    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
-        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)
-        return {'value':{'invoice_line_tax_id': res}}
-
-account_invoice_line()
-
-class account_invoice_tax(osv.osv):
-    _name = "account.invoice.tax"
-    _description = "Invoice Tax"
-
-    def _count_factor(self, cr, uid, ids, name, args, context=None):
-        res = {}
-        for invoice_tax in self.browse(cr, uid, ids, context=context):
-            res[invoice_tax.id] = {
-                'factor_base': 1.0,
-                'factor_tax': 1.0,
-            }
-            if invoice_tax.amount <> 0.0:
-                factor_tax = invoice_tax.tax_amount / invoice_tax.amount
-                res[invoice_tax.id]['factor_tax'] = factor_tax
-
-            if invoice_tax.base <> 0.0:
-                factor_base = invoice_tax.base_amount / invoice_tax.base
-                res[invoice_tax.id]['factor_base'] = factor_base
-
-        return res
-
-    _columns = {
-        'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),
-        'name': fields.char('Tax Description', size=64, required=True),
-        'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),
-        'base': fields.float('Base', digits_compute=dp.get_precision('Account')),
-        'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
-        'manual': fields.boolean('Manual'),
-        'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of invoice tax."),
-        'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="The account basis of the tax declaration."),
-        'base_amount': fields.float('Base Code Amount', digits_compute=dp.get_precision('Account')),
-        'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="The tax basis of the tax declaration."),
-        'tax_amount': fields.float('Tax Code Amount', digits_compute=dp.get_precision('Account')),
-        'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
-        'factor_base': fields.function(_count_factor, string='Multipication factor for Base code', type='float', multi="all"),
-        'factor_tax': fields.function(_count_factor, string='Multipication factor Tax code', type='float', multi="all")
-    }
-
-    def base_change(self, cr, uid, ids, base, currency_id=False, company_id=False, date_invoice=False):
-        cur_obj = self.pool.get('res.currency')
-        company_obj = self.pool.get('res.company')
-        company_currency = False
-        factor = 1
-        if ids:
-            factor = self.read(cr, uid, ids[0], ['factor_base'])['factor_base']
-        if company_id:
-            company_currency = company_obj.read(cr, uid, [company_id], ['currency_id'])[0]['currency_id'][0]
-        if currency_id and company_currency:
-            base = cur_obj.compute(cr, uid, currency_id, company_currency, base*factor, context={'date': date_invoice or time.strftime('%Y-%m-%d')}, round=False)
-        return {'value': {'base_amount':base}}
-
-    def amount_change(self, cr, uid, ids, amount, currency_id=False, company_id=False, date_invoice=False):
-        cur_obj = self.pool.get('res.currency')
-        company_obj = self.pool.get('res.company')
-        company_currency = False
-        factor = 1
-        if ids:
-            factor = self.read(cr, uid, ids[0], ['factor_tax'])['factor_tax']
-        if company_id:
-            company_currency = company_obj.read(cr, uid, [company_id], ['currency_id'])[0]['currency_id'][0]
-        if currency_id and company_currency:
-            amount = cur_obj.compute(cr, uid, currency_id, company_currency, amount*factor, context={'date': date_invoice or time.strftime('%Y-%m-%d')}, round=False)
-        return {'value': {'tax_amount': amount}}
-
-    _order = 'sequence'
-    _defaults = {
-        'manual': 1,
-        'base_amount': 0.0,
-        'tax_amount': 0.0,
-    }
-    def compute(self, cr, uid, invoice_id, context=None):
-        tax_grouped = {}
-        tax_obj = self.pool.get('account.tax')
-        cur_obj = self.pool.get('res.currency')
-        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
-        cur = inv.currency_id
-        company_currency = inv.company_id.currency_id.id
-
-        for line in inv.invoice_line:
-            for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id)['taxes']:
-                val={}
-                val['invoice_id'] = inv.id
-                val['name'] = tax['name']
-                val['amount'] = tax['amount']
-                val['manual'] = False
-                val['sequence'] = tax['sequence']
-                val['base'] = tax['price_unit'] * line['quantity']
-
-                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 or time.strftime('%Y-%m-%d')}, round=False)
-                    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')}, round=False)
-                    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 or time.strftime('%Y-%m-%d')}, round=False)
-                    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')}, round=False)
-                    val['account_id'] = tax['account_paid_id'] or line.account_id.id
-
-                key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
-                if not key in tax_grouped:
-                    tax_grouped[key] = val
-                else:
-                    tax_grouped[key]['amount'] += val['amount']
-                    tax_grouped[key]['base'] += val['base']
-                    tax_grouped[key]['base_amount'] += val['base_amount']
-                    tax_grouped[key]['tax_amount'] += val['tax_amount']
-
-        for t in tax_grouped.values():
-            t['base'] = cur_obj.round(cr, uid, cur, t['base'])
-            t['amount'] = cur_obj.round(cr, uid, cur, t['amount'])
-            t['base_amount'] = cur_obj.round(cr, uid, cur, t['base_amount'])
-            t['tax_amount'] = cur_obj.round(cr, uid, cur, t['tax_amount'])
-        return tax_grouped
-
-    def move_line_get(self, cr, uid, invoice_id):
-        res = []
-        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'] \
-                    and not t['tax_amount']:
-                continue
-            res.append({
-                'type':'tax',
-                'name':t['name'],
-                'price_unit': t['amount'],
-                'quantity': 1,
-                'price': t['amount'] or 0.0,
-                'account_id': t['account_id'],
-                'tax_code_id': t['tax_code_id'],
-                'tax_amount': t['tax_amount']
-            })
-        return res
-
-account_invoice_tax()
-
-
-class res_partner(osv.osv):
-    """ Inherits partner and adds invoice information in the partner form """
-    _inherit = 'res.partner'
-    _columns = {
-        'invoice_ids': fields.one2many('account.invoice.line', 'partner_id', 'Invoices', readonly=True),
-    }
-
-    def copy(self, cr, uid, id, default=None, context=None):
-        if default is None:
-            default = {}
-
-        if context is None:
-            context = {}
-
-        default.update({'invoice_ids' : []})
-        return super(res_partner, self).copy(cr, uid, id, default, context)
-
-res_partner()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: