[MERGE] opw 18200 : don't erase unit price when erasing the product in invoice line
[odoo/odoo.git] / addons / account / invoice.py
index 4cdaeab..7f02f07 100644 (file)
@@ -24,8 +24,8 @@ from lxml import etree
 import decimal_precision as dp
 
 import netsvc
-from osv import fields, osv, orm
 import pooler
+from osv import fields, osv, orm
 from tools.translate import _
 
 class account_invoice(osv.osv):
@@ -57,17 +57,13 @@ class account_invoice(osv.osv):
                                             ('company_id', '=', company_id),
                                             ('refund_journal', '=', refund_journal.get(type_inv, False))],
                                                 limit=1)
-        if res:
-            return res[0]
-        else:
-            return False
+        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])[0]
+        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
-        else:
-            return pooler.get_pool(cr.dbname).get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
+        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'}
@@ -92,50 +88,14 @@ class account_invoice(osv.osv):
         return [('none', _('Free Reference'))]
 
     def _amount_residual(self, cr, uid, ids, name, args, context=None):
-        res = {}
-        cur_obj = self.pool.get('res.currency')
-        data_inv = self.browse(cr, uid, ids)
-        if context is None:
-            context = {}
-
-        for inv in data_inv:
-            debit = credit = 0.0
-            context.update({'date':inv.date_invoice})
-            context_unreconciled=context.copy()
-            for lines in inv.move_lines:
-                debit_tmp = lines.debit
-                credit_tmp = lines.credit
-                # If currency conversion needed
-                if inv.company_id.currency_id.id <> inv.currency_id.id:
-                    # If invoice paid, compute currency amount according to invoice date
-                    # otherwise, take the line date
-                    if not inv.reconciled:
-                        context.update({'date':lines.date})
-                    context_unreconciled.update({'date':lines.date})
-                    # If amount currency setted, compute for debit and credit in company currency
-                    if lines.amount_currency < 0:
-                        credit_tmp=abs(cur_obj.compute(cr, uid, lines.currency_id.id, inv.company_id.currency_id.id, lines.amount_currency, round=False, context=context_unreconciled))
-                    elif lines.amount_currency > 0:
-                        debit_tmp=abs(cur_obj.compute(cr, uid, lines.currency_id.id, inv.company_id.currency_id.id, lines.amount_currency, round=False, context=context_unreconciled))
-                    # Then, recomput into invoice currency to avoid rounding trouble !
-                    debit += cur_obj.compute(cr, uid, inv.company_id.currency_id.id, inv.currency_id.id, debit_tmp, round=False, context=context)
-                    credit += cur_obj.compute(cr, uid, inv.company_id.currency_id.id, inv.currency_id.id, credit_tmp, round=False, context=context)
-                else:
-                    debit+=debit_tmp
-                    credit+=credit_tmp
-
-            if not inv.amount_total:
-                result = 0.0
-            elif inv.type in ('out_invoice','in_refund'):
-                amount = credit-debit
-                result = inv.amount_total - amount
-            else:
-                amount = debit-credit
-                result = inv.amount_total - amount
-            # Use is_zero function to avoid rounding trouble => should be fixed into ORM
-            res[inv.id] = not self.pool.get('res.currency').is_zero(cr, uid, inv.company_id.currency_id, result) and result or 0.0
-
-        return res
+        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
@@ -173,7 +133,7 @@ class account_invoice(osv.osv):
 
     def _compute_lines(self, cr, uid, ids, name, args, context=None):
         result = {}
-        for invoice in self.browse(cr, uid, ids, context):
+        for invoice in self.browse(cr, uid, ids, context=context):
             src = []
             lines = []
             if invoice.move_id:
@@ -192,7 +152,7 @@ class account_invoice(osv.osv):
 
     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):
+        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
@@ -206,7 +166,7 @@ class account_invoice(osv.osv):
 
     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):
+        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:
@@ -251,8 +211,8 @@ class account_invoice(osv.osv):
             \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)]}, help="Keep empty to use the current date"),
-        'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]},
+        '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)]}),
@@ -268,26 +228,26 @@ class account_invoice(osv.osv):
         '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, help="Link to the automatically generated Journal Items."),
+        '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, method=True, 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'], 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, method=True, 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'], 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, method=True, 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'], 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)]}),
@@ -305,9 +265,9 @@ class account_invoice(osv.osv):
         'move_lines':fields.function(_get_lines, method=True, type='many2many', relation='account.move.line', string='Entry Lines'),
         'residual': fields.function(_amount_residual, method=True, digits_compute=dp.get_precision('Account'), string='Residual',
             store={
-                'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 50),
+                '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'], 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),
             },
@@ -331,17 +291,23 @@ class account_invoice(osv.osv):
 
     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.get('active_model','') in ['res.partner']:
-            partner = self.pool.get(context['active_model']).read(cr,uid,context['active_ids'],['supplier','customer'])[0]
+        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')])[0]
+                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')])[0]
+                    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')])[0]
+                    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':
@@ -351,7 +317,7 @@ class account_invoice(osv.osv):
         if view_type == 'tree':
             doc = etree.XML(res['arch'])
             nodes = doc.xpath("//field[@name='partner_id']")
-            partner_string = 'Customer'
+            partner_string = _('Customer')
             if context.get('type', 'out_invoice') in ('in_invoice', 'in_refund'):
                 partner_string = _('Supplier')
             for node in nodes:
@@ -359,26 +325,46 @@ class account_invoice(osv.osv):
             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):
-                message = _('Invoice ') + " '" + name + "' "+ _("is waiting for validation.")
-                self.log(cr, uid, inv_id, message)
+                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(_('UnknownError'), str(e))
+                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):
-        invoices = self.read(cr, uid, ids, ['state'])
+        if context is None:
+            context = {}
+        invoices = self.read(cr, uid, ids, ['state'], context=context)
         unlink_ids = []
         for t in invoices:
             if t['state'] in ('draft', 'cancel'):
@@ -461,14 +447,6 @@ class account_invoice(osv.osv):
             result['value'].update(to_update['value'])
         return result
 
-    def onchange_currency_id(self, cr, uid, ids, curr_id, company_id):
-        if curr_id and company_id:
-            currency = self.pool.get('res.currency').browse(cr, uid, curr_id)
-            if currency.company_id.id != company_id:
-                raise osv.except_osv(_('Configuration Error !'),
-                        _('Can not select currency that is not related to current company.\nPlease select accordingly !.'))
-        return {}
-
     def onchange_journal_id(self, cr, uid, ids, journal_id=False):
         result = {}
         if journal_id:
@@ -496,7 +474,6 @@ class account_invoice(osv.osv):
             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):
@@ -509,6 +486,8 @@ class account_invoice(osv.osv):
         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)
@@ -533,7 +512,6 @@ class account_invoice(osv.osv):
                     else:
                         acc_id = pay_res_id
                     val= {'account_id': acc_id}
-            account_obj = self.pool.get('account.account')
             if ids:
                 if company_id:
                     inv_obj = self.browse(cr,uid,ids)
@@ -544,7 +522,7 @@ class account_invoice(osv.osv):
                                 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.'))
-                                self.pool.get('account.invoice.line').write(cr, uid, [line.id], {'account_id': result_id[0]})
+                                inv_line_obj.write(cr, uid, [line.id], {'account_id': result_id[0]})
             else:
                 if invoice_line:
                     for inv_line in invoice_line:
@@ -566,8 +544,12 @@ class account_invoice(osv.osv):
             journal_ids = obj_journal.search(cr, uid, [('company_id','=',company_id), ('type', '=', journal_type)])
             if journal_ids:
                 val['journal_id'] = journal_ids[0]
-            else:
-                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)))
+            res_journal_default = self.pool.get('ir.values').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, [])
@@ -584,14 +566,14 @@ class account_invoice(osv.osv):
                 val['currency_id'] = False
             else:
                 val['currency_id'] = company.currency_id.id
-
-        return {'value': val, 'domain': dom }
+        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
 
@@ -620,12 +602,15 @@ class account_invoice(osv.osv):
         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,
+            'period_id': False
         })
         if 'date_invoice' not in default:
             default.update({
@@ -653,7 +638,7 @@ class account_invoice(osv.osv):
         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", (id,))
+            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})
@@ -665,7 +650,7 @@ class account_invoice(osv.osv):
 
     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):
+        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
@@ -674,7 +659,7 @@ class account_invoice(osv.osv):
         return (ref or '').replace('/','')
 
     def _get_analytic_lines(self, cr, uid, id):
-        inv = self.browse(cr, uid, [id])[0]
+        inv = self.browse(cr, uid, id)
         cur_obj = self.pool.get('res.currency')
 
         company_currency = inv.company_id.currency_id.id
@@ -690,6 +675,8 @@ class account_invoice(osv.osv):
                     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'],
@@ -699,7 +686,7 @@ class account_invoice(osv.osv):
                     'product_id': il['product_id'],
                     'product_uom_id': il['uos_id'],
                     'general_account_id': il['account_id'],
-                    'journal_id': self._get_journal_analytic(cr, uid, inv.type),
+                    'journal_id': inv.journal_id.analytic_journal_id.id,
                     'ref': ref,
                 })]
         return iml
@@ -795,7 +782,6 @@ class account_invoice(osv.osv):
             line = []
             for key, val in line2.items():
                 line.append((0,0,val))
-
         return line
 
     def action_move_create(self, cr, uid, ids, *args):
@@ -818,9 +804,9 @@ class account_invoice(osv.osv):
             # one move line per invoice line
             iml = self._get_analytic_lines(cr, uid, inv.id)
             # check if taxes are all computed
-
-            context.update({'lang': inv.partner_id.lang})
-            compute_taxes = ait_obj.compute(cr, uid, inv.id, context=context)
+            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):
@@ -833,7 +819,7 @@ class account_invoice(osv.osv):
                         total_fixed += line.value_amount
                     if line.value == 'procent':
                         total_percent += line.value_amount
-                total_fixed = (total_fixed * 100) / inv.amount_total
+                total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0)
                 if (total_fixed + total_percent) > 100:
                     raise osv.except_osv(_('Error !'), _("Cannot create the invoice !\nThe payment term defined gives a computed amount greater than the total invoiced amount."))
 
@@ -931,7 +917,7 @@ class account_invoice(osv.osv):
             }
             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'))])
+                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:
@@ -952,29 +938,31 @@ class account_invoice(osv.osv):
     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],
+            '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),
+            '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),
+            'ref': x.get('ref', False),
+            'quantity': x.get('quantity',1.00),
+            'product_id': x.get('product_id', False),
+            'product_uom_id': x.get('uos_id', False),
+            'analytic_account_id': x.get('account_analytic_id', False),
         }
 
-    def action_number(self, cr, uid, ids, *args):
+    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):
+        for obj_inv in self.browse(cr, uid, ids, context=context):
             id = obj_inv.id
             invtype = obj_inv.type
             number = obj_inv.number
@@ -984,7 +972,10 @@ class account_invoice(osv.osv):
             self.write(cr, uid, ids, {'internal_number':number})
 
             if invtype in ('in_invoice', 'in_refund'):
-                ref = reference
+                if not reference:
+                    ref = self._convert_ref(cr, uid, number)
+                else:
+                    ref = reference
             else:
                 ref = self._convert_ref(cr, uid, number)
 
@@ -1001,21 +992,21 @@ class account_invoice(osv.osv):
                         (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 ') + " '" + name + "' "+ _("is validated.")
-                self.log(cr, uid, inv_id, message)
-
+                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']:
-                account_move_obj.button_cancel(cr, uid, [i['move_id'][0]])
-                # 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, [i['move_id'][0]])
+                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'])
@@ -1023,7 +1014,15 @@ class account_invoice(osv.osv):
                     if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids:
                         raise osv.except_osv(_('Error !'), _('You cannot cancel the Invoice which is Partially Paid! You need to unreconcile concerned payment entries!'))
 
+        # 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
 
@@ -1051,7 +1050,7 @@ class account_invoice(osv.osv):
                 'out_refund': 'OR: ',
                 'in_refund': 'SR: ',
                 }
-        return [(r['id'], types[r['type']]+(r['number'] or '')+' '+(r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
+        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:
@@ -1060,9 +1059,9 @@ class account_invoice(osv.osv):
             context = {}
         ids = []
         if name:
-            ids = self.search(cr, user, [('number','=',name)]+ args, limit=limit, context=context)
+            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)
+            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):
@@ -1130,6 +1129,7 @@ class account_invoice(osv.osv):
                 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=''):
@@ -1137,7 +1137,7 @@ class account_invoice(osv.osv):
             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])
+        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}
@@ -1218,17 +1218,19 @@ class account_invoice(osv.osv):
 
         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.log(cr, uid, inv_id, _('Invoice ') + " '" + name + "' "+ _("is totally paid."))
             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.code
-            amt = str(pay_amount) + code + ' on ' + str(invoice.amount_total) + code + ' (' + str(total) + code + ' remaining)'
-            self.log(cr, uid, inv_id, _('Invoice ') + " '" + name + "' "+ _("is paid partially: ") + amt)
+            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):
@@ -1257,7 +1259,7 @@ class account_invoice_line(osv.osv):
                     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, 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
@@ -1280,7 +1282,7 @@ class account_invoice_line(osv.osv):
         '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),
+        '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 = {
@@ -1289,14 +1291,6 @@ class account_invoice_line(osv.osv):
         'price_unit': _price_unit_default,
     }
 
-    def product_id_change_unit_price_inv(self, cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=None):
-        tax_obj = self.pool.get('account.tax')
-        if price_unit:
-            taxes = tax_obj.browse(cr, uid, tax_id)
-            for tax in tax_obj.compute_inv(cr, uid, taxes, price_unit, qty, address_invoice_id, product, partner_id):
-                price_unit = price_unit - tax['amount']
-        return {'price_unit': price_unit,'invoice_line_tax_id': tax_id}
-
     def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, currency_id=False, context=None):
         if context is None:
             context = {}
@@ -1304,78 +1298,16 @@ class account_invoice_line(osv.osv):
         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)
+            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) or False
+        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 company_id:
-            property_obj = self.pool.get('ir.property')
-            account_obj = self.pool.get('account.account')
-            in_pro_id = property_obj.search(cr, uid, [('name','=','property_account_income'),('res_id','=','product.template,'+str(res.product_tmpl_id.id)+''),('company_id','=',company_id)])
-            if not in_pro_id:
-                in_pro_id = property_obj.search(cr, uid, [('name','=','property_account_income_categ'),('res_id','=','product.template,'+str(res.categ_id.id)+''),('company_id','=',company_id)])
-            exp_pro_id = property_obj.search(cr, uid, [('name','=','property_account_expense'),('res_id','=','product.template,'+str(res.product_tmpl_id.id)+''),('company_id','=',company_id)])
-            if not exp_pro_id:
-                exp_pro_id = property_obj.search(cr, uid, [('name','=','property_account_expense_categ'),('res_id','=','product.template,'+str(res.categ_id.id)+''),('company_id','=',company_id)])
-
-            if not in_pro_id:
-                in_acc = res.product_tmpl_id.property_account_income
-                in_acc_cate = res.categ_id.property_account_income_categ
-                if in_acc:
-                    app_acc_in = in_acc
-                else:
-                    app_acc_in = in_acc_cate
-            else:
-                # Get the fields from the ir.property record
-                my_value = property_obj.read(cr,uid,in_pro_id,['name','value_reference','res_id'])
-                # Parse the value_reference field to get the ID of the account.account record
-                account_id = int (my_value[0]["value_reference"].split(",")[1])
-                # Use the ID of the account.account record in the browse for the account.account record
-                app_acc_in = account_obj.browse(cr, uid, [account_id])[0]
-            if not exp_pro_id:
-                ex_acc = res.product_tmpl_id.property_account_expense
-                ex_acc_cate = res.categ_id.property_account_expense_categ
-                if ex_acc:
-                    app_acc_exp = ex_acc
-                else:
-                    app_acc_exp = ex_acc_cate
-            else:
-                app_acc_exp = account_obj.browse(cr, uid, exp_pro_id)[0]
-            if not in_pro_id and not exp_pro_id:
-                in_acc = res.product_tmpl_id.property_account_income
-                in_acc_cate = res.categ_id.property_account_income_categ
-                ex_acc = res.product_tmpl_id.property_account_expense
-                ex_acc_cate = res.categ_id.property_account_expense_categ
-                if in_acc or ex_acc:
-                    app_acc_in = in_acc
-                    app_acc_exp = ex_acc
-                else:
-                    app_acc_in = in_acc_cate
-                    app_acc_exp = ex_acc_cate
-            if app_acc_in.company_id.id != company_id and app_acc_exp.company_id.id != company_id:
-                in_res_id = account_obj.search(cr, uid, [('name','=',app_acc_in.name),('company_id','=',company_id)])
-                exp_res_id = account_obj.search(cr, uid, [('name','=',app_acc_exp.name),('company_id','=',company_id)])
-                if not in_res_id and not exp_res_id:
-                    raise osv.except_osv(_('Configuration Error !'),
-                        _('Can not find account chart for this company, Please Create account.'))
-                in_obj_acc = account_obj.browse(cr, uid, in_res_id)
-                exp_obj_acc = account_obj.browse(cr, uid, exp_res_id)
-                if in_acc or ex_acc:
-                    res.product_tmpl_id.property_account_income = in_obj_acc[0]
-                    res.product_tmpl_id.property_account_expense = exp_obj_acc[0]
-                else:
-                    res.categ_id.property_account_income_categ = in_obj_acc[0]
-                    res.categ_id.property_account_expense_categ = exp_obj_acc[0]
-
         if type in ('out_invoice','out_refund'):
             a = res.product_tmpl_id.property_account_income.id
             if not a:
@@ -1384,28 +1316,25 @@ class account_invoice_line(osv.osv):
             a = res.product_tmpl_id.property_account_expense.id
             if not a:
                 a = res.categ_id.property_account_expense_categ.id
-
         a = 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).tax_ids or False)
-            tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
+            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).tax_ids or False)
-            tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
+            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'):
-            to_update = self.product_id_change_unit_price_inv(cr, uid, tax_id, price_unit or res.standard_price, qty, address_invoice_id, product, partner_id, context=context)
-            result.update(to_update)
+            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})
-
-#        if not name:
         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:
@@ -1417,8 +1346,8 @@ class account_invoice_line(osv.osv):
         if not company_id or not currency_id:
             return res_final
 
-        company = self.pool.get('res.company').browse(cr, uid, company_id)
-        currency = self.pool.get('res.currency').browse(cr, uid, currency_id)
+        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:
             new_price = res_final['value']['price_unit'] * currency.rate
@@ -1432,18 +1361,30 @@ class account_invoice_line(osv.osv):
         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):
-        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)
+        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')
-        inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id)
+        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:
@@ -1500,8 +1441,8 @@ class account_invoice_line(osv.osv):
         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)
-        r = {'value':{'invoice_line_tax_id': res}}
-        return r
+        return {'value':{'invoice_line_tax_id': res}}
+
 account_invoice_line()
 
 class account_invoice_tax(osv.osv):
@@ -1533,12 +1474,11 @@ class account_invoice_tax(osv.osv):
         '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),
+        '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, method=True, string='Multipication factor for Base code', type='float', multi="all"),
         'factor_tax': fields.function(_count_factor, method=True, string='Multipication factor Tax code', type='float', multi="all")
     }
@@ -1571,15 +1511,15 @@ class account_invoice_tax(osv.osv):
 
     _order = 'sequence'
     _defaults = {
-        'manual': lambda *a: 1,
-        'base_amount': lambda *a: 0.0,
-        'tax_amount': lambda *a: 0.0,
+        'manual': 1,
+        'base_amount': 0.0,
+        'tax_amount': 0.0,
     }
-    def compute(self, cr, uid, invoice_id, context={}):
+    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)
+        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
 
@@ -1641,6 +1581,7 @@ class account_invoice_tax(osv.osv):
                 'tax_amount': t['tax_amount']
             })
         return res
+
 account_invoice_tax()