[merge]
[odoo/odoo.git] / addons / account / invoice.py
index b810ef0..dcc7383 100644 (file)
 ##############################################################################
 
 import time
+from operator import itemgetter
+import decimal_precision as dp
+
 import netsvc
-from osv import fields, osv
-import ir
+from osv import fields, osv, orm
 import pooler
-import mx.DateTime
-from mx.DateTime import RelativeDateTime
 from tools import config
 from tools.translate import _
 
-class fiscalyear_seq(osv.osv):
-    _name = "fiscalyear.seq"
-    _description = "Maintains Invoice sequences with Fiscal Year"
-    _rec_name = 'fiscalyear_id'
-    _columns = {
-        'journal_id': fields.many2one('account.journal', 'Journal'),
-        'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year',required=True),
-        'sequence_id':fields.many2one('ir.sequence', 'Sequence',required=True),
-    }
-
-fiscalyear_seq()
-
 class account_invoice(osv.osv):
     def _amount_all(self, cr, uid, ids, name, args, context=None):
         res = {}
-        for invoice in self.browse(cr,uid,ids, context=context):
+        for invoice in self.browse(cr, uid, ids, context=context):
             res[invoice.id] = {
                 'amount_untaxed': 0.0,
                 'amount_tax': 0.0,
@@ -57,23 +45,25 @@ class account_invoice(osv.osv):
             res[invoice.id]['amount_total'] = res[invoice.id]['amount_tax'] + res[invoice.id]['amount_untaxed']
         return res
 
-    def _get_journal(self, cr, uid, context):
+    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)
+        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', 'in_refund': 'purchase'}
+        type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale_refund', 'in_refund': 'purchase_refund'}
+        refund_journal = {'out_invoice': False, 'in_invoice': False, 'out_refund': True, 'in_refund': True}
         journal_obj = self.pool.get('account.journal')
         res = journal_obj.search(cr, uid, [('type', '=', type2journal.get(type_inv, 'sale')),
-                                            ('company_id', '=', company_id)],
+                                            ('company_id', '=', company_id),
+                                            ('refund_journal', '=', refund_journal.get(type_inv, False))],
                                                 limit=1)
         if res:
             return res[0]
         else:
             return False
 
-    def _get_currency(self, cr, uid, context):
+    def _get_currency(self, cr, uid, context=None):
         user = pooler.get_pool(cr.dbname).get('res.users').browse(cr, uid, [uid])[0]
         if user.company_id:
             return user.company_id.currency_id.id
@@ -91,10 +81,9 @@ class account_invoice(osv.osv):
     def _get_type(self, cr, uid, context=None):
         if context is None:
             context = {}
-        type = context.get('type', 'out_invoice')
-        return type
+        return context.get('type', 'out_invoice')
 
-    def _reconciled(self, cr, uid, ids, name, args, context):
+    def _reconciled(self, cr, uid, ids, name, args, context=None):
         res = {}
         for id in ids:
             res[id] = self.test_paid(cr, uid, [id])
@@ -105,8 +94,11 @@ class account_invoice(osv.osv):
 
     def _amount_residual(self, cr, uid, ids, name, args, context=None):
         res = {}
-        data_inv = self.browse(cr, uid, ids)
         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})
@@ -123,12 +115,12 @@ class account_invoice(osv.osv):
                     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))
+                        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))
+                        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)
+                    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
@@ -142,18 +134,20 @@ class account_invoice(osv.osv):
                 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
+            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
 
     def _get_lines(self, cr, uid, ids, name, arg, context=None):
         res = {}
         for id in ids:
-            move_lines = self.move_line_id_payment_get(cr,uid,[id])
+            move_lines = self.move_line_id_payment_get(cr, uid, [id])
             if not move_lines:
                 res[id] = []
                 continue
-            data_lines = self.pool.get('account.move.line').browse(cr,uid,move_lines)
+            res[id] = []
+            data_lines = self.pool.get('account.move.line').browse(cr, uid, move_lines)
+            partial_ids = []# Keeps the track of ids where partial payments are done with payment terms
             for line in data_lines:
                 ids_line = []
                 if line.reconcile_id:
@@ -161,7 +155,8 @@ class account_invoice(osv.osv):
                 elif line.reconcile_partial_id:
                     ids_line = line.reconcile_partial_id.line_partial_ids
                 l = map(lambda x: x.id, ids_line)
-                res[id]=[x for x in l if x <> line.id]
+                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):
@@ -183,16 +178,19 @@ class account_invoice(osv.osv):
             src = []
             lines = []
             for m in self.pool.get('account.move.line').browse(cr, uid, moves, context):
+                temp_lines = []#Added temp list to avoid duplicate records
                 if m.reconcile_id:
-                    lines += map(lambda x: x.id, m.reconcile_id.line_id)
+                    temp_lines = map(lambda x: x.id, m.reconcile_id.line_id)
                 elif m.reconcile_partial_id:
-                    lines += map(lambda x: x.id, m.reconcile_partial_id.line_partial_ids)
+                    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={}):
+    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):
             if line.reconcile_partial_id:
@@ -206,7 +204,7 @@ class account_invoice(osv.osv):
             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={}):
+    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 line in r.line_partial_ids:
@@ -222,9 +220,10 @@ class account_invoice(osv.osv):
     _name = "account.invoice"
     _description = 'Invoice'
     _order = "number"
+    _log_create = True
     _columns = {
-        'name': fields.char('Description', size=64, select=True,readonly=True, states={'draft':[('readonly',False)]}),
-        'origin': fields.char('Origin', size=64, help="Reference of the document that produced this invoice."),
+        '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'),
@@ -235,7 +234,7 @@ class account_invoice(osv.osv):
         '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),
+            required=True, readonly=True, states={'draft':[('readonly',False)]}),
         'comment': fields.text('Additional Information', translate=True),
 
         'state': fields.selection([
@@ -251,8 +250,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 \'Done\' state is set automatically when invoice is paid.\
             \n* The \'Cancelled\' state is used when user cancel invoice.'),
-        'date_invoice': fields.date('Date Invoiced', states={'open':[('readonly',True)],'close':[('readonly',True)]}, help="Keep empty to use the current date"),
-        'date_due': fields.date('Due Date', states={'open':[('readonly',True)],'close':[('readonly',True)]},
+        'date_invoice': fields.date('Date Invoiced', 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)]},
             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)]}),
@@ -269,21 +268,21 @@ class account_invoice(osv.osv):
         'tax_line': fields.one2many('account.invoice.tax', 'invoice_id', 'Tax Lines', readonly=True, states={'draft':[('readonly',False)]}),
 
         'move_id': fields.many2one('account.move', 'Invoice Movement', readonly=True, help="Links to the automatically generated Ledger Postings."),
-        'amount_untaxed': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])),string='Untaxed',
+        '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),
             },
             multi='all'),
-        'amount_tax': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])), string='Tax',
+        '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),
             },
             multi='all'),
-        'amount_total': fields.function(_amount_all, method=True, digits=(16, int(config['price_accuracy'])), string='Total',
+        '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),
@@ -291,9 +290,9 @@ class account_invoice(osv.osv):
             },
             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),
-        'check_total': fields.float('Total', digits=(16, int(config['price_accuracy'])), states={'open':[('readonly',True)],'close':[('readonly',True)]}),
+        '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, method=True, string='Paid/Reconciled', type='boolean',
             store={
                 'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
@@ -301,9 +300,9 @@ class account_invoice(osv.osv):
                 'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
             }, help="The Ledger Postings of the invoice have been reconciled with Ledger Postings of the payment(s)."),
         'partner_bank': fields.many2one('res.partner.bank', 'Bank Account',
-            help='The bank account to pay to or to be paid from'),
-        'move_lines':fields.function(_get_lines , method=True,type='many2many' , relation='account.move.line',string='Entry Lines'),
-        'residual': fields.function(_amount_residual, method=True, digits=(16, int(config['price_accuracy'])),string='Residual',
+            help='The bank account to pay to or to be paid from', readonly=True, states={'draft':[('readonly',False)]}),
+        '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.tax': (_get_invoice_tax, None, 50),
@@ -313,20 +312,53 @@ class account_invoice(osv.osv):
             },
             help="Remaining amount due."),
         'payment_ids': fields.function(_compute_lines, method=True, relation='account.move.line', type="many2many", string='Payments'),
-        'move_name': fields.char('Ledger Posting', size=64),
-        'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position')
+        'move_name': fields.char('Ledger Posting', 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,
         #'date_invoice': lambda *a: time.strftime('%Y-%m-%d'),
-        'state': lambda *a: 'draft',
+        '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': lambda *a: 'none',
-        'check_total': lambda *a: 0.0,
+        'reference_type': 'none',
+        'check_total': 0.0,
+        '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):
+        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 not view_type:
+                view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name','=','account.invoice.tree')])[0]
+                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]
+                else:
+                    view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name','=','account.invoice.form')])[0]
+        return super(account_invoice,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
+
+    def create(self, cr, uid, vals, context=None):
+        try:
+            res = super(account_invoice, self).create(cr, uid, vals, context)
+            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))
+
+    def confirm_paid(self, cr, uid, ids, context=None):
+        self.write(cr, uid, ids, {'state':'paid'}, context=context)
+        for (id, name) in self.name_get(cr, uid, ids):
+            message = _('Document ') + " '" + name + "' "+ _("has been paid.")
+            self.log(cr, uid, id, message)
+        return True
+
     def unlink(self, cr, uid, ids, context=None):
         invoices = self.read(cr, uid, ids, ['state'])
         unlink_ids = []
@@ -342,7 +374,7 @@ class account_invoice(osv.osv):
 #       res = self.pool.get('res.partner').address_get(cr, uid, [part], ['invoice'])
 #       return [{}]
     def onchange_partner_id(self, cr, uid, ids, type, partner_id,
-            date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
+            date_invoice=False, payment_term=False, partner_bank=False, company_id=False):
         invoice_addr_id = False
         contact_addr_id = False
         partner_payment_term = False
@@ -373,8 +405,8 @@ class account_invoice(osv.osv):
                     if not rec_res_id and not pay_res_id:
                         raise osv.except_osv(_('Configration Error !'),
                             _('Can not find account chart for this company, Please Create account.'))
-                    rec_obj_acc=self.pool.get('account.account').browse(cr,uid,[rec_res_id])
-                    pay_obj_acc=self.pool.get('account.account').browse(cr,uid,[pay_res_id])
+                    rec_obj_acc=self.pool.get('account.account').browse(cr, uid, [rec_res_id])
+                    pay_obj_acc=self.pool.get('account.account').browse(cr, uid, [pay_res_id])
                     p.property_account_receivable = rec_obj_acc[0]
                     p.property_account_payable = pay_obj_acc[0]
 
@@ -402,20 +434,20 @@ class account_invoice(osv.osv):
         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)
+                    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:
+        if partner_bank != bank_id:
             to_update = self.onchange_partner_bank(cr, uid, ids, bank_id)
             result['value'].update(to_update['value'])
         return result
 
     def onchange_currency_id(self, cr, uid, ids, curr_id, company_id):
-        if curr_id:
+        if curr_id and company_id:
             currency = self.pool.get('res.currency').browse(cr, uid, curr_id)
-            if currency.company_id != company_id:
+            if currency.company_id.id != company_id:
                 raise osv.except_osv(_('Configration Error !'),
                         _('Can not select currency that is not related to current company.\nPlease select accordingly !.'))
         return {}
@@ -442,25 +474,26 @@ class account_invoice(osv.osv):
     def onchange_invoice_line(self, cr, uid, ids, lines):
         return {}
 
-    def onchange_partner_bank(self, cursor, user, ids, partner_bank_id):
+    def onchange_partner_bank(self, cursor, user, ids, partner_bank):
         return {'value': {}}
 
-    def onchange_company_id(self, cr, uid, ids, company_id, part_id, type, invoice_line):
-        val={}
-        dom={}
+    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')
         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:
-                    rec_pro_id = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
-                    pay_pro_id = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_payable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
+                    rec_pro_id = self.pool.get('ir.property').search(cr, uid, [('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(part_id)+''),('company_id','=',company_id)])
+                    pay_pro_id = self.pool.get('ir.property').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 = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_receivable'),('company_id','=',company_id)])
+                        rec_pro_id = self.pool.get('ir.property').search(cr, uid, [('name','=','property_account_receivable'),('company_id','=',company_id)])
                     if not pay_pro_id:
-                        pay_pro_id = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_payable'),('company_id','=',company_id)])
-                    rec_line_data = self.pool.get('ir.property').read(cr,uid,rec_pro_id,['name','value','res_id'])
-                    pay_line_data = self.pool.get('ir.property').read(cr,uid,pay_pro_id,['name','value','res_id'])
+                        pay_pro_id = self.pool.get('ir.property').search(cr, uid, [('name','=','property_account_payable'),('company_id','=',company_id)])
+                    rec_line_data = self.pool.get('ir.property').read(cr, uid, rec_pro_id, ['name','value','res_id'])
+                    pay_line_data = self.pool.get('ir.property').read(cr, uid, pay_pro_id, ['name','value','res_id'])
                     rec_res_id = rec_line_data and int(rec_line_data[0]['value'].split(',')[1]) or False
                     pay_res_id = pay_line_data and int(pay_line_data[0]['value'].split(',')[1]) or False
                     if not rec_res_id and not rec_res_id:
@@ -477,27 +510,49 @@ class account_invoice(osv.osv):
                     for line in inv_obj[0].invoice_line:
                         if line.account_id:
                             if line.account_id.company_id.id != company_id:
-                                result_id = self.pool.get('account.account').search(cr,uid,[('name','=',line.account_id.name),('company_id','=',company_id)])
+                                result_id = self.pool.get('account.account').search(cr, uid, [('name','=',line.account_id.name),('company_id','=',company_id)])
                                 if not result_id:
                                     raise osv.except_osv(_('Configration Error !'),
                                         _('Can not find account chart for this company in invoice line account, Please Create account.'))
-                                r_id = self.pool.get('account.invoice.line').write(cr,uid,[line.id],{'account_id': result_id[0]})
+                                r_id = self.pool.get('account.invoice.line').write(cr, uid, [line.id], {'account_id': result_id[0]})
             else:
                 if invoice_line:
                     for inv_line in invoice_line:
-                        obj_l = self.pool.get('account.account').browse(cr,uid,inv_line[2]['account_id'])
+                        obj_l = self.pool.get('account.account').browse(cr, uid, inv_line[2]['account_id'])
                         if obj_l.company_id.id != company_id:
                             raise osv.except_osv(_('Configration Error !'),
                                 _('invoice line account company is not match with invoice company.'))
                         else:
                             continue
-        if company_id:
-            val['journal_id']=False
-            journal_ids=self.pool.get('account.journal').search(cr,uid,[('company_id','=',company_id)])
-            dom={'journal_id':  [('id','in',journal_ids)]}
+        if company_id and type:
+            if type in ('out_invoice', 'out_refund'):
+                journal_type = 'sale'
+            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]
+            else:
+                raise osv.except_osv(_('Configration Error !'),
+                                _('Can not find account journal for this company in invoice, Please Create journal.'))
+            dom = {'journal_id':  [('id', 'in', journal_ids)]}
         else:
-            journal_ids=self.pool.get('account.journal').search(cr,uid,[])
-            dom={'journal_id':  [('id','in',journal_ids)]}
+            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.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.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
@@ -508,6 +563,16 @@ class account_invoice(osv.osv):
             wf_service.trg_create(uid, 'account.invoice', inv_id, cr)
         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
+
     # Workflow stuff
     #################
 
@@ -516,12 +581,13 @@ class account_invoice(osv.osv):
     def move_line_id_payment_get(self, cr, uid, ids, *args):
         res = []
         if not ids: return res
-        cr.execute('select \
-                l.id \
-            from account_move_line l \
-                left join account_invoice i on (i.move_id=l.move_id) \
-            where i.id in ('+','.join(map(str,map(int, ids)))+') and l.account_id=i.account_id')
-        res = map(lambda x: x[0], cr.fetchall())
+        cr.execute('SELECT 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),))
+        res = map(itemgetter(0), cr.fetchall())
         return res
 
     def copy(self, cr, uid, id, default=None, context=None):
@@ -551,7 +617,7 @@ class account_invoice(osv.osv):
         ait_obj = self.pool.get('account.invoice.tax')
         for id in ids:
             cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%s", (id,))
-            partner = self.browse(cr, uid, id,context=context).partner_id
+            partner = self.browse(cr, uid, id, context=context).partner_id
             if partner.lang:
                 context.update({'lang': partner.lang})
             for taxe in ait_obj.compute(cr, uid, id, context=context).values():
@@ -609,11 +675,103 @@ class account_invoice(osv.osv):
                 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.invoice_sequence_id:
+                raise osv.except_osv(_('Error !'), _('Please define invoice 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
 
@@ -628,24 +786,7 @@ class account_invoice(osv.osv):
 
             context.update({'lang': inv.partner_id.lang})
             compute_taxes = ait_obj.compute(cr, uid, inv.id, context=context)
-            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 !'))
+            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.'))
@@ -653,33 +794,23 @@ class account_invoice(osv.osv):
             # 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
-            for i in iml:
-                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']
+            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 '/'
@@ -734,36 +865,20 @@ class account_invoice(osv.osv):
 
             line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, part, date, context={})) ,iml)
 
-            if inv.journal_id.group_invoice_lines:
-                line2 = {}
-                for x, y, l in line:
-                    tmp = str(l['account_id'])
-                    tmp += '-'+str(l.get('tax_code_id',"False"))
-                    tmp += '-'+str(l.get('product_id',"False"))
-                    tmp += '-'+str(l.get('analytic_account_id',"False"))
-                    tmp += '-'+str(l.get('date_maturity',"False"))
-
-                    if tmp in line2:
-                        am = line2[tmp]['debit'] - line2[tmp]['credit'] + (l['debit'] - l['credit'])
-                        line2[tmp]['debit'] = (am > 0) and am or 0.0
-                        line2[tmp]['credit'] = (am < 0) and -am or 0.0
-                        line2[tmp]['tax_amount'] += l['tax_amount']
-                        line2[tmp]['analytic_lines'] += l['analytic_lines']
-                    else:
-                        line2[tmp] = l
-                line = []
-                for key, val in line2.items():
-                    line.append((0,0,val))
+            line = self.group_lines(cr, uid, iml, line, inv)
 
             journal_id = inv.journal_id.id #self._get_journal(cr, uid, {'type': inv['type']})
             journal = self.pool.get('account.journal').browse(cr, uid, journal_id)
             if journal.centralisation:
                 raise osv.except_osv(_('UserError'),
                         _('Cannot create invoice move on centralised journal'))
-            move = {'ref': inv.number, 'line_id': line, 'journal_id': journal_id, 'date': date}
+
+            line = self.finalize_invoice_move_lines(cr, uid, inv, line)
+
+            move = {'ref': inv.number, 'line_id': line, 'journal_id': journal_id, 'date': date, 'type': entry_type}
             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'))])
                 if len(period_ids):
                     period_id=period_ids[0]
             if period_id:
@@ -802,14 +917,15 @@ class account_invoice(osv.osv):
 
     def action_number(self, cr, uid, ids, *args):
         cr.execute('SELECT id, type, number, move_id, reference ' \
-                'FROM account_invoice ' \
-                'WHERE id IN ('+','.join(map(str, ids))+')')
+                    'FROM account_invoice ' \
+                    'WHERE id IN %s',
+                    (tuple(ids),))
         obj_inv = self.browse(cr, uid, ids)[0]
         for (id, invtype, number, move_id, reference) in cr.fetchall():
             if not number:
                 if obj_inv.journal_id.invoice_sequence_id:
                     sid = obj_inv.journal_id.invoice_sequence_id.id
-                    number = self.pool.get('ir.sequence').get_id(cr, uid, sid, 'id=%s', {'fiscalyear_id': obj_inv.period_id.fiscalyear_id.id})
+                    number = self.pool.get('ir.sequence').get_id(cr, uid, sid, 'id', {'fiscalyear_id': obj_inv.period_id.fiscalyear_id.id})
                 else:
                     number = self.pool.get('ir.sequence').get(cr, uid,
                             'account.invoice.' + invtype)
@@ -834,7 +950,7 @@ class account_invoice(osv.osv):
 
     def action_cancel(self, cr, uid, ids, *args):
         account_move_obj = self.pool.get('account.move')
-        invoices = self.read(cr, uid, ids, ['move_id'])
+        invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids'])
         for i in invoices:
             if i['move_id']:
                 account_move_obj.button_cancel(cr, uid, [i['move_id'][0]])
@@ -842,8 +958,15 @@ class account_invoice(osv.osv):
                 # Note that the corresponding move_lines and move_reconciles
                 # will be automatically deleted too
                 account_move_obj.unlink(cr, uid, [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 cannot cancel the Invoice which is Partially Paid! You need to unreconcile concerned payment entries!'))
+
         self.write(cr, uid, ids, {'state':'cancel', 'move_id':False})
-        self._log_event(cr, uid, ids,-1.0, 'Cancel Invoice')
+        self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice')
         return True
 
     ###################
@@ -858,23 +981,8 @@ class account_invoice(osv.osv):
         return taxes.values()
 
     def _log_event(self, cr, uid, ids, factor=1.0, name='Open Invoice'):
-        invs = self.read(cr, uid, ids, ['type','partner_id','amount_untaxed'])
-        for inv in invs:
-            part=inv['partner_id'] and inv['partner_id'][0]
-            pc = pr = 0.0
-            cr.execute('select sum(quantity*price_unit) from account_invoice_line where invoice_id=%s', (inv['id'],))
-            total = inv['amount_untaxed']
-            if inv['type'] in ('in_invoice','in_refund'):
-                partnertype='supplier'
-                eventtype = 'purchase'
-                pc = total*factor
-            else:
-                partnertype = 'customer'
-                eventtype = 'sale'
-                pr = total*factor
-            if self.pool.get('res.partner.event.type').check(cr, uid, 'invoice_open'):
-                self.pool.get('res.partner.event').create(cr, uid, {'name':'Invoice: '+name, 'som':False, 'description':name+' '+str(inv['id']), 'document':name, 'partner_id':part, 'date':time.strftime('%Y-%m-%d %H:%M:%S'), 'canal_id':False, 'user_id':uid, 'partner_type':partnertype, 'probability':1.0, 'planned_revenue':pr, 'planned_cost':pc, 'type':eventtype})
-        return len(invs)
+        #TODO: implement messages system
+        return True
 
     def name_get(self, cr, uid, ids, context=None):
         if not len(ids):
@@ -942,6 +1050,10 @@ class account_invoice(osv.osv):
             tax_lines = self.pool.get('account.invoice.tax').read(cr, uid, invoice['tax_line'])
             tax_lines = filter(lambda l: l['manual'], tax_lines)
             tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines)
+            if invoice['type'] == 'in_invoice':
+                refund_journal_ids = self.pool.get('account.journal').search(cr, uid, [('type','=','purchase_refund')])
+            else:
+                refund_journal_ids = self.pool.get('account.journal').search(cr, uid, [('type','=','sale_refund')])
             if not date :
                 date = time.strftime('%Y-%m-%d')
             invoice.update({
@@ -950,7 +1062,8 @@ class account_invoice(osv.osv):
                 'state': 'draft',
                 'number': False,
                 'invoice_line': invoice_lines,
-                'tax_line': tax_lines
+                'tax_line': tax_lines,
+                'journal_id': refund_journal_ids
             })
             if period_id :
                 invoice.update({
@@ -992,13 +1105,25 @@ class account_invoice(osv.osv):
             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':invoice.number,
+            'ref':ref,
             'date': date,
             'currency_id':currency_id,
             'amount_currency':amount_currency and direction * amount_currency or 0.0,
@@ -1009,7 +1134,7 @@ class account_invoice(osv.osv):
             'credit': direction * pay_amount>0 and direction * pay_amount,
             'account_id': pay_account_id,
             'partner_id': invoice.partner_id.id,
-            'ref':invoice.number,
+            'ref':ref,
             'date': date,
             'currency_id':currency_id,
             'amount_currency':amount_currency and - direction * amount_currency or 0.0,
@@ -1022,7 +1147,7 @@ class account_invoice(osv.osv):
         l2['name'] = name
 
         lines = [(0, 0, l1), (0, 0, l2)]
-        move = {'ref': invoice.number, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date}
+        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 = []
@@ -1031,13 +1156,15 @@ class account_invoice(osv.osv):
         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 = ANY(%s)',(move_ids,))
+        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)
-        if (not round(total,int(config['price_accuracy']))) or writeoff_acc_id:
+        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:
             self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context)
@@ -1048,19 +1175,19 @@ class account_invoice(osv.osv):
 account_invoice()
 
 class account_invoice_line(osv.osv):
-    def _amount_line(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+    def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict):
         res = {}
-        cur_obj=self.pool.get('res.currency')
+        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)
+            res[line.id] = taxes['total']
             if line.invoice_id:
-                res[line.id] = line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0)
                 cur = line.invoice_id.currency_id
                 res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
-            else:
-                res[line.id] = round(line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0),int(config['price_accuracy']))
         return res
 
-
     def _price_unit_default(self, cr, uid, context=None):
         if context is None:
             context = {}
@@ -1073,14 +1200,14 @@ 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])
-                        for tax in tax_obj.compute(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 = tax_obj.browse(cr, uid, 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"
+    _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."),
@@ -1088,18 +1215,20 @@ class account_invoice_line(osv.osv):
         '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=(16, int(config['price_accuracy']))),
-        'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',store=True, type="float", digits=(16, int(config['price_accuracy']))),
+        'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')),
+        'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', type="float",
+            digits_compute= dp.get_precision('Account'), store=True),
         'quantity': fields.float('Quantity', required=True),
-        'discount': fields.float('Discount (%)', digits=(16, int(config['price_accuracy']))),
+        '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', translate=True),
         '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),
+        'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
     }
     _defaults = {
-        'quantity': lambda *a: 1,
-        'discount': lambda *a: 0.0,
+        'quantity': 1,
+        'discount': 0.0,
         'price_unit': _price_unit_default,
     }
 
@@ -1112,6 +1241,7 @@ class account_invoice_line(osv.osv):
         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):
+        print "2222*", uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context
         if context is None:
             context = {}
         company_id = context.get('company_id',False)
@@ -1125,18 +1255,18 @@ class account_invoice_line(osv.osv):
         part = self.pool.get('res.partner').browse(cr, uid, partner_id)
         fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
 
-        lang=part.lang
-        context.update({'lang': lang})
+        if part.lang:
+            context.update({'lang': part.lang})
         result = {}
         res = self.pool.get('product.product').browse(cr, uid, product, context=context)
 
         if company_id:
-            in_pro_id = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_income'),('res_id','=','product.template,'+str(res.product_tmpl_id.id)+''),('company_id','=',company_id)])
+            in_pro_id = self.pool.get('ir.property').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 = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_income_categ'),('res_id','=','product.template,'+str(res.categ_id.id)+''),('company_id','=',company_id)])
-            exp_pro_id = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_expense'),('res_id','=','product.template,'+str(res.product_tmpl_id.id)+''),('company_id','=',company_id)])
+                in_pro_id = self.pool.get('ir.property').search(cr, uid, [('name','=','property_account_income_categ'),('res_id','=','product.template,'+str(res.categ_id.id)+''),('company_id','=',company_id)])
+            exp_pro_id = self.pool.get('ir.property').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 = self.pool.get('ir.property').search(cr,uid,[('name','=','property_account_expense_categ'),('res_id','=','product.template,'+str(res.categ_id.id)+''),('company_id','=',company_id)])
+                exp_pro_id = self.pool.get('ir.property').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
@@ -1146,7 +1276,7 @@ class account_invoice_line(osv.osv):
                 else:
                     app_acc_in = in_acc_cate
             else:
-                app_acc_in = self.pool.get('account.account').browse(cr,uid,in_pro_id)[0]
+                app_acc_in = self.pool.get('account.account').browse(cr, uid, in_pro_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
@@ -1155,7 +1285,7 @@ class account_invoice_line(osv.osv):
                 else:
                     app_acc_exp = ex_acc_cate
             else:
-                app_acc_exp = self.pool.get('account.account').browse(cr,uid,exp_pro_id)[0]
+                app_acc_exp = self.pool.get('account.account').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
@@ -1171,13 +1301,13 @@ class account_invoice_line(osv.osv):
 #                app_acc_in = self.pool.get('account.account').browse(cr,uid,in_pro_id)[0]
 #                app_acc_exp = self.pool.get('account.account').browse(cr,uid,exp_pro_id)[0]
             if app_acc_in.company_id.id != company_id and app_acc_exp.company_id.id != company_id:
-                in_res_id=self.pool.get('account.account').search(cr,uid,[('name','=',app_acc_in.name),('company_id','=',company_id)])
-                exp_res_id=self.pool.get('account.account').search(cr,uid,[('name','=',app_acc_exp.name),('company_id','=',company_id)])
+                in_res_id=self.pool.get('account.account').search(cr, uid, [('name','=',app_acc_in.name),('company_id','=',company_id)])
+                exp_res_id=self.pool.get('account.account').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(_('Configration Error !'),
                         _('Can not find account chart for this company, Please Create account.'))
-                in_obj_acc=self.pool.get('account.account').browse(cr,uid,in_res_id)
-                exp_obj_acc=self.pool.get('account.account').browse(cr,uid,exp_res_id)
+                in_obj_acc=self.pool.get('account.account').browse(cr, uid, in_res_id)
+                exp_obj_acc=self.pool.get('account.account').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]
@@ -1201,22 +1331,22 @@ class account_invoice_line(osv.osv):
         taxep=None
         tax_obj = self.pool.get('account.tax')
         if type in ('out_invoice', 'out_refund'):
-            taxes = res.taxes_id and res.taxes_id or (a and self.pool.get('account.account').browse(cr, uid,a).tax_ids or False)
+            taxes = res.taxes_id and res.taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a).tax_ids or False)
             tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
         else:
-            taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid,a).tax_ids or False)
+            taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a).tax_ids or False)
             tax_id = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
         if type in ('in_invoice', 'in_refund'):
-            to_update = self.product_id_change_unit_price_inv(cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=context)
+            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)
         else:
             result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
 
         if not name:
-            result['name'] = res.name
+            result['name'] = res.partner_ref
 
         domain = {}
-        result['uos_id'] = uom or res.uom_id.id or False
+        result['uos_id'] = res.uom_id.id or uom or False
         if result['uos_id']:
             res2 = res.uom_id.category_id.id
             if res2 :
@@ -1231,16 +1361,30 @@ class account_invoice_line(osv.osv):
 
         company = self.pool.get('res.company').browse(cr, uid, company_id)
         currency = self.pool.get('res.currency').browse(cr, uid, currency_id)
-        
+
         if not currency.company_id.id == company.id:
             raise osv.except_osv(_('Configration Error !'),
                         _('Can not select currency that is not related to any company.\nPlease select accordingly !.'))
-        
+
         if company.currency_id.id != currency.id:
             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):
+        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)
+        if 'uos_id' in res['value']:
+            del res['value']['uos_id']
+        if not uom:
+            res['value']['price_unit'] = 0.0
+        return res
+
     def move_line_get(self, cr, uid, invoice_id, context=None):
         res = []
         tax_grouped = {}
@@ -1257,10 +1401,10 @@ class account_invoice_line(osv.osv):
                 continue
             res.append(mres)
             tax_code_found= False
-            for tax in tax_obj.compute(cr, uid, line.invoice_line_tax_id,
+            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):
+                    inv.partner_id)['taxes']:
 
                 if inv.type in ('out_invoice', 'in_invoice'):
                     tax_code_id = tax['base_code_id']
@@ -1316,34 +1460,34 @@ class account_invoice_tax(osv.osv):
         '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=(16,int(config['price_accuracy']))),
-        'amount': fields.float('Amount', digits=(16,int(config['price_accuracy']))),
+        '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=(16,int(config['price_accuracy']))),
+        '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=(16,int(config['price_accuracy']))),
-        'company_id': fields.related('account_id','company_id',type='many2one',relation='res.company',string='Company',store=True),
+        '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),
     }
 
-    def base_change(self, cr, uid, ids, base,currency_id=False,company_id=False,date_invoice=False):
+    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
         if company_id:
-            company_currency = company_obj.read(cr,uid,[company_id],['currency_id'])[0]['currency_id'][0]
+            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, 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):
+    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
         if company_id:
-            company_currency = company_obj.read(cr,uid,[company_id],['currency_id'])[0]['currency_id'][0]
+            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, context={'date': date_invoice or time.strftime('%Y-%m-%d')}, round=False)
         return {'value': {'tax_amount':amount}}
@@ -1363,7 +1507,7 @@ class account_invoice_tax(osv.osv):
         company_currency = inv.company_id.currency_id.id
 
         for line in inv.invoice_line:
-            for tax in tax_obj.compute(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):
+            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']
@@ -1421,5 +1565,14 @@ class account_invoice_tax(osv.osv):
         return res
 account_invoice_tax()
 
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
+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),
+    }
+
+res_partner()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: