2011-09-13 10:46:53 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-13 05:41:16 +00:00
#
2008-11-06 07:29:50 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-13 05:41:16 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
import time
2010-10-08 11:28:58 +00:00
from lxml import etree
2012-12-17 15:23:03 +00:00
import openerp . addons . decimal_precision as dp
2013-02-27 08:38:20 +00:00
import openerp . exceptions
2010-03-06 20:52:19 +00:00
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv , orm
from openerp . tools . translate import _
2007-05-11 11:52:16 +00:00
2006-12-07 13:41:40 +00:00
class account_invoice ( osv . osv ) :
2009-01-06 13:31:53 +00:00
def _amount_all ( self , cr , uid , ids , name , args , context = None ) :
2008-07-22 15:11:28 +00:00
res = { }
2010-06-16 11:51:39 +00:00
for invoice in self . browse ( cr , uid , ids , context = context ) :
2008-12-07 02:15:41 +00:00
res [ invoice . id ] = {
' amount_untaxed ' : 0.0 ,
' amount_tax ' : 0.0 ,
' amount_total ' : 0.0
}
for line in invoice . invoice_line :
res [ invoice . id ] [ ' amount_untaxed ' ] + = line . price_subtotal
for line in invoice . tax_line :
res [ invoice . id ] [ ' amount_tax ' ] + = line . amount
res [ invoice . id ] [ ' amount_total ' ] = res [ invoice . id ] [ ' amount_tax ' ] + res [ invoice . id ] [ ' amount_untaxed ' ]
2008-07-22 15:11:28 +00:00
return res
2010-07-02 10:55:58 +00:00
def _get_journal ( self , cr , uid , context = None ) :
2009-01-06 13:31:53 +00:00
if context is None :
context = { }
2008-07-22 15:11:28 +00:00
type_inv = context . get ( ' type ' , ' out_invoice ' )
2010-07-02 10:55:58 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
2009-12-02 11:20:06 +00:00
company_id = context . get ( ' company_id ' , user . company_id . id )
2010-06-18 09:33:36 +00:00
type2journal = { ' out_invoice ' : ' sale ' , ' in_invoice ' : ' purchase ' , ' out_refund ' : ' sale_refund ' , ' in_refund ' : ' purchase_refund ' }
2008-07-22 15:11:28 +00:00
journal_obj = self . pool . get ( ' account.journal ' )
2013-03-08 13:02:27 +00:00
domain = [ ( ' company_id ' , ' = ' , company_id ) ]
if isinstance ( type_inv , list ) :
domain . append ( ( ' type ' , ' in ' , [ type2journal . get ( type ) for type in type_inv if type2journal . get ( type ) ] ) )
else :
domain . append ( ( ' type ' , ' = ' , type2journal . get ( type_inv , ' sale ' ) ) )
res = journal_obj . search ( cr , uid , domain , limit = 1 )
2010-10-20 04:44:12 +00:00
return res and res [ 0 ] or False
2008-07-22 15:11:28 +00:00
2012-02-01 16:06:48 +00:00
def _get_currency ( self , cr , uid , context = None ) :
res = False
journal_id = self . _get_journal ( cr , uid , context = context )
if journal_id :
journal = self . pool . get ( ' account.journal ' ) . browse ( cr , uid , journal_id , context = context )
res = journal . currency and journal . currency . id or journal . company_id . currency_id . id
return res
2009-01-06 13:31:53 +00:00
def _get_journal_analytic ( self , cr , uid , type_inv , context = None ) :
2008-07-22 15:11:28 +00:00
type2journal = { ' out_invoice ' : ' sale ' , ' in_invoice ' : ' purchase ' , ' out_refund ' : ' sale ' , ' in_refund ' : ' purchase ' }
tt = type2journal . get ( type_inv , ' sale ' )
2008-10-31 22:43:31 +00:00
result = self . pool . get ( ' account.analytic.journal ' ) . search ( cr , uid , [ ( ' type ' , ' = ' , tt ) ] , context = context )
2008-07-22 15:11:28 +00:00
if not result :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Analytic Journal! ' ) , _ ( " You must define an analytic journal of type ' %s ' ! " ) % ( tt , ) )
2008-07-22 15:11:28 +00:00
return result [ 0 ]
2009-01-06 13:31:53 +00:00
def _get_type ( self , cr , uid , context = None ) :
if context is None :
context = { }
2010-07-02 10:55:58 +00:00
return context . get ( ' type ' , ' out_invoice ' )
2008-07-22 15:11:28 +00:00
2010-07-02 10:55:58 +00:00
def _reconciled ( self , cr , uid , ids , name , args , context = None ) :
2008-07-22 15:11:28 +00:00
res = { }
2012-03-28 11:27:25 +00:00
for inv in self . browse ( cr , uid , ids , context = context ) :
res [ inv . id ] = self . test_paid ( cr , uid , [ inv . id ] )
if not res [ inv . id ] and inv . state == ' paid ' :
2013-02-01 06:47:40 +00:00
self . signal_open_test ( cr , uid , [ inv . id ] )
2008-07-22 15:11:28 +00:00
return res
2008-12-08 17:08:40 +00:00
def _get_reference_type ( self , cr , uid , context = None ) :
return [ ( ' none ' , _ ( ' Free Reference ' ) ) ]
2008-07-22 15:11:28 +00:00
2009-01-06 13:31:53 +00:00
def _amount_residual ( self , cr , uid , ids , name , args , context = None ) :
2013-05-23 12:28:55 +00:00
""" Function of the field residua. It computes the residual amount (balance) for each invoice """
if context is None :
context = { }
ctx = context . copy ( )
2011-01-05 13:46:54 +00:00
result = { }
2013-05-23 12:28:55 +00:00
currency_obj = self . pool . get ( ' res.currency ' )
2011-01-05 13:46:54 +00:00
for invoice in self . browse ( cr , uid , ids , context = context ) :
2013-05-23 12:28:55 +00:00
nb_inv_in_partial_rec = max_invoice_id = 0
2011-01-05 13:46:54 +00:00
result [ invoice . id ] = 0.0
if invoice . move_id :
2013-05-23 12:28:55 +00:00
for aml in invoice . move_id . line_id :
if aml . account_id . type in ( ' receivable ' , ' payable ' ) :
if aml . currency_id and aml . currency_id . id == invoice . currency_id . id :
result [ invoice . id ] + = aml . amount_residual_currency
else :
ctx [ ' date ' ] = aml . date
result [ invoice . id ] + = currency_obj . compute ( cr , uid , aml . company_id . currency_id . id , invoice . currency_id . id , aml . amount_residual , context = ctx )
if aml . reconcile_partial_id . line_partial_ids :
#we check if the invoice is partially reconciled and if there are other invoices
#involved in this partial reconciliation (and we sum these invoices)
for line in aml . reconcile_partial_id . line_partial_ids :
2014-02-05 10:03:24 +00:00
if line . invoice and invoice . type == line . invoice . type :
2013-05-23 12:28:55 +00:00
nb_inv_in_partial_rec + = 1
#store the max invoice id as for this invoice we will make a balance instead of a simple division
max_invoice_id = max ( max_invoice_id , line . invoice . id )
if nb_inv_in_partial_rec :
#if there are several invoices in a partial reconciliation, we split the residual by the number
#of invoice to have a sum of residual amounts that matches the partner balance
new_value = currency_obj . round ( cr , uid , invoice . currency_id , result [ invoice . id ] / nb_inv_in_partial_rec )
if invoice . id == max_invoice_id :
#if it's the last the invoice of the bunch of invoices partially reconciled together, we make a
#balance to avoid rounding errors
result [ invoice . id ] = result [ invoice . id ] - ( ( nb_inv_in_partial_rec - 1 ) * new_value )
else :
result [ invoice . id ] = new_value
2013-03-15 13:01:47 +00:00
#prevent the residual amount on the invoice to be less than 0
result [ invoice . id ] = max ( result [ invoice . id ] , 0.0 )
2011-01-05 13:46:54 +00:00
return result
2008-09-12 07:21:22 +00:00
2010-09-19 12:35:06 +00:00
# Give Journal Items related to the payment reconciled to this invoice
# Return ids of partial and total payments related to the selected invoices
2008-09-12 07:21:22 +00:00
def _get_lines ( self , cr , uid , ids , name , arg , context = None ) :
res = { }
2010-09-19 12:35:06 +00:00
for invoice in self . browse ( cr , uid , ids , context = context ) :
id = invoice . id
2010-01-04 09:17:23 +00:00
res [ id ] = [ ]
2010-09-19 12:35:06 +00:00
if not invoice . move_id :
continue
2010-10-04 07:31:13 +00:00
data_lines = [ x for x in invoice . move_id . line_id if x . account_id . id == invoice . account_id . id ]
2010-09-19 12:35:06 +00:00
partial_ids = [ ]
2008-09-12 07:21:22 +00:00
for line in data_lines :
ids_line = [ ]
if line . reconcile_id :
ids_line = line . reconcile_id . line_id
elif line . reconcile_partial_id :
ids_line = line . reconcile_partial_id . line_partial_ids
l = map ( lambda x : x . id , ids_line )
2010-01-04 09:17:23 +00:00
partial_ids . append ( line . id )
res [ id ] = [ x for x in l if x < > line . id and x not in partial_ids ]
2008-09-12 07:21:22 +00:00
return res
2008-09-18 13:32:58 +00:00
2009-01-06 13:31:53 +00:00
def _get_invoice_line ( self , cr , uid , ids , context = None ) :
2008-12-07 12:45:27 +00:00
result = { }
2008-12-08 07:56:41 +00:00
for line in self . pool . get ( ' account.invoice.line ' ) . browse ( cr , uid , ids , context = context ) :
result [ line . invoice_id . id ] = True
2008-12-07 12:45:27 +00:00
return result . keys ( )
2009-01-06 13:31:53 +00:00
def _get_invoice_tax ( self , cr , uid , ids , context = None ) :
2008-12-07 02:15:41 +00:00
result = { }
for tax in self . pool . get ( ' account.invoice.tax ' ) . browse ( cr , uid , ids , context = context ) :
result [ tax . invoice_id . id ] = True
return result . keys ( )
2009-01-06 13:31:53 +00:00
def _compute_lines ( self , cr , uid , ids , name , args , context = None ) :
2008-09-16 11:45:13 +00:00
result = { }
2010-11-19 13:48:01 +00:00
for invoice in self . browse ( cr , uid , ids , context = context ) :
2008-09-16 11:45:13 +00:00
src = [ ]
lines = [ ]
2010-09-19 12:35:06 +00:00
if invoice . move_id :
for m in invoice . move_id . line_id :
temp_lines = [ ]
if m . reconcile_id :
temp_lines = map ( lambda x : x . id , m . reconcile_id . line_id )
elif m . reconcile_partial_id :
temp_lines = map ( lambda x : x . id , m . reconcile_partial_id . line_partial_ids )
lines + = [ x for x in temp_lines if x not in lines ]
src . append ( m . id )
2010-02-09 08:31:46 +00:00
2008-09-16 11:45:13 +00:00
lines = filter ( lambda x : x not in src , lines )
result [ invoice . id ] = lines
return result
2008-09-12 07:21:22 +00:00
2010-07-02 10:55:58 +00:00
def _get_invoice_from_line ( self , cr , uid , ids , context = None ) :
2009-01-16 09:44:05 +00:00
move = { }
2010-11-19 13:48:01 +00:00
for line in self . pool . get ( ' account.move.line ' ) . browse ( cr , uid , ids , context = context ) :
2009-01-16 10:02:34 +00:00
if line . reconcile_partial_id :
for line2 in line . reconcile_partial_id . line_partial_ids :
move [ line2 . move_id . id ] = True
if line . reconcile_id :
for line2 in line . reconcile_id . line_id :
move [ line2 . move_id . id ] = True
2009-01-16 09:44:05 +00:00
invoice_ids = [ ]
if move :
invoice_ids = self . pool . get ( ' account.invoice ' ) . search ( cr , uid , [ ( ' move_id ' , ' in ' , move . keys ( ) ) ] , context = context )
return invoice_ids
2010-07-02 10:55:58 +00:00
def _get_invoice_from_reconcile ( self , cr , uid , ids , context = None ) :
2009-01-16 09:44:05 +00:00
move = { }
2010-11-19 13:48:01 +00:00
for r in self . pool . get ( ' account.move.reconcile ' ) . browse ( cr , uid , ids , context = context ) :
2009-01-16 09:44:05 +00:00
for line in r . line_partial_ids :
move [ line . move_id . id ] = True
for line in r . line_id :
move [ line . move_id . id ] = True
2009-11-13 05:41:16 +00:00
2009-01-16 09:44:05 +00:00
invoice_ids = [ ]
if move :
invoice_ids = self . pool . get ( ' account.invoice ' ) . search ( cr , uid , [ ( ' move_id ' , ' in ' , move . keys ( ) ) ] , context = context )
return invoice_ids
2008-07-22 15:11:28 +00:00
_name = " account.invoice "
2012-04-03 10:58:01 +00:00
_inherit = [ ' mail.thread ' ]
2008-07-22 15:11:28 +00:00
_description = ' Invoice '
2010-08-27 06:17:56 +00:00
_order = " id desc "
2012-12-18 22:06:17 +00:00
_track = {
2012-12-19 12:15:20 +00:00
' type ' : {
} ,
2012-12-18 22:06:17 +00:00
' state ' : {
2013-06-27 14:46:47 +00:00
' account.mt_invoice_paid ' : lambda self , cr , uid , obj , ctx = None : obj . state == ' paid ' and obj . type in ( ' out_invoice ' , ' out_refund ' ) ,
' account.mt_invoice_validated ' : lambda self , cr , uid , obj , ctx = None : obj . state == ' open ' and obj . type in ( ' out_invoice ' , ' out_refund ' ) ,
2012-12-18 22:06:17 +00:00
} ,
}
2008-07-22 15:11:28 +00:00
_columns = {
2014-04-01 07:02:27 +00:00
' name ' : fields . char ( ' Reference/Description ' , size = 64 , select = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-07-09 06:34:21 +00:00
' origin ' : fields . char ( ' Source Document ' , size = 64 , help = " Reference of the document that produced this invoice. " , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-10-22 10:32:16 +00:00
' supplier_invoice_number ' : fields . char ( ' Supplier Invoice Number ' , size = 64 , help = " The reference of this invoice as provided by the supplier. " , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2008-07-22 15:11:28 +00:00
' type ' : fields . selection ( [
( ' out_invoice ' , ' Customer Invoice ' ) ,
( ' in_invoice ' , ' Supplier Invoice ' ) ,
( ' out_refund ' , ' Customer Refund ' ) ,
( ' in_refund ' , ' Supplier Refund ' ) ,
2012-12-20 11:47:30 +00:00
] , ' Type ' , readonly = True , select = True , change_default = True , track_visibility = ' always ' ) ,
2008-07-22 15:11:28 +00:00
2010-08-14 13:58:01 +00:00
' number ' : fields . related ( ' move_id ' , ' name ' , type = ' char ' , readonly = True , size = 64 , relation = ' account.move ' , store = True , string = ' Number ' ) ,
' internal_number ' : fields . char ( ' Invoice Number ' , size = 32 , readonly = True , help = " Unique number of the invoice, computed automatically when the invoice is created. " ) ,
2008-09-22 06:06:56 +00:00
' reference ' : fields . char ( ' Invoice Reference ' , size = 64 , help = " The partner reference of this invoice. " ) ,
2012-07-14 23:18:43 +00:00
' reference_type ' : fields . selection ( _get_reference_type , ' Payment Reference ' ,
2010-07-08 14:25:59 +00:00
required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-07-25 18:05:49 +00:00
' comment ' : fields . text ( ' Additional Information ' ) ,
2008-07-22 15:11:28 +00:00
' state ' : fields . selection ( [
( ' draft ' , ' Draft ' ) ,
( ' proforma ' , ' Pro-forma ' ) ,
2008-10-07 10:02:21 +00:00
( ' proforma2 ' , ' Pro-forma ' ) ,
2008-07-22 15:11:28 +00:00
( ' open ' , ' Open ' ) ,
2012-05-22 11:19:07 +00:00
( ' paid ' , ' Paid ' ) ,
2012-05-22 11:06:00 +00:00
( ' cancel ' , ' Cancelled ' ) ,
2012-12-20 11:47:30 +00:00
] , ' Status ' , select = True , readonly = True , track_visibility = ' onchange ' ,
2012-10-12 11:42:58 +00:00
help = ' * The \' Draft \' status is used when a user is encoding a new and unconfirmed Invoice. \
\n * The \' Pro-forma \' when invoice is in Pro-forma status,invoice does not have an invoice number. \
\n * The \' Open \' status is used when user create invoice,a invoice number is generated.Its in open status till user does not pay invoice. \
\n * The \' Paid \' status is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \
\n * The \' Cancelled \' status is used when user cancel invoice. ' ) ,
2012-05-24 06:32:38 +00:00
' sent ' : fields . boolean ( ' Sent ' , readonly = True , help = " It indicates that the invoice has been sent. " ) ,
2011-10-19 08:14:03 +00:00
' date_invoice ' : fields . date ( ' Invoice Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , select = True , help = " Keep empty to use the current date " ) ,
2012-08-24 10:57:52 +00:00
' date_due ' : fields . date ( ' Due Date ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , select = True ,
2009-01-16 09:44:05 +00:00
help = " If you use payment terms, the due date will be computed automatically at the generation " \
2012-11-30 17:11:30 +00:00
" of accounting entries. The payment term may compute several due dates, for example 50 % now and 50 % i n one month, but if you want to force a due date, make sure that the payment term is not set on the invoice. If you keep the payment term and the due date empty, it means direct payment. " ) ,
2012-12-20 11:47:30 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' , change_default = True , readonly = True , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , track_visibility = ' always ' ) ,
2012-12-19 06:56:45 +00:00
' payment_term ' : fields . many2one ( ' account.payment.term ' , ' Payment Terms ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
2009-01-16 09:44:05 +00:00
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. " \
2009-01-27 11:15:46 +00:00
" The payment term may compute several due dates, for example 50 % now, 50 % i n one month. " ) ,
2009-07-06 18:59:08 +00:00
' period_id ' : fields . many2one ( ' account.period ' , ' Force Period ' , domain = [ ( ' state ' , ' <> ' , ' done ' ) ] , help = " Keep empty to use the period of the validation(invoice) date. " , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2008-07-22 15:11:28 +00:00
2008-09-22 06:06:56 +00:00
' account_id ' : fields . many2one ( ' account.account ' , ' Account ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , help = " The partner account used for this invoice. " ) ,
2008-07-22 15:11:28 +00:00
' 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 ) ] } ) ,
2010-12-28 10:22:36 +00:00
' move_id ' : fields . many2one ( ' account.move ' , ' Journal Entry ' , readonly = True , select = 1 , ondelete = ' restrict ' , help = " Link to the automatically generated Journal Items. " ) ,
2012-12-21 16:48:08 +00:00
' amount_untaxed ' : fields . function ( _amount_all , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Subtotal ' , track_visibility = ' always ' ,
2008-12-07 02:15:41 +00:00
store = {
2009-08-20 15:32:05 +00:00
' account.invoice ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' invoice_line ' ] , 20 ) ,
2008-12-14 16:46:57 +00:00
' account.invoice.tax ' : ( _get_invoice_tax , None , 20 ) ,
2010-12-13 12:28:57 +00:00
' account.invoice.line ' : ( _get_invoice_line , [ ' price_unit ' , ' invoice_line_tax_id ' , ' quantity ' , ' discount ' , ' invoice_id ' ] , 20 ) ,
2008-12-07 02:15:41 +00:00
} ,
multi = ' all ' ) ,
2011-07-01 23:41:24 +00:00
' amount_tax ' : fields . function ( _amount_all , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Tax ' ,
2008-12-07 02:15:41 +00:00
store = {
2009-08-20 15:32:05 +00:00
' account.invoice ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' invoice_line ' ] , 20 ) ,
2008-12-14 16:46:57 +00:00
' account.invoice.tax ' : ( _get_invoice_tax , None , 20 ) ,
2010-12-13 12:28:57 +00:00
' account.invoice.line ' : ( _get_invoice_line , [ ' price_unit ' , ' invoice_line_tax_id ' , ' quantity ' , ' discount ' , ' invoice_id ' ] , 20 ) ,
2008-12-07 02:15:41 +00:00
} ,
multi = ' all ' ) ,
2011-07-01 23:41:24 +00:00
' amount_total ' : fields . function ( _amount_all , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Total ' ,
2008-12-07 02:15:41 +00:00
store = {
2009-08-20 15:32:05 +00:00
' account.invoice ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' invoice_line ' ] , 20 ) ,
2008-12-14 16:46:57 +00:00
' account.invoice.tax ' : ( _get_invoice_tax , None , 20 ) ,
2010-12-13 12:28:57 +00:00
' account.invoice.line ' : ( _get_invoice_line , [ ' price_unit ' , ' invoice_line_tax_id ' , ' quantity ' , ' discount ' , ' invoice_id ' ] , 20 ) ,
2008-12-07 02:15:41 +00:00
} ,
multi = ' all ' ) ,
2012-12-20 11:47:30 +00:00
' currency_id ' : fields . many2one ( ' res.currency ' , ' Currency ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , track_visibility = ' always ' ) ,
2010-06-16 11:51:39 +00:00
' journal_id ' : fields . many2one ( ' account.journal ' , ' Journal ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-07-09 06:34:21 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True , change_default = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-08-24 10:57:52 +00:00
' check_total ' : fields . float ( ' Verification Total ' , digits_compute = dp . get_precision ( ' Account ' ) , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2011-07-01 23:41:24 +00:00
' reconciled ' : fields . function ( _reconciled , string = ' Paid/Reconciled ' , type = ' boolean ' ,
2009-01-26 22:22:32 +00:00
store = {
2009-08-20 15:32:05 +00:00
' account.invoice ' : ( lambda self , cr , uid , ids , c = { } : ids , None , 50 ) , # Check if we can remove ?
2009-01-26 22:22:32 +00:00
' account.move.line ' : ( _get_invoice_from_line , None , 50 ) ,
' account.move.reconcile ' : ( _get_invoice_from_reconcile , None , 50 ) ,
2011-11-30 15:51:56 +00:00
} , help = " It indicates that the invoice has been paid and the journal entry of the invoice has been reconciled with one or several journal entries of payment. " ) ,
2010-07-19 13:47:09 +00:00
' partner_bank_id ' : fields . many2one ( ' res.partner.bank ' , ' Bank Account ' ,
2012-01-10 14:09:12 +00:00
help = ' Bank Account Number to which the invoice will be paid. A Company bank account if this is a Customer Invoice or Supplier Refund, otherwise a Partner bank account number. ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2011-07-01 23:41:24 +00:00
' move_lines ' : fields . function ( _get_lines , type = ' many2many ' , relation = ' account.move.line ' , string = ' Entry Lines ' ) ,
2011-12-31 07:57:20 +00:00
' residual ' : fields . function ( _amount_residual , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Balance ' ,
2008-12-07 02:45:43 +00:00
store = {
2011-06-21 14:39:09 +00:00
' account.invoice ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' invoice_line ' , ' move_id ' ] , 50 ) ,
2008-12-14 16:46:57 +00:00
' account.invoice.tax ' : ( _get_invoice_tax , None , 50 ) ,
2010-12-13 12:28:57 +00:00
' account.invoice.line ' : ( _get_invoice_line , [ ' price_unit ' , ' invoice_line_tax_id ' , ' quantity ' , ' discount ' , ' invoice_id ' ] , 50 ) ,
2009-01-16 09:44:05 +00:00
' account.move.line ' : ( _get_invoice_from_line , None , 50 ) ,
' account.move.reconcile ' : ( _get_invoice_from_reconcile , None , 50 ) ,
2008-12-07 02:45:43 +00:00
} ,
help = " Remaining amount due. " ) ,
2011-07-01 23:41:24 +00:00
' payment_ids ' : fields . function ( _compute_lines , relation = ' account.move.line ' , type = " many2many " , string = ' Payments ' ) ,
2010-08-24 13:06:22 +00:00
' move_name ' : fields . char ( ' Journal Entry ' , size = 64 , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-12-20 11:47:30 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Salesperson ' , readonly = True , track_visibility = ' onchange ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2013-04-22 15:34:49 +00:00
' fiscal_position ' : fields . many2one ( ' account.fiscal.position ' , ' Fiscal Position ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' commercial_partner_id ' : fields . related ( ' partner_id ' , ' commercial_partner_id ' , string = ' Commercial Entity ' , type = ' many2one ' ,
relation = ' res.partner ' , store = True , readonly = True ,
help = " The commercial entity that will be used on Journal Entries for this invoice " )
2008-07-22 15:11:28 +00:00
}
_defaults = {
' type ' : _get_type ,
2010-07-02 10:55:58 +00:00
' state ' : ' draft ' ,
2008-07-22 15:11:28 +00:00
' journal_id ' : _get_journal ,
2012-02-01 16:06:48 +00:00
' currency_id ' : _get_currency ,
2009-12-23 17:16:39 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' account.invoice ' , context = c ) ,
2010-07-02 10:55:58 +00:00
' reference_type ' : ' none ' ,
' check_total ' : 0.0 ,
2010-08-14 13:58:01 +00:00
' internal_number ' : False ,
2010-06-16 11:51:39 +00:00
' user_id ' : lambda s , cr , u , c : u ,
2012-05-24 06:32:38 +00:00
' sent ' : False ,
2008-07-22 15:11:28 +00:00
}
2011-11-09 06:30:48 +00:00
_sql_constraints = [
2012-02-06 13:57:24 +00:00
( ' number_uniq ' , ' unique(number, company_id, journal_id, type) ' , ' Invoice Number must be unique per Company! ' ) ,
2011-11-09 06:30:48 +00:00
]
2008-07-22 15:11:28 +00:00
2013-03-05 16:20:15 +00:00
2012-11-30 16:35:28 +00:00
2010-06-23 10:31:14 +00:00
def fields_view_get ( self , cr , uid , view_id = None , view_type = False , context = None , toolbar = False , submenu = False ) :
2010-09-22 11:24:03 +00:00
journal_obj = self . pool . get ( ' account.journal ' )
2010-11-16 04:27:28 +00:00
if context is None :
context = { }
2010-11-19 13:48:01 +00:00
2010-11-16 04:27:28 +00:00
if context . get ( ' active_model ' , ' ' ) in [ ' res.partner ' ] and context . get ( ' active_ids ' , False ) and context [ ' active_ids ' ] :
2013-03-29 14:37:20 +00:00
partner = self . pool [ context [ ' active_model ' ] ] . read ( cr , uid , context [ ' active_ids ' ] , [ ' supplier ' , ' customer ' ] ) [ 0 ]
2010-06-23 10:31:14 +00:00
if not view_type :
2010-11-26 08:49:11 +00:00
view_id = self . pool . get ( ' ir.ui.view ' ) . search ( cr , uid , [ ( ' name ' , ' = ' , ' account.invoice.tree ' ) ] )
2010-06-23 10:31:14 +00:00
view_type = ' tree '
if view_type == ' form ' :
if partner [ ' supplier ' ] and not partner [ ' customer ' ] :
2010-11-26 08:49:11 +00:00
view_id = self . pool . get ( ' ir.ui.view ' ) . search ( cr , uid , [ ( ' name ' , ' = ' , ' account.invoice.supplier.form ' ) ] )
2012-07-25 10:46:34 +00:00
elif partner [ ' customer ' ] and not partner [ ' supplier ' ] :
2010-11-26 08:49:11 +00:00
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 ]
2010-09-21 13:06:42 +00:00
res = super ( account_invoice , self ) . fields_view_get ( cr , uid , view_id = view_id , view_type = view_type , context = context , toolbar = toolbar , submenu = submenu )
2010-11-26 08:49:11 +00:00
2011-11-09 11:07:04 +00:00
type = context . get ( ' journal_type ' , False )
2010-09-21 13:06:42 +00:00
for field in res [ ' fields ' ] :
2011-11-09 11:07:04 +00:00
if field == ' journal_id ' and type :
2010-09-22 11:24:03 +00:00
journal_select = journal_obj . _name_search ( cr , uid , ' ' , [ ( ' type ' , ' = ' , type ) ] , context = context , limit = None , name_get_uid = 1 )
2010-09-21 13:06:42 +00:00
res [ ' fields ' ] [ field ] [ ' selection ' ] = journal_select
2010-10-08 11:28:58 +00:00
2011-04-29 05:01:18 +00:00
doc = etree . XML ( res [ ' arch ' ] )
2012-08-06 15:44:10 +00:00
2012-01-18 10:14:28 +00:00
if context . get ( ' type ' , False ) :
for node in doc . xpath ( " //field[@name= ' partner_bank_id ' ] " ) :
if context [ ' type ' ] == ' in_refund ' :
node . set ( ' domain ' , " [( ' partner_id.ref_companies ' , ' in ' , [company_id])] " )
2012-01-19 13:21:53 +00:00
elif context [ ' type ' ] == ' out_refund ' :
2012-01-19 05:38:02 +00:00
node . set ( ' domain ' , " [( ' partner_id ' , ' = ' , partner_id)] " )
2012-01-18 10:14:28 +00:00
res [ ' arch ' ] = etree . tostring ( doc )
2012-08-06 15:44:10 +00:00
2011-04-29 05:01:18 +00:00
if view_type == ' search ' :
if context . get ( ' type ' , ' in_invoice ' ) in ( ' out_invoice ' , ' out_refund ' ) :
for node in doc . xpath ( " //group[@name= ' extended filter ' ] " ) :
doc . remove ( node )
2011-04-29 13:03:53 +00:00
res [ ' arch ' ] = etree . tostring ( doc )
2011-04-29 05:01:18 +00:00
2010-10-08 11:28:58 +00:00
if view_type == ' tree ' :
2010-10-17 17:30:00 +00:00
partner_string = _ ( ' Customer ' )
2010-10-08 11:28:58 +00:00
if context . get ( ' type ' , ' out_invoice ' ) in ( ' in_invoice ' , ' in_refund ' ) :
2010-10-09 16:01:43 +00:00
partner_string = _ ( ' Supplier ' )
2011-04-29 05:01:18 +00:00
for node in doc . xpath ( " //field[@name= ' reference ' ] " ) :
2011-04-29 08:53:55 +00:00
node . set ( ' invisible ' , ' 0 ' )
2011-04-29 05:01:18 +00:00
for node in doc . xpath ( " //field[@name= ' partner_id ' ] " ) :
2010-10-08 11:28:58 +00:00
node . set ( ' string ' , partner_string )
res [ ' arch ' ] = etree . tostring ( doc )
2010-09-21 13:06:42 +00:00
return res
2010-06-23 10:31:14 +00:00
2010-10-25 09:54:30 +00:00
def get_log_context ( self , cr , uid , context = None ) :
if context is None :
context = { }
2011-01-12 07:22:09 +00:00
res = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' account ' , ' invoice_form ' )
2010-10-25 09:54:30 +00:00
view_id = res and res [ 1 ] or False
2012-02-14 12:07:41 +00:00
context [ ' view_id ' ] = view_id
2010-10-25 09:54:30 +00:00
return context
2012-02-29 10:10:45 +00:00
def invoice_print ( self , cr , uid , ids , context = None ) :
2012-05-25 15:17:40 +00:00
'''
This function prints the invoice and mark it as sent , so that we can see more easily the next step of the workflow
'''
2012-07-25 07:33:57 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time. '
2012-05-25 15:17:40 +00:00
self . write ( cr , uid , ids , { ' sent ' : True } , context = context )
2014-05-02 13:03:10 +00:00
return self . pool [ ' report ' ] . get_action ( cr , uid , ids , ' account.report_invoice ' , context = context )
2012-02-29 10:10:45 +00:00
def action_invoice_sent ( self , cr , uid , ids , context = None ) :
2012-05-25 15:17:40 +00:00
'''
This function opens a window to compose an email , with the edi invoice template message loaded by default
'''
2012-10-23 11:56:28 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time. '
ir_model_data = self . pool . get ( ' ir.model.data ' )
try :
template_id = ir_model_data . get_object_reference ( cr , uid , ' account ' , ' email_template_edi_invoice ' ) [ 1 ]
except ValueError :
template_id = False
try :
compose_form_id = ir_model_data . get_object_reference ( cr , uid , ' mail ' , ' email_compose_message_wizard_form ' ) [ 1 ]
except ValueError :
2013-02-14 17:28:52 +00:00
compose_form_id = False
2012-09-11 14:16:50 +00:00
ctx = dict ( context )
ctx . update ( {
' default_model ' : ' account.invoice ' ,
' default_res_id ' : ids [ 0 ] ,
2012-10-23 11:56:28 +00:00
' default_use_template ' : bool ( template_id ) ,
2012-09-11 14:16:50 +00:00
' default_template_id ' : template_id ,
2012-11-13 11:20:38 +00:00
' default_composition_mode ' : ' comment ' ,
2012-11-21 10:21:37 +00:00
' mark_invoice_as_sent ' : True ,
2012-09-11 14:16:50 +00:00
} )
2012-02-29 06:47:05 +00:00
return {
2013-03-21 05:38:55 +00:00
' name ' : _ ( ' Compose Email ' ) ,
2012-10-23 11:56:28 +00:00
' type ' : ' ir.actions.act_window ' ,
2012-09-11 14:16:50 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' mail.compose.message ' ,
2012-10-23 11:56:28 +00:00
' views ' : [ ( compose_form_id , ' form ' ) ] ,
' view_id ' : compose_form_id ,
2012-09-11 14:16:50 +00:00
' target ' : ' new ' ,
' context ' : ctx ,
2012-02-29 06:47:05 +00:00
}
2010-05-17 13:34:31 +00:00
2010-05-19 20:02:36 +00:00
def confirm_paid ( self , cr , uid , ids , context = None ) :
2011-02-01 06:42:45 +00:00
if context is None :
context = { }
2010-05-19 20:02:36 +00:00
self . write ( cr , uid , ids , { ' state ' : ' paid ' } , context = context )
return True
2009-01-21 11:21:21 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2011-02-01 06:42:45 +00:00
if context is None :
context = { }
2011-03-15 11:30:55 +00:00
invoices = self . read ( cr , uid , ids , [ ' state ' , ' internal_number ' ] , context = context )
2009-04-07 12:15:46 +00:00
unlink_ids = [ ]
2013-02-15 17:10:53 +00:00
2009-04-07 12:15:46 +00:00
for t in invoices :
2013-02-15 17:10:53 +00:00
if t [ ' state ' ] not in ( ' draft ' , ' cancel ' ) :
2013-02-20 09:28:32 +00:00
raise openerp . exceptions . Warning ( _ ( ' You cannot delete an invoice which is not draft or cancelled. You should refund it instead. ' ) )
elif t [ ' internal_number ' ] :
2013-02-15 17:10:53 +00:00
raise openerp . exceptions . Warning ( _ ( ' You cannot delete an invoice after it has been validated (and received a number). You can set it back to " Draft " state and modify its content, then re-confirm it. ' ) )
2009-04-07 12:15:46 +00:00
else :
2013-02-15 17:10:53 +00:00
unlink_ids . append ( t [ ' id ' ] )
2009-04-07 12:15:46 +00:00
osv . osv . unlink ( self , cr , uid , unlink_ids , context = context )
return True
2008-07-22 15:11:28 +00:00
2010-07-19 13:47:09 +00:00
def onchange_partner_id ( self , cr , uid , ids , type , partner_id , \
2010-07-20 04:20:34 +00:00
date_invoice = False , payment_term = False , partner_bank_id = False , company_id = False ) :
2008-07-22 15:11:28 +00:00
partner_payment_term = False
acc_id = False
bank_id = False
2009-01-19 13:59:11 +00:00
fiscal_position = False
2008-07-22 15:11:28 +00:00
opt = [ ( ' uid ' , str ( uid ) ) ]
if partner_id :
opt . insert ( 0 , ( ' id ' , partner_id ) )
p = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id )
2009-11-10 12:49:20 +00:00
if company_id :
2012-11-26 18:52:49 +00:00
if ( p . property_account_receivable . company_id and ( p . property_account_receivable . company_id . id != company_id ) ) and ( p . property_account_payable . company_id and ( p . property_account_payable . company_id . id != company_id ) ) :
2010-08-12 21:10:05 +00:00
property_obj = self . pool . get ( ' ir.property ' )
rec_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_receivable ' ) , ( ' res_id ' , ' = ' , ' res.partner, ' + str ( partner_id ) + ' ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
pay_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_payable ' ) , ( ' res_id ' , ' = ' , ' res.partner, ' + str ( partner_id ) + ' ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2009-12-24 08:43:23 +00:00
if not rec_pro_id :
2010-08-12 21:10:05 +00:00
rec_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_receivable ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2009-11-10 12:49:20 +00:00
if not pay_pro_id :
2010-08-12 21:10:05 +00:00
pay_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_payable ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2010-09-09 12:10:42 +00:00
rec_line_data = property_obj . read ( cr , uid , rec_pro_id , [ ' name ' , ' value_reference ' , ' res_id ' ] )
pay_line_data = property_obj . read ( cr , uid , pay_pro_id , [ ' name ' , ' value_reference ' , ' res_id ' ] )
2010-09-13 09:11:57 +00:00
rec_res_id = rec_line_data and rec_line_data [ 0 ] . get ( ' value_reference ' , False ) and int ( rec_line_data [ 0 ] [ ' value_reference ' ] . split ( ' , ' ) [ 1 ] ) or False
pay_res_id = pay_line_data and pay_line_data [ 0 ] . get ( ' value_reference ' , False ) and int ( pay_line_data [ 0 ] [ ' value_reference ' ] . split ( ' , ' ) [ 1 ] ) or False
2009-11-10 12:49:20 +00:00
if not rec_res_id and not pay_res_id :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' Configuration Error! ' ) ,
2012-07-11 13:28:44 +00:00
_ ( ' Cannot find a chart of accounts for this company, you should create one. ' ) )
2010-08-12 21:10:05 +00:00
account_obj = self . pool . get ( ' account.account ' )
rec_obj_acc = account_obj . browse ( cr , uid , [ rec_res_id ] )
pay_obj_acc = account_obj . browse ( cr , uid , [ pay_res_id ] )
2009-11-10 12:49:20 +00:00
p . property_account_receivable = rec_obj_acc [ 0 ]
p . property_account_payable = pay_obj_acc [ 0 ]
2008-07-22 15:11:28 +00:00
if type in ( ' out_invoice ' , ' out_refund ' ) :
acc_id = p . property_account_receivable . id
2012-07-11 11:14:34 +00:00
partner_payment_term = p . property_payment_term and p . property_payment_term . id or False
2008-07-22 15:11:28 +00:00
else :
acc_id = p . property_account_payable . id
2012-07-11 11:14:34 +00:00
partner_payment_term = p . property_supplier_payment_term and p . property_supplier_payment_term . id or False
2009-01-19 16:49:29 +00:00
fiscal_position = p . property_account_position and p . property_account_position . id or False
2008-07-22 15:11:28 +00:00
if p . bank_ids :
bank_id = p . bank_ids [ 0 ] . id
result = { ' value ' : {
' account_id ' : acc_id ,
' payment_term ' : partner_payment_term ,
2009-01-19 13:59:11 +00:00
' fiscal_position ' : fiscal_position
2008-07-22 15:11:28 +00:00
}
}
if type in ( ' in_invoice ' , ' in_refund ' ) :
2010-07-19 13:47:09 +00:00
result [ ' value ' ] [ ' partner_bank_id ' ] = bank_id
2009-12-24 08:43:23 +00:00
2009-11-10 12:49:20 +00:00
if payment_term != partner_payment_term :
if partner_payment_term :
to_update = self . onchange_payment_term_date_invoice (
2010-06-16 11:51:39 +00:00
cr , uid , ids , partner_payment_term , date_invoice )
2009-11-10 12:49:20 +00:00
result [ ' value ' ] . update ( to_update [ ' value ' ] )
else :
result [ ' value ' ] [ ' date_due ' ] = False
2008-07-22 15:11:28 +00:00
2010-07-20 04:20:34 +00:00
if partner_bank_id != bank_id :
2008-07-22 15:11:28 +00:00
to_update = self . onchange_partner_bank ( cr , uid , ids , bank_id )
result [ ' value ' ] . update ( to_update [ ' value ' ] )
return result
2012-02-01 14:16:33 +00:00
def onchange_journal_id ( self , cr , uid , ids , journal_id = False , context = None ) :
2010-09-17 14:21:13 +00:00
result = { }
2010-09-17 06:51:33 +00:00
if journal_id :
2012-02-01 14:16:33 +00:00
journal = self . pool . get ( ' account.journal ' ) . browse ( cr , uid , journal_id , context = context )
2010-09-17 14:21:13 +00:00
currency_id = journal . currency and journal . currency . id or journal . company_id . currency_id . id
2012-09-09 11:45:15 +00:00
company_id = journal . company_id . id
2010-09-17 14:21:13 +00:00
result = { ' value ' : {
' currency_id ' : currency_id ,
2012-09-09 11:45:15 +00:00
' company_id ' : company_id ,
2010-09-17 06:10:44 +00:00
}
}
return result
2008-07-22 15:11:28 +00:00
def onchange_payment_term_date_invoice ( self , cr , uid , ids , payment_term_id , date_invoice ) :
2013-02-14 17:28:52 +00:00
res = { }
2013-07-12 06:58:43 +00:00
if isinstance ( ids , ( int , long ) ) :
2013-05-17 05:03:25 +00:00
ids = [ ids ]
2010-08-30 06:28:31 +00:00
if not date_invoice :
2008-10-22 10:16:03 +00:00
date_invoice = time . strftime ( ' % Y- % m- %d ' )
2012-11-15 08:16:34 +00:00
if not payment_term_id :
2013-07-12 06:58:43 +00:00
inv = self . browse ( cr , uid , ids [ 0 ] )
#To make sure the invoice due date should contain due date which is entered by user when there is no payment term defined
return { ' value ' : { ' date_due ' : inv . date_due and inv . date_due or date_invoice } }
2012-05-04 06:35:59 +00:00
pterm_list = self . pool . get ( ' account.payment.term ' ) . compute ( cr , uid , payment_term_id , value = 1 , date_ref = date_invoice )
2008-07-22 15:11:28 +00:00
if pterm_list :
pterm_list = [ line [ 0 ] for line in pterm_list ]
pterm_list . sort ( )
2010-08-30 06:28:31 +00:00
res = { ' value ' : { ' date_due ' : pterm_list [ - 1 ] } }
2009-03-17 13:28:02 +00:00
else :
2012-08-07 10:23:26 +00:00
raise osv . except_osv ( _ ( ' Insufficient Data! ' ) , _ ( ' The payment term of supplier does not have a payment term line. ' ) )
2008-07-22 15:11:28 +00:00
return res
def onchange_invoice_line ( self , cr , uid , ids , lines ) :
return { }
2010-07-20 04:20:34 +00:00
def onchange_partner_bank ( self , cursor , user , ids , partner_bank_id = False ) :
2008-07-22 15:11:28 +00:00
return { ' value ' : { } }
2013-02-15 14:37:18 +00:00
def onchange_company_id ( self , cr , uid , ids , company_id , part_id , type , invoice_line , currency_id , context = None ) :
2013-06-07 17:59:49 +00:00
#TODO: add the missing context parameter when forward-porting in trunk so we can remove
# this hack!
context = self . pool [ ' res.users ' ] . context_get ( cr , uid )
2010-04-06 13:07:31 +00:00
val = { }
dom = { }
obj_journal = self . pool . get ( ' account.journal ' )
2010-10-20 04:44:12 +00:00
account_obj = self . pool . get ( ' account.account ' )
inv_line_obj = self . pool . get ( ' account.invoice.line ' )
2013-02-14 17:31:56 +00:00
2009-11-10 12:49:20 +00:00
if company_id and part_id and type :
acc_id = False
2013-02-15 14:37:18 +00:00
partner_obj = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , part_id , context = context )
2013-02-14 17:31:56 +00:00
2009-11-10 12:49:20 +00:00
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 :
2010-08-12 21:10:05 +00:00
property_obj = self . pool . get ( ' ir.property ' )
rec_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_receivable ' ) , ( ' res_id ' , ' = ' , ' res.partner, ' + str ( part_id ) + ' ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
pay_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_payable ' ) , ( ' res_id ' , ' = ' , ' res.partner, ' + str ( part_id ) + ' ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2013-02-14 17:31:56 +00:00
2009-12-24 08:43:23 +00:00
if not rec_pro_id :
2010-08-12 21:10:05 +00:00
rec_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_receivable ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2009-11-10 12:49:20 +00:00
if not pay_pro_id :
2010-08-12 21:10:05 +00:00
pay_pro_id = property_obj . search ( cr , uid , [ ( ' name ' , ' = ' , ' property_account_payable ' ) , ( ' company_id ' , ' = ' , company_id ) ] )
2013-02-14 17:31:56 +00:00
2010-09-09 12:10:42 +00:00
rec_line_data = property_obj . read ( cr , uid , rec_pro_id , [ ' name ' , ' value_reference ' , ' res_id ' ] )
pay_line_data = property_obj . read ( cr , uid , pay_pro_id , [ ' name ' , ' value_reference ' , ' res_id ' ] )
2010-09-13 09:11:57 +00:00
rec_res_id = rec_line_data and rec_line_data [ 0 ] . get ( ' value_reference ' , False ) and int ( rec_line_data [ 0 ] [ ' value_reference ' ] . split ( ' , ' ) [ 1 ] ) or False
pay_res_id = pay_line_data and pay_line_data [ 0 ] . get ( ' value_reference ' , False ) and int ( pay_line_data [ 0 ] [ ' value_reference ' ] . split ( ' , ' ) [ 1 ] ) or False
2013-02-14 17:31:56 +00:00
2010-08-12 21:10:05 +00:00
if not rec_res_id and not pay_res_id :
2013-02-15 14:37:18 +00:00
raise self . pool . get ( ' res.config.settings ' ) . get_config_warning ( cr , _ ( ' Cannot find any chart of account: you can create a new one from % (menu:account.menu_account_config)s. ' ) , context = context )
2013-02-14 17:34:13 +00:00
2009-11-10 12:49:20 +00:00
if type in ( ' out_invoice ' , ' out_refund ' ) :
acc_id = rec_res_id
else :
acc_id = pay_res_id
2013-02-14 17:31:56 +00:00
2009-11-10 12:49:20 +00:00
val = { ' account_id ' : acc_id }
if ids :
if company_id :
inv_obj = self . browse ( cr , uid , ids )
for line in inv_obj [ 0 ] . invoice_line :
if line . account_id :
if line . account_id . company_id . id != company_id :
2010-08-12 21:10:05 +00:00
result_id = account_obj . search ( cr , uid , [ ( ' name ' , ' = ' , line . account_id . name ) , ( ' company_id ' , ' = ' , company_id ) ] )
2009-11-10 12:49:20 +00:00
if not result_id :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' Configuration Error! ' ) ,
2012-07-11 08:48:21 +00:00
_ ( ' Cannot find a chart of account, you should create one from Settings \ Configuration \ Accounting menu. ' ) )
2011-01-25 09:58:54 +00:00
inv_line_obj . write ( cr , uid , [ line . id ] , { ' account_id ' : result_id [ - 1 ] } )
2009-11-10 12:49:20 +00:00
else :
if invoice_line :
for inv_line in invoice_line :
2010-08-12 21:10:05 +00:00
obj_l = account_obj . browse ( cr , uid , inv_line [ 2 ] [ ' account_id ' ] )
2009-11-10 12:49:20 +00:00
if obj_l . company_id . id != company_id :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' Configuration Error! ' ) ,
2013-04-29 05:38:51 +00:00
_ ( ' Invoice line account \' s company and invoice \' s company does not match. ' ) )
2009-11-10 12:49:20 +00:00
else :
continue
2010-04-06 13:07:31 +00:00
if company_id and type :
2013-06-07 17:59:49 +00:00
journal_mapping = {
' out_invoice ' : ' sale ' ,
' out_refund ' : ' sale_refund ' ,
' in_refund ' : ' purchase_refund ' ,
' in_invoice ' : ' purchase ' ,
}
journal_type = journal_mapping [ type ]
2010-04-06 13:07:31 +00:00
journal_ids = obj_journal . search ( cr , uid , [ ( ' company_id ' , ' = ' , company_id ) , ( ' type ' , ' = ' , journal_type ) ] )
if journal_ids :
val [ ' journal_id ' ] = journal_ids [ 0 ]
2011-05-16 15:33:31 +00:00
ir_values_obj = self . pool . get ( ' ir.values ' )
res_journal_default = ir_values_obj . get ( cr , uid , ' default ' , ' type= %s ' % ( type ) , [ ' account.invoice ' ] )
2011-01-10 11:47:41 +00:00
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 ) :
2013-06-07 17:59:49 +00:00
journal_type_map = dict ( obj_journal . _columns [ ' type ' ] . selection )
journal_type_label = self . pool [ ' ir.translation ' ] . _get_source ( cr , uid , None , ( ' code ' , ' selection ' ) ,
context . get ( ' lang ' ) ,
journal_type_map . get ( journal_type ) )
raise osv . except_osv ( _ ( ' Configuration Error! ' ) ,
_ ( ' Cannot find any account journal of %s type for this company. \n \n You can create one in the menu: \n Configuration \ Journals \ Journals. ' ) % ( ' " %s " ' % journal_type_label ) )
2010-04-06 13:07:31 +00:00
dom = { ' journal_id ' : [ ( ' id ' , ' in ' , journal_ids ) ] }
2009-11-10 12:49:20 +00:00
else :
2010-04-06 13:07:31 +00:00
journal_ids = obj_journal . search ( cr , uid , [ ] )
2010-02-24 08:47:01 +00:00
2010-10-20 07:00:04 +00:00
return { ' value ' : val , ' domain ' : dom }
2009-11-10 12:49:20 +00:00
2008-07-22 15:11:28 +00:00
# go from canceled state to draft state
def action_cancel_draft ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , { ' state ' : ' draft ' } )
2013-02-01 06:47:40 +00:00
self . delete_workflow ( cr , uid , ids )
self . create_workflow ( cr , uid , ids )
2008-07-22 15:11:28 +00:00
return True
2014-04-16 14:37:55 +00:00
def get_formview_id ( self , cr , uid , id , context = None ) :
2013-04-26 14:40:19 +00:00
""" Update form view id of action to open the invoice """
obj = self . browse ( cr , uid , id , context = context )
if obj . type == ' in_invoice ' :
model , view_id = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' account ' , ' invoice_supplier_form ' )
else :
model , view_id = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' account ' , ' invoice_form ' )
2014-04-16 14:37:55 +00:00
return view_id
2013-04-26 14:40:19 +00:00
2008-07-22 15:11:28 +00:00
# Workflow stuff
#################
# return the ids of the move lines which has the same account than the invoice
# whose id is in ids
def move_line_id_payment_get ( self , cr , uid , ids , * args ) :
2010-09-19 12:35:06 +00:00
if not ids : return [ ]
result = self . move_line_id_payment_gets ( cr , uid , ids , * args )
return result . get ( ids [ 0 ] , [ ] )
def move_line_id_payment_gets ( self , cr , uid , ids , * args ) :
res = { }
2009-08-20 15:32:05 +00:00
if not ids : return res
2010-09-19 12:35:06 +00:00
cr . execute ( ' SELECT i.id, l.id ' \
2010-06-10 13:34:19 +00:00
' 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 ) , ) )
2010-09-19 12:35:06 +00:00
for r in cr . fetchall ( ) :
res . setdefault ( r [ 0 ] , [ ] )
res [ r [ 0 ] ] . append ( r [ 1 ] )
2008-07-22 15:11:28 +00:00
return res
2011-12-14 09:35:31 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
default = default or { }
2010-08-14 13:58:01 +00:00
default . update ( {
2010-08-17 06:15:57 +00:00
' state ' : ' draft ' ,
' number ' : False ,
' move_id ' : False ,
2010-08-14 13:58:01 +00:00
' move_name ' : False ,
' internal_number ' : False ,
2011-11-24 13:29:01 +00:00
' period_id ' : False ,
2012-05-24 06:32:38 +00:00
' sent ' : False ,
2010-08-14 13:58:01 +00:00
} )
2008-07-22 15:11:28 +00:00
if ' date_invoice ' not in default :
2010-08-14 13:58:01 +00:00
default . update ( {
' date_invoice ' : False
} )
2008-07-22 15:11:28 +00:00
if ' date_due ' not in default :
2010-08-14 13:58:01 +00:00
default . update ( {
' date_due ' : False
} )
2008-07-22 15:11:28 +00:00
return super ( account_invoice , self ) . copy ( cr , uid , id , default , context )
def test_paid ( self , cr , uid , ids , * args ) :
res = self . move_line_id_payment_get ( cr , uid , ids )
if not res :
return False
ok = True
for id in res :
2008-12-10 14:29:55 +00:00
cr . execute ( ' select reconcile_id from account_move_line where id= %s ' , ( id , ) )
2008-07-22 15:11:28 +00:00
ok = ok and bool ( cr . fetchone ( ) [ 0 ] )
return ok
2009-01-06 13:31:53 +00:00
def button_reset_taxes ( self , cr , uid , ids , context = None ) :
2010-10-06 14:27:45 +00:00
if context is None :
2009-02-02 07:10:01 +00:00
context = { }
2010-10-06 14:27:45 +00:00
ctx = context . copy ( )
2008-07-22 15:11:28 +00:00
ait_obj = self . pool . get ( ' account.invoice.tax ' )
for id in ids :
2010-11-16 06:17:52 +00:00
cr . execute ( " DELETE FROM account_invoice_tax WHERE invoice_id= %s AND manual is False " , ( id , ) )
2010-10-06 14:27:45 +00:00
partner = self . browse ( cr , uid , id , context = ctx ) . partner_id
2009-09-11 15:31:07 +00:00
if partner . lang :
2010-10-06 14:27:45 +00:00
ctx . update ( { ' lang ' : partner . lang } )
for taxe in ait_obj . compute ( cr , uid , id , context = ctx ) . values ( ) :
2008-07-22 15:11:28 +00:00
ait_obj . create ( cr , uid , taxe )
2010-08-30 06:28:31 +00:00
# Update the stored value (fields.function), so we write to trigger recompute
2010-10-06 14:27:45 +00:00
self . pool . get ( ' account.invoice ' ) . write ( cr , uid , ids , { ' invoice_line ' : [ ] } , context = ctx )
2008-07-22 15:11:28 +00:00
return True
2009-01-06 13:31:53 +00:00
def button_compute ( self , cr , uid , ids , context = None , set_total = False ) :
2008-12-31 12:58:51 +00:00
self . button_reset_taxes ( cr , uid , ids , context )
2010-11-19 13:48:01 +00:00
for inv in self . browse ( cr , uid , ids , context = context ) :
2008-07-22 15:11:28 +00:00
if set_total :
self . pool . get ( ' account.invoice ' ) . write ( cr , uid , [ inv . id ] , { ' check_total ' : inv . amount_total } )
return True
def _convert_ref ( self , cr , uid , ref ) :
return ( ref or ' ' ) . replace ( ' / ' , ' ' )
2011-02-08 12:56:53 +00:00
def _get_analytic_lines ( self , cr , uid , id , context = None ) :
if context is None :
context = { }
2010-10-17 16:42:26 +00:00
inv = self . browse ( cr , uid , id )
2008-07-22 15:11:28 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2013-05-17 08:00:31 +00:00
company_currency = self . pool [ ' res.company ' ] . browse ( cr , uid , inv . company_id . id ) . currency_id . id
2008-07-22 15:11:28 +00:00
if inv . type in ( ' out_invoice ' , ' in_refund ' ) :
sign = 1
else :
sign = - 1
2011-02-08 12:56:53 +00:00
iml = self . pool . get ( ' account.invoice.line ' ) . move_line_get ( cr , uid , inv . id , context = context )
2008-07-22 15:11:28 +00:00
for il in iml :
if il [ ' account_analytic_id ' ] :
if inv . type in ( ' in_invoice ' , ' in_refund ' ) :
ref = inv . reference
else :
ref = self . _convert_ref ( cr , uid , inv . number )
2010-10-17 16:42:26 +00:00
if not inv . journal_id . analytic_journal_id :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Analytic Journal! ' ) , _ ( " You have to define an analytic journal on the ' %s ' journal! " ) % ( inv . journal_id . name , ) )
2008-07-22 15:11:28 +00:00
il [ ' analytic_lines ' ] = [ ( 0 , 0 , {
' name ' : il [ ' name ' ] ,
' date ' : inv [ ' date_invoice ' ] ,
' account_id ' : il [ ' account_analytic_id ' ] ,
' unit_amount ' : il [ ' quantity ' ] ,
' amount ' : cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , il [ ' price ' ] , context = { ' date ' : inv . date_invoice } ) * sign ,
' product_id ' : il [ ' product_id ' ] ,
' product_uom_id ' : il [ ' uos_id ' ] ,
' general_account_id ' : il [ ' account_id ' ] ,
2010-10-17 16:42:26 +00:00
' journal_id ' : inv . journal_id . analytic_journal_id . id ,
2008-07-22 15:11:28 +00:00
' ref ' : ref ,
} ) ]
return iml
2009-03-15 16:29:55 +00:00
def action_date_assign ( self , cr , uid , ids , * args ) :
for inv in self . browse ( cr , uid , ids ) :
res = self . onchange_payment_term_date_invoice ( cr , uid , inv . id , inv . payment_term . id , inv . date_invoice )
if res and res [ ' value ' ] :
self . write ( cr , uid , [ inv . id ] , res [ ' value ' ] )
return True
2010-05-17 13:34:31 +00:00
2010-05-10 12:27:32 +00:00
def finalize_invoice_move_lines ( self , cr , uid , invoice_browse , move_lines ) :
""" finalize_invoice_move_lines(cr, uid, invoice, move_lines) -> move_lines
2010-05-17 13:34:31 +00:00
Hook method to be overridden in additional modules to verify and possibly alter the
2010-05-10 12:27:32 +00:00
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 ( ) )
2010-05-17 13:34:31 +00:00
: return : the ( possibly updated ) final move_lines to create for this invoice
2010-05-10 12:27:32 +00:00
"""
return move_lines
2010-02-24 08:47:01 +00:00
2010-02-22 05:35:21 +00:00
def check_tax_lines ( self , cr , uid , inv , compute_taxes , ait_obj ) :
2013-05-17 07:35:16 +00:00
company_currency = self . pool [ ' res.company ' ] . browse ( cr , uid , inv . company_id . id ) . currency_id
2010-02-22 05:35:21 +00:00
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
2012-07-10 21:21:15 +00:00
key = ( tax . tax_code_id . id , tax . base_code_id . id , tax . account_id . id , tax . account_analytic_id . id )
2010-02-22 05:35:21 +00:00
tax_key . append ( key )
if not key in compute_taxes :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Global taxes defined, but they are not in invoice lines ! ' ) )
2010-02-22 05:35:21 +00:00
base = compute_taxes [ key ] [ ' base ' ]
2013-05-17 07:35:16 +00:00
if abs ( base - tax . base ) > company_currency . rounding :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Tax base different! \n Click on compute to update the tax base. ' ) )
2010-02-22 05:35:21 +00:00
for key in compute_taxes :
if not key in tax_key :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' Taxes are missing! \n Click on compute button. ' ) )
2010-02-22 05:35:21 +00:00
2012-09-11 13:17:08 +00:00
def compute_invoice_totals ( self , cr , uid , inv , company_currency , ref , invoice_move_lines , context = None ) :
2012-07-10 12:03:16 +00:00
if context is None :
context = { }
2010-02-22 05:35:21 +00:00
total = 0
total_currency = 0
2010-04-16 13:45:24 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2010-02-22 05:35:21 +00:00
for i in invoice_move_lines :
if inv . currency_id . id != company_currency :
2012-07-10 12:03:16 +00:00
context . update ( { ' date ' : inv . date_invoice or time . strftime ( ' % Y- % m- %d ' ) } )
2010-02-22 05:35:21 +00:00
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 ' ] ,
2012-07-10 12:03:16 +00:00
context = context )
2010-02-22 05:35:21 +00:00
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
2010-02-24 08:47:01 +00:00
2010-02-22 05:35:21 +00:00
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 . """
2010-02-24 08:48:52 +00:00
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 " ) )
2010-02-24 08:47:01 +00:00
2010-02-22 05:35:21 +00:00
def group_lines ( self , cr , uid , iml , line , inv ) :
2010-02-23 05:38:30 +00:00
""" Merge account move lines (and hence analytic lines) if invoice line hashcodes are equals """
2010-02-22 05:35:21 +00:00
if inv . journal_id . group_invoice_lines :
line2 = { }
for x , y , l in line :
tmp = self . inv_line_characteristic_hashcode ( inv , l )
2010-02-24 08:47:01 +00:00
2010-02-22 05:35:21 +00:00
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
2009-03-15 16:29:55 +00:00
2011-12-14 11:15:27 +00:00
def action_move_create ( self , cr , uid , ids , context = None ) :
2010-02-22 05:35:21 +00:00
""" Creates invoice related analytics and financial move lines """
2008-07-22 15:11:28 +00:00
ait_obj = self . pool . get ( ' account.invoice.tax ' )
cur_obj = self . pool . get ( ' res.currency ' )
2011-11-11 06:05:23 +00:00
period_obj = self . pool . get ( ' account.period ' )
2011-12-21 05:28:15 +00:00
payment_term_obj = self . pool . get ( ' account.payment.term ' )
journal_obj = self . pool . get ( ' account.journal ' )
move_obj = self . pool . get ( ' account.move ' )
2011-12-14 11:15:27 +00:00
if context is None :
context = { }
2011-12-21 10:12:36 +00:00
for inv in self . browse ( cr , uid , ids , context = context ) :
2010-08-14 13:58:01 +00:00
if not inv . journal_id . sequence_id :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Please define sequence on the journal related to this invoice. ' ) )
2010-06-18 07:18:07 +00:00
if not inv . invoice_line :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Invoice Lines! ' ) , _ ( ' Please create some invoice lines. ' ) )
2008-07-22 15:11:28 +00:00
if inv . move_id :
continue
2012-08-06 15:44:10 +00:00
2011-12-21 10:12:36 +00:00
ctx = context . copy ( )
ctx . update ( { ' lang ' : inv . partner_id . lang } )
2008-10-14 15:05:12 +00:00
if not inv . date_invoice :
2012-02-14 12:25:20 +00:00
self . write ( cr , uid , [ inv . id ] , { ' date_invoice ' : fields . date . context_today ( self , cr , uid , context = context ) } , context = ctx )
2013-05-17 07:35:16 +00:00
company_currency = self . pool [ ' res.company ' ] . browse ( cr , uid , inv . company_id . id ) . currency_id . id
2008-07-22 15:11:28 +00:00
# create the analytical lines
# one move line per invoice line
2011-12-15 05:59:33 +00:00
iml = self . _get_analytic_lines ( cr , uid , inv . id , context = ctx )
2008-07-22 15:11:28 +00:00
# check if taxes are all computed
2010-11-04 18:43:48 +00:00
compute_taxes = ait_obj . compute ( cr , uid , inv . id , context = ctx )
2010-02-22 05:35:21 +00:00
self . check_tax_lines ( cr , uid , inv , compute_taxes , ait_obj )
2008-07-22 15:11:28 +00:00
2012-01-04 06:38:07 +00:00
# I disabled the check_total feature
2012-10-24 09:13:13 +00:00
group_check_total_id = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' account ' , ' group_supplier_inv_check_total ' ) [ 1 ]
group_check_total = self . pool . get ( ' res.groups ' ) . browse ( cr , uid , group_check_total_id , context = context )
if group_check_total and uid in [ x . id for x in group_check_total . users ] :
if ( inv . type in ( ' in_invoice ' , ' in_refund ' ) and abs ( inv . check_total - inv . amount_total ) > = ( inv . currency_id . rounding / 2.0 ) ) :
2013-04-30 07:25:47 +00:00
raise osv . except_osv ( _ ( ' Bad Total! ' ) , _ ( ' Please verify the price of the invoice! \n The encoded total does not match the computed total. ' ) )
2009-01-27 10:06:08 +00:00
2010-09-07 03:43:06 +00:00
if inv . payment_term :
total_fixed = total_percent = 0
for line in inv . payment_term . line_ids :
if line . value == ' fixed ' :
total_fixed + = line . value_amount
if line . value == ' procent ' :
total_percent + = line . value_amount
2010-10-20 13:58:03 +00:00
total_fixed = ( total_fixed * 100 ) / ( inv . amount_total or 1.0 )
2010-09-07 03:43:06 +00:00
if ( total_fixed + total_percent ) > 100 :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( " Cannot create the invoice. \n The related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. In order to avoid rounding issues, the latest line of your payment term must be of type ' balance ' . " ) )
2010-09-07 03:43:06 +00:00
2008-07-22 15:11:28 +00:00
# one move line per tax line
iml + = ait_obj . move_line_get ( cr , uid , inv . id )
2010-07-02 05:16:21 +00:00
2010-08-30 06:28:31 +00:00
entry_type = ' '
2008-07-22 15:11:28 +00:00
if inv . type in ( ' in_invoice ' , ' in_refund ' ) :
ref = inv . reference
2010-06-17 13:17:58 +00:00
entry_type = ' journal_pur_voucher '
2010-06-18 07:34:50 +00:00
if inv . type == ' in_refund ' :
2010-06-17 13:17:58 +00:00
entry_type = ' cont_voucher '
2008-07-22 15:11:28 +00:00
else :
ref = self . _convert_ref ( cr , uid , inv . number )
2010-06-17 13:17:58 +00:00
entry_type = ' journal_sale_vou '
2010-06-18 07:34:50 +00:00
if inv . type == ' out_refund ' :
2010-06-17 13:17:58 +00:00
entry_type = ' cont_voucher '
2008-07-22 15:11:28 +00:00
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
2012-09-11 13:17:08 +00:00
total , total_currency , iml = self . compute_invoice_totals ( cr , uid , inv , company_currency , ref , iml , context = ctx )
2008-07-22 15:11:28 +00:00
acc_id = inv . account_id . id
2013-02-15 09:58:01 +00:00
name = inv [ ' name ' ] or inv [ ' supplier_invoice_number ' ] or ' / '
2008-07-22 15:11:28 +00:00
totlines = False
if inv . payment_term :
2011-12-21 05:28:15 +00:00
totlines = payment_term_obj . compute ( cr ,
uid , inv . payment_term . id , total , inv . date_invoice or False , context = ctx )
2008-07-22 15:11:28 +00:00
if totlines :
res_amount_currency = total_currency
i = 0
2011-09-14 04:51:21 +00:00
ctx . update ( { ' date ' : inv . date_invoice } )
2008-07-22 15:11:28 +00:00
for t in totlines :
if inv . currency_id . id != company_currency :
2011-09-09 09:38:44 +00:00
amount_currency = cur_obj . compute ( cr , uid , company_currency , inv . currency_id . id , t [ 1 ] , context = ctx )
2008-07-22 15:11:28 +00:00
else :
amount_currency = False
# last line add the diff
res_amount_currency - = amount_currency or 0
i + = 1
if i == len ( totlines ) :
amount_currency + = res_amount_currency
iml . append ( {
' type ' : ' dest ' ,
' name ' : name ,
' price ' : t [ 1 ] ,
' account_id ' : acc_id ,
' date_maturity ' : t [ 0 ] ,
' amount_currency ' : diff_currency_p \
2011-10-17 14:14:48 +00:00
and amount_currency or False ,
2008-07-22 15:11:28 +00:00
' currency_id ' : diff_currency_p \
and inv . currency_id . id or False ,
' ref ' : ref ,
} )
else :
iml . append ( {
' type ' : ' dest ' ,
' name ' : name ,
' price ' : total ,
' account_id ' : acc_id ,
2010-10-11 05:51:53 +00:00
' date_maturity ' : inv . date_due or False ,
2008-07-22 15:11:28 +00:00
' amount_currency ' : diff_currency_p \
and total_currency or False ,
' currency_id ' : diff_currency_p \
and inv . currency_id . id or False ,
' ref ' : ref
} )
2008-10-14 15:05:12 +00:00
date = inv . date_invoice or time . strftime ( ' % Y- % m- %d ' )
2008-12-26 18:11:02 +00:00
2013-03-06 15:01:42 +00:00
part = self . pool . get ( " res.partner " ) . _find_accounting_partner ( inv . partner_id )
2012-11-26 09:26:58 +00:00
line = map ( lambda x : ( 0 , 0 , self . line_get_convert ( cr , uid , x , part . id , date , context = ctx ) ) , iml )
2008-07-22 15:11:28 +00:00
2010-02-22 05:35:21 +00:00
line = self . group_lines ( cr , uid , iml , line , inv )
2008-12-26 18:11:02 +00:00
2010-08-26 04:20:06 +00:00
journal_id = inv . journal_id . id
2011-12-21 05:28:15 +00:00
journal = journal_obj . browse ( cr , uid , journal_id , context = ctx )
2008-07-22 15:11:28 +00:00
if journal . centralisation :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' User Error! ' ) ,
2012-07-25 07:33:57 +00:00
_ ( ' You cannot create an invoice on a centralized journal. Uncheck the centralized counterpart box in the related journal from the configuration menu. ' ) )
2010-04-30 11:25:55 +00:00
2010-04-30 12:01:26 +00:00
line = self . finalize_invoice_move_lines ( cr , uid , inv , line )
2010-04-30 11:25:55 +00:00
2010-07-27 14:33:07 +00:00
move = {
2010-08-24 12:33:45 +00:00
' ref ' : inv . reference and inv . reference or inv . name ,
2010-08-14 05:05:55 +00:00
' line_id ' : line ,
' journal_id ' : journal_id ,
' date ' : date ,
2013-05-16 08:52:54 +00:00
' narration ' : inv . comment ,
' company_id ' : inv . company_id . id ,
2010-07-27 14:33:07 +00:00
}
2010-08-30 06:28:31 +00:00
period_id = inv . period_id and inv . period_id . id or False
2013-04-18 10:39:07 +00:00
ctx . update ( company_id = inv . company_id . id )
2008-08-25 12:25:04 +00:00
if not period_id :
2011-11-14 11:47:11 +00:00
period_ids = period_obj . find ( cr , uid , inv . date_invoice , context = ctx )
2011-11-11 09:00:25 +00:00
period_id = period_ids and period_ids [ 0 ] or False
2008-08-25 12:25:04 +00:00
if period_id :
move [ ' period_id ' ] = period_id
2008-07-22 15:11:28 +00:00
for i in line :
2008-08-25 12:25:04 +00:00
i [ 2 ] [ ' period_id ' ] = period_id
2008-12-15 10:41:24 +00:00
2012-11-05 13:28:52 +00:00
ctx . update ( invoice = inv )
2011-12-21 10:12:36 +00:00
move_id = move_obj . create ( cr , uid , move , context = ctx )
2012-01-03 12:33:39 +00:00
new_move_name = move_obj . browse ( cr , uid , move_id , context = ctx ) . name
2008-07-22 15:11:28 +00:00
# make the invoice point to that move
2011-12-21 05:28:15 +00:00
self . write ( cr , uid , [ inv . id ] , { ' move_id ' : move_id , ' period_id ' : period_id , ' move_name ' : new_move_name } , context = ctx )
2010-07-21 18:37:19 +00:00
# Pass invoice in context in method post: used if you want to get the same
# account move reference when creating the same invoice after a cancelled one:
2011-12-21 05:28:15 +00:00
move_obj . post ( cr , uid , [ move_id ] , context = ctx )
2008-07-22 15:11:28 +00:00
self . _log_event ( cr , uid , ids )
return True
2012-08-06 15:44:10 +00:00
2012-03-19 10:38:23 +00:00
def invoice_validate ( self , cr , uid , ids , context = None ) :
self . write ( cr , uid , ids , { ' state ' : ' open ' } , context = context )
return True
2008-07-22 15:11:28 +00:00
2009-01-06 13:31:53 +00:00
def line_get_convert ( self , cr , uid , x , part , date , context = None ) :
2008-07-22 15:11:28 +00:00
return {
' date_maturity ' : x . get ( ' date_maturity ' , False ) ,
2010-12-27 07:37:46 +00:00
' partner_id ' : part ,
' name ' : x [ ' name ' ] [ : 64 ] ,
2009-01-28 18:33:27 +00:00
' date ' : date ,
2010-12-27 07:37:46 +00:00
' 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 ) ,
2008-07-22 15:11:28 +00:00
' tax_code_id ' : x . get ( ' tax_code_id ' , False ) ,
' tax_amount ' : x . get ( ' tax_amount ' , False ) ,
2010-12-27 07:37:46 +00:00
' 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 ) ,
2012-07-12 21:09:24 +00:00
' analytic_account_id ' : x . get ( ' account_analytic_id ' , False ) ,
2008-07-22 15:11:28 +00:00
}
2010-10-25 09:54:30 +00:00
def action_number ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
2010-08-14 13:58:01 +00:00
#TODO: not correct fix but required a frech values before reading it.
self . write ( cr , uid , ids , { } )
2010-08-17 06:15:57 +00:00
2010-11-19 13:48:01 +00:00
for obj_inv in self . browse ( cr , uid , ids , context = context ) :
2010-08-14 13:58:01 +00:00
invtype = obj_inv . type
number = obj_inv . number
move_id = obj_inv . move_id and obj_inv . move_id . id or False
2010-10-21 06:58:57 +00:00
reference = obj_inv . reference or ' '
2010-08-14 13:58:01 +00:00
2012-12-19 13:00:24 +00:00
self . write ( cr , uid , ids , { ' internal_number ' : number } )
2010-08-17 06:15:57 +00:00
2010-08-14 13:58:01 +00:00
if invtype in ( ' in_invoice ' , ' in_refund ' ) :
2010-10-21 06:58:57 +00:00
if not reference :
ref = self . _convert_ref ( cr , uid , number )
else :
ref = reference
2010-08-14 13:58:01 +00:00
else :
ref = self . _convert_ref ( cr , uid , number )
cr . execute ( ' UPDATE account_move SET ref= %s ' \
' WHERE id= %s AND (ref is null OR ref = \' \' ) ' ,
( ref , move_id ) )
cr . execute ( ' UPDATE account_move_line SET ref= %s ' \
' WHERE move_id= %s AND (ref is null OR ref = \' \' ) ' ,
( ref , move_id ) )
cr . execute ( ' UPDATE account_analytic_line SET ref= %s ' \
' FROM account_move_line ' \
' WHERE account_move_line.move_id = %s ' \
' AND account_analytic_line.move_id = account_move_line.id ' ,
2008-07-22 15:11:28 +00:00
( ref , move_id ) )
return True
2012-11-27 12:24:16 +00:00
def action_cancel ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
2008-07-22 15:11:28 +00:00
account_move_obj = self . pool . get ( ' account.move ' )
2010-01-27 06:40:35 +00:00
invoices = self . read ( cr , uid , ids , [ ' move_id ' , ' payment_ids ' ] )
2011-01-05 12:08:11 +00:00
move_ids = [ ] # ones that we will need to remove
2008-07-22 15:11:28 +00:00
for i in invoices :
2010-06-18 13:55:20 +00:00
if i [ ' move_id ' ] :
2011-01-05 12:08:11 +00:00
move_ids . append ( i [ ' move_id ' ] [ 0 ] )
2010-06-18 13:55:20 +00:00
if i [ ' payment_ids ' ] :
2010-05-12 10:41:58 +00:00
account_move_line_obj = self . pool . get ( ' account.move.line ' )
2010-10-11 05:51:53 +00:00
pay_ids = account_move_line_obj . browse ( cr , uid , i [ ' payment_ids ' ] )
2010-05-12 10:41:58 +00:00
for move_line in pay_ids :
if move_line . reconcile_partial_id and move_line . reconcile_partial_id . line_partial_ids :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' You cannot cancel an invoice which is partially paid. You need to unreconcile related payment entries first. ' ) )
2010-05-12 10:41:58 +00:00
2011-01-05 12:08:11 +00:00
# First, set the invoices as cancelled and detach the move ids
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' , ' move_id ' : False } )
2011-01-05 12:08:11 +00:00
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 )
2010-06-16 11:51:39 +00:00
self . _log_event ( cr , uid , ids , - 1.0 , ' Cancel Invoice ' )
2008-07-22 15:11:28 +00:00
return True
###################
def list_distinct_taxes ( self , cr , uid , ids ) :
invoices = self . browse ( cr , uid , ids )
taxes = { }
for inv in invoices :
for tax in inv . tax_line :
if not tax [ ' name ' ] in taxes :
taxes [ tax [ ' name ' ] ] = { ' name ' : tax [ ' name ' ] }
return taxes . values ( )
def _log_event ( self , cr , uid , ids , factor = 1.0 , name = ' Open Invoice ' ) :
2010-05-27 07:08:59 +00:00
#TODO: implement messages system
return True
2008-07-22 15:11:28 +00:00
2009-01-06 13:31:53 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
2010-10-11 05:51:53 +00:00
if not ids :
2008-07-22 15:11:28 +00:00
return [ ]
types = {
2013-06-06 16:32:59 +00:00
' out_invoice ' : _ ( ' Invoice ' ) ,
' in_invoice ' : _ ( ' Supplier Invoice ' ) ,
' out_refund ' : _ ( ' Refund ' ) ,
' in_refund ' : _ ( ' Supplier Refund ' ) ,
2008-07-22 15:11:28 +00:00
}
2013-06-06 16:32:59 +00:00
return [ ( r [ ' id ' ] , ' %s %s ' % ( r [ ' number ' ] or types [ r [ ' type ' ] ] , r [ ' name ' ] or ' ' ) ) for r in self . read ( cr , uid , ids , [ ' type ' , ' number ' , ' name ' ] , context , load = ' _classic_write ' ) ]
2008-07-22 15:11:28 +00:00
2009-12-09 11:43:34 +00:00
def name_search ( self , cr , user , name , args = None , operator = ' ilike ' , context = None , limit = 100 ) :
2008-07-22 15:11:28 +00:00
if not args :
2010-08-30 06:28:31 +00:00
args = [ ]
2009-01-06 13:31:53 +00:00
if context is None :
2010-08-30 06:28:31 +00:00
context = { }
2008-07-22 15:11:28 +00:00
ids = [ ]
if name :
2010-11-10 12:13:05 +00:00
ids = self . search ( cr , user , [ ( ' number ' , ' = ' , name ) ] + args , limit = limit , context = context )
2008-07-22 15:11:28 +00:00
if not ids :
2010-11-10 12:13:05 +00:00
ids = self . search ( cr , user , [ ( ' name ' , operator , name ) ] + args , limit = limit , context = context )
2008-07-22 15:11:28 +00:00
return self . name_get ( cr , user , ids , context )
2012-08-29 08:39:33 +00:00
def _refund_cleanup_lines ( self , cr , uid , lines , context = None ) :
2013-02-15 09:27:27 +00:00
""" Convert records to dict of values suitable for one2many line creation
: param list ( browse_record ) lines : records to convert
: return : list of command tuple for one2many line creation [ ( 0 , 0 , dict of valueis ) , . . . ]
"""
2012-10-12 12:24:06 +00:00
clean_lines = [ ]
2008-07-22 15:11:28 +00:00
for line in lines :
2012-10-12 12:24:06 +00:00
clean_line = { }
for field in line . _all_columns . keys ( ) :
if line . _all_columns [ field ] . column . _type == ' many2one ' :
clean_line [ field ] = line [ field ] . id
2012-10-16 16:22:51 +00:00
elif line . _all_columns [ field ] . column . _type not in [ ' many2many ' , ' one2many ' ] :
2012-10-12 12:24:06 +00:00
clean_line [ field ] = line [ field ]
2012-10-16 16:22:51 +00:00
elif field == ' invoice_line_tax_id ' :
tax_list = [ ]
for tax in line [ field ] :
tax_list . append ( tax . id )
clean_line [ field ] = [ ( 6 , 0 , tax_list ) ]
2012-10-12 12:24:06 +00:00
clean_lines . append ( clean_line )
return map ( lambda x : ( 0 , 0 , x ) , clean_lines )
def _prepare_refund ( self , cr , uid , invoice , date = None , period_id = None , description = None , journal_id = None , context = None ) :
2012-10-10 15:37:24 +00:00
""" Prepare the dict of values to create the new refund from the invoice.
This method may be overridden to implement custom
refund generation ( making sure to call super ( ) to establish
a clean extension chain ) .
: param integer invoice_id : id of the invoice to refund
: param dict invoice : read of the invoice to refund
2012-10-12 12:24:06 +00:00
: param string date : refund creation date from the wizard
2012-10-10 15:37:24 +00:00
: param integer period_id : force account . period from the wizard
2012-10-12 12:24:06 +00:00
: param string description : description of the refund from the wizard
2012-10-10 15:37:24 +00:00
: param integer journal_id : account . journal from the wizard
: return : dict of value to create ( ) the refund
"""
2010-10-12 05:17:13 +00:00
obj_journal = self . pool . get ( ' account.journal ' )
2008-07-22 15:11:28 +00:00
2012-08-29 08:39:33 +00:00
type_dict = {
' out_invoice ' : ' out_refund ' , # Customer Invoice
' in_invoice ' : ' in_refund ' , # Supplier Invoice
' out_refund ' : ' out_invoice ' , # Customer Refund
' in_refund ' : ' in_invoice ' , # Supplier Refund
}
2012-10-12 12:24:06 +00:00
invoice_data = { }
for field in [ ' name ' , ' reference ' , ' comment ' , ' date_due ' , ' partner_id ' , ' company_id ' ,
2012-12-18 17:42:25 +00:00
' account_id ' , ' currency_id ' , ' payment_term ' , ' user_id ' , ' fiscal_position ' ] :
2012-10-12 12:24:06 +00:00
if invoice . _all_columns [ field ] . column . _type == ' many2one ' :
invoice_data [ field ] = invoice [ field ] . id
2010-06-18 09:33:36 +00:00
else :
2012-12-18 17:42:25 +00:00
invoice_data [ field ] = invoice [ field ] if invoice [ field ] else False
2008-07-22 15:11:28 +00:00
2012-10-12 12:24:06 +00:00
invoice_lines = self . _refund_cleanup_lines ( cr , uid , invoice . invoice_line , context = context )
2010-08-14 05:05:55 +00:00
2012-10-12 12:24:06 +00:00
tax_lines = filter ( lambda l : l [ ' manual ' ] , invoice . tax_line )
2012-08-29 08:39:33 +00:00
tax_lines = self . _refund_cleanup_lines ( cr , uid , tax_lines , context = context )
if journal_id :
refund_journal_ids = [ journal_id ]
elif invoice [ ' type ' ] == ' in_invoice ' :
refund_journal_ids = obj_journal . search ( cr , uid , [ ( ' type ' , ' = ' , ' purchase_refund ' ) ] , context = context )
else :
refund_journal_ids = obj_journal . search ( cr , uid , [ ( ' type ' , ' = ' , ' sale_refund ' ) ] , context = context )
if not date :
date = time . strftime ( ' % Y- % m- %d ' )
2012-10-12 12:24:06 +00:00
invoice_data . update ( {
2012-08-29 08:39:33 +00:00
' type ' : type_dict [ invoice [ ' type ' ] ] ,
' date_invoice ' : date ,
' state ' : ' draft ' ,
' number ' : False ,
' invoice_line ' : invoice_lines ,
' tax_line ' : tax_lines ,
2012-10-12 12:24:06 +00:00
' journal_id ' : refund_journal_ids and refund_journal_ids [ 0 ] or False ,
2012-08-29 08:39:33 +00:00
} )
if period_id :
2012-12-18 17:42:25 +00:00
invoice_data [ ' period_id ' ] = period_id
2012-08-29 08:39:33 +00:00
if description :
2012-12-18 17:42:25 +00:00
invoice_data [ ' name ' ] = description
2012-10-12 12:24:06 +00:00
return invoice_data
2012-08-29 08:39:33 +00:00
def refund ( self , cr , uid , ids , date = None , period_id = None , description = None , journal_id = None , context = None ) :
new_ids = [ ]
2012-10-12 12:24:06 +00:00
for invoice in self . browse ( cr , uid , ids , context = context ) :
2012-12-18 17:42:25 +00:00
invoice = self . _prepare_refund ( cr , uid , invoice ,
2012-08-29 15:34:48 +00:00
date = date ,
period_id = period_id ,
description = description ,
journal_id = journal_id ,
context = context )
2008-07-22 15:11:28 +00:00
# create the new invoice
2012-08-29 08:39:33 +00:00
new_ids . append ( self . create ( cr , uid , invoice , context = context ) )
2010-12-27 07:37:46 +00:00
2008-07-22 15:11:28 +00:00
return new_ids
2009-01-06 13:31:53 +00:00
def pay_and_reconcile ( self , cr , uid , ids , pay_amount , pay_account_id , period_id , pay_journal_id , writeoff_acc_id , writeoff_period_id , writeoff_journal_id , context = None , name = ' ' ) :
if context is None :
context = { }
2008-07-22 15:11:28 +00:00
#TODO check if we can use different period for payment and the writeoff line
2012-07-25 07:33:57 +00:00
assert len ( ids ) == 1 , " Can only pay one invoice at a time. "
2010-11-19 13:48:01 +00:00
invoice = self . browse ( cr , uid , ids [ 0 ] , context = context )
2008-07-22 15:11:28 +00:00
src_account_id = invoice . account_id . id
2008-08-25 15:41:01 +00:00
# Take the seq as name for move
2008-07-22 15:11:28 +00:00
types = { ' out_invoice ' : - 1 , ' in_invoice ' : 1 , ' out_refund ' : 1 , ' in_refund ' : - 1 }
direction = types [ invoice . type ]
2008-08-25 15:41:01 +00:00
#take the choosen date
2008-12-15 12:15:02 +00:00
if ' date_p ' in context and context [ ' date_p ' ] :
2008-08-25 15:41:01 +00:00
date = context [ ' date_p ' ]
else :
date = time . strftime ( ' % Y- % m- %d ' )
2009-11-25 09:31:44 +00:00
2009-11-02 08:52:13 +00:00
# Take the amount in currency and the currency of the payment
if ' amount_currency ' in context and context [ ' amount_currency ' ] and ' currency_id ' in context and context [ ' currency_id ' ] :
amount_currency = context [ ' amount_currency ' ]
currency_id = context [ ' currency_id ' ]
else :
amount_currency = False
currency_id = False
2010-06-18 07:34:50 +00:00
2010-06-18 08:28:11 +00:00
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 '
2009-12-10 06:15:40 +00:00
if invoice . type in ( ' in_invoice ' , ' in_refund ' ) :
ref = invoice . reference
else :
2010-02-09 08:31:46 +00:00
ref = self . _convert_ref ( cr , uid , invoice . number )
2013-04-07 21:23:33 +00:00
partner = self . pool [ ' res.partner ' ] . _find_accounting_partner ( invoice . partner_id )
2009-11-02 08:52:13 +00:00
# Pay attention to the sign for both debit/credit AND amount_currency
2008-07-22 15:11:28 +00:00
l1 = {
' debit ' : direction * pay_amount > 0 and direction * pay_amount ,
' credit ' : direction * pay_amount < 0 and - direction * pay_amount ,
' account_id ' : src_account_id ,
2012-11-28 11:12:52 +00:00
' partner_id ' : partner . id ,
2009-12-10 06:15:40 +00:00
' ref ' : ref ,
2009-06-25 13:34:42 +00:00
' date ' : date ,
2009-11-02 08:52:13 +00:00
' currency_id ' : currency_id ,
' amount_currency ' : amount_currency and direction * amount_currency or 0.0 ,
2009-12-01 14:54:18 +00:00
' company_id ' : invoice . company_id . id ,
2008-07-22 15:11:28 +00:00
}
l2 = {
' debit ' : direction * pay_amount < 0 and - direction * pay_amount ,
' credit ' : direction * pay_amount > 0 and direction * pay_amount ,
' account_id ' : pay_account_id ,
2012-11-28 11:12:52 +00:00
' partner_id ' : partner . id ,
2009-12-10 06:15:40 +00:00
' ref ' : ref ,
2009-06-25 13:34:42 +00:00
' date ' : date ,
2009-11-02 08:52:13 +00:00
' currency_id ' : currency_id ,
' amount_currency ' : amount_currency and - direction * amount_currency or 0.0 ,
2009-12-01 14:54:18 +00:00
' company_id ' : invoice . company_id . id ,
2008-07-22 15:11:28 +00:00
}
2009-01-26 17:57:57 +00:00
if not name :
name = invoice . invoice_line and invoice . invoice_line [ 0 ] . name or invoice . number
2008-12-15 11:41:34 +00:00
l1 [ ' name ' ] = name
l2 [ ' name ' ] = name
2008-07-22 15:11:28 +00:00
lines = [ ( 0 , 0 , l1 ) , ( 0 , 0 , l2 ) ]
2011-12-06 10:13:54 +00:00
move = { ' ref ' : ref , ' line_id ' : lines , ' journal_id ' : pay_journal_id , ' period_id ' : period_id , ' date ' : date }
2009-07-24 06:17:35 +00:00
move_id = self . pool . get ( ' account.move ' ) . create ( cr , uid , move , context = context )
2008-07-22 15:11:28 +00:00
line_ids = [ ]
total = 0.0
line = self . pool . get ( ' account.move.line ' )
2009-11-26 13:54:00 +00:00
move_ids = [ move_id , ]
if invoice . move_id :
move_ids . append ( invoice . move_id . id )
2010-06-10 13:34:19 +00:00
cr . execute ( ' SELECT id FROM account_move_line ' \
2010-06-16 11:51:39 +00:00
' WHERE move_id IN %s ' ,
2010-06-10 13:34:19 +00:00
( ( move_id , invoice . move_id . id ) , ) )
2008-07-22 15:11:28 +00:00
lines = line . browse ( cr , uid , map ( lambda x : x [ 0 ] , cr . fetchall ( ) ) )
2009-01-26 22:22:32 +00:00
for l in lines + invoice . payment_ids :
2010-07-29 07:10:03 +00:00
if l . account_id . id == src_account_id :
2008-07-22 15:11:28 +00:00
line_ids . append ( l . id )
total + = ( l . debit or 0.0 ) - ( l . credit or 0.0 )
2010-07-20 11:02:23 +00:00
inv_id , name = self . name_get ( cr , uid , [ invoice . id ] , context = context ) [ 0 ]
2010-03-06 20:52:19 +00:00
if ( not round ( total , self . pool . get ( ' decimal.precision ' ) . precision_get ( cr , uid , ' Account ' ) ) ) or writeoff_acc_id :
2008-07-22 15:11:28 +00:00
self . pool . get ( ' account.move.line ' ) . reconcile ( cr , uid , line_ids , ' manual ' , writeoff_acc_id , writeoff_period_id , writeoff_journal_id , context )
else :
2010-11-18 12:24:59 +00:00
code = invoice . currency_id . symbol
2010-10-17 17:30:00 +00:00
# TODO: use currency's formatting function
2012-12-19 13:00:24 +00:00
msg = _ ( " Invoice partially paid: %s %s of %s %s ( %s %s remaining). " ) % \
( pay_amount , code , invoice . amount_total , code , total , code )
2012-08-17 10:03:02 +00:00
self . message_post ( cr , uid , [ inv_id ] , body = msg , context = context )
2008-07-22 15:11:28 +00:00
self . pool . get ( ' account.move.line ' ) . reconcile_partial ( cr , uid , line_ids , ' manual ' , context )
2008-12-20 04:57:05 +00:00
2009-01-02 09:03:46 +00:00
# Update the stored value (fields.function), so we write to trigger recompute
2008-12-20 04:57:05 +00:00
self . pool . get ( ' account.invoice ' ) . write ( cr , uid , ids , { } , context = context )
2008-07-22 15:11:28 +00:00
return True
2012-08-06 15:44:10 +00:00
2006-12-07 13:41:40 +00:00
class account_invoice_line ( osv . osv ) :
2011-08-19 05:50:29 +00:00
2011-09-13 10:46:53 +00:00
def _amount_line ( self , cr , uid , ids , prop , unknow_none , unknow_dict ) :
2008-07-22 15:11:28 +00:00
res = { }
2010-06-05 21:39:55 +00:00
tax_obj = self . pool . get ( ' account.tax ' )
cur_obj = self . pool . get ( ' res.currency ' )
2008-07-22 15:11:28 +00:00
for line in self . browse ( cr , uid , ids ) :
2010-06-05 21:39:55 +00:00
price = line . price_unit * ( 1 - ( line . discount or 0.0 ) / 100.0 )
2012-03-05 06:48:45 +00:00
taxes = tax_obj . compute_all ( cr , uid , line . invoice_line_tax_id , price , line . quantity , product = line . product_id , partner = line . invoice_id . partner_id )
2010-06-05 21:39:55 +00:00
res [ line . id ] = taxes [ ' total ' ]
2009-03-19 13:02:14 +00:00
if line . invoice_id :
cur = line . invoice_id . currency_id
res [ line . id ] = cur_obj . round ( cr , uid , cur , res [ line . id ] )
2008-07-22 15:11:28 +00:00
return res
2009-01-06 13:31:53 +00:00
def _price_unit_default ( self , cr , uid , context = None ) :
if context is None :
context = { }
2012-01-04 06:38:07 +00:00
if context . get ( ' check_total ' , False ) :
2008-07-22 15:11:28 +00:00
t = context [ ' check_total ' ]
for l in context . get ( ' invoice_line ' , { } ) :
2009-07-02 07:41:25 +00:00
if isinstance ( l , ( list , tuple ) ) and len ( l ) > = 3 and l [ 2 ] :
2008-07-22 15:11:28 +00:00
tax_obj = self . pool . get ( ' account.tax ' )
p = l [ 2 ] . get ( ' price_unit ' , 0 ) * ( 1 - l [ 2 ] . get ( ' discount ' , 0 ) / 100.0 )
t = t - ( p * l [ 2 ] . get ( ' quantity ' ) )
taxes = l [ 2 ] . get ( ' invoice_line_tax_id ' )
if len ( taxes [ 0 ] ) > = 3 and taxes [ 0 ] [ 2 ] :
2011-03-08 16:40:37 +00:00
taxes = tax_obj . browse ( cr , uid , list ( taxes [ 0 ] [ 2 ] ) )
2012-03-05 06:48:45 +00:00
for tax in tax_obj . compute_all ( cr , uid , taxes , p , l [ 2 ] . get ( ' quantity ' ) , l [ 2 ] . get ( ' product_id ' , False ) , context . get ( ' partner_id ' , False ) ) [ ' taxes ' ] :
2008-07-22 15:11:28 +00:00
t = t - tax [ ' amount ' ]
return t
return 0
_name = " account.invoice.line "
2010-05-19 18:32:32 +00:00
_description = " Invoice Line "
2013-09-03 16:01:08 +00:00
_order = " invoice_id,sequence,id "
2008-07-22 15:11:28 +00:00
_columns = {
2012-07-14 20:36:23 +00:00
' name ' : fields . text ( ' Description ' , required = True ) ,
2012-10-08 10:41:51 +00:00
' origin ' : fields . char ( ' Source Document ' , size = 256 , help = " Reference of the document that produced this invoice. " ) ,
2012-10-08 12:17:45 +00:00
' sequence ' : fields . integer ( ' Sequence ' , help = " Gives the sequence of this line when displaying the invoice. " ) ,
2009-12-22 09:38:41 +00:00
' invoice_id ' : fields . many2one ( ' account.invoice ' , ' Invoice Reference ' , ondelete = ' cascade ' , select = True ) ,
2012-11-29 10:12:28 +00:00
' uos_id ' : fields . many2one ( ' product.uom ' , ' Unit of Measure ' , ondelete = ' set null ' , select = True ) ,
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , ondelete = ' set null ' , select = True ) ,
2008-09-22 06:06:56 +00:00
' 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. " ) ,
2012-07-11 13:06:15 +00:00
' price_unit ' : fields . float ( ' Unit Price ' , required = True , digits_compute = dp . get_precision ( ' Product Price ' ) ) ,
2012-12-19 06:56:45 +00:00
' price_subtotal ' : fields . function ( _amount_line , string = ' Amount ' , type = " float " ,
2010-06-05 21:39:55 +00:00
digits_compute = dp . get_precision ( ' Account ' ) , store = True ) ,
2012-07-10 12:25:52 +00:00
' quantity ' : fields . float ( ' Quantity ' , digits_compute = dp . get_precision ( ' Product Unit of Measure ' ) , required = True ) ,
' discount ' : fields . float ( ' Discount ( % ) ' , digits_compute = dp . get_precision ( ' Discount ' ) ) ,
2008-07-22 15:11:28 +00:00
' invoice_line_tax_id ' : fields . many2many ( ' account.tax ' , ' account_invoice_line_tax ' , ' invoice_line_id ' , ' tax_id ' , ' Taxes ' , domain = [ ( ' parent_id ' , ' = ' , False ) ] ) ,
' account_analytic_id ' : fields . many2one ( ' account.analytic.account ' , ' Analytic Account ' ) ,
2011-01-06 11:32:21 +00:00
' company_id ' : fields . related ( ' invoice_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = ' Company ' , store = True , readonly = True ) ,
2010-03-16 15:00:17 +00:00
' partner_id ' : fields . related ( ' invoice_id ' , ' partner_id ' , type = ' many2one ' , relation = ' res.partner ' , string = ' Partner ' , store = True )
2008-07-22 15:11:28 +00:00
}
2012-08-08 07:06:12 +00:00
2012-09-09 12:42:59 +00:00
def _default_account_id ( self , cr , uid , context = None ) :
# XXX this gets the default account for the user's company,
# it should get the default account for the invoice's company
# however, the invoice's company does not reach this point
2012-12-21 09:41:47 +00:00
if context is None :
context = { }
if context . get ( ' type ' ) in ( ' out_invoice ' , ' out_refund ' ) :
prop = self . pool . get ( ' ir.property ' ) . get ( cr , uid , ' property_account_income_categ ' , ' product.category ' , context = context )
else :
prop = self . pool . get ( ' ir.property ' ) . get ( cr , uid , ' property_account_expense_categ ' , ' product.category ' , context = context )
2012-08-08 07:06:12 +00:00
return prop and prop . id or False
2008-07-22 15:11:28 +00:00
_defaults = {
2010-07-02 10:55:58 +00:00
' quantity ' : 1 ,
' discount ' : 0.0 ,
2008-07-22 15:11:28 +00:00
' price_unit ' : _price_unit_default ,
2012-08-17 05:56:39 +00:00
' account_id ' : _default_account_id ,
2013-09-03 16:01:08 +00:00
' sequence ' : 10 ,
2008-07-22 15:11:28 +00:00
}
2011-03-09 05:10:47 +00:00
def fields_view_get ( self , cr , uid , view_id = None , view_type = ' form ' , context = None , toolbar = False , submenu = False ) :
if context is None :
context = { }
res = super ( account_invoice_line , self ) . fields_view_get ( cr , uid , view_id = view_id , view_type = view_type , context = context , toolbar = toolbar , submenu = submenu )
if context . get ( ' type ' , False ) :
doc = etree . XML ( res [ ' arch ' ] )
for node in doc . xpath ( " //field[@name= ' product_id ' ] " ) :
2011-03-09 05:49:13 +00:00
if context [ ' type ' ] in ( ' in_invoice ' , ' in_refund ' ) :
2011-03-09 05:10:47 +00:00
node . set ( ' domain ' , " [( ' purchase_ok ' , ' = ' , True)] " )
else :
node . set ( ' domain ' , " [( ' sale_ok ' , ' = ' , True)] " )
res [ ' arch ' ] = etree . tostring ( doc )
return res
2012-12-05 09:40:45 +00:00
def product_id_change ( self , cr , uid , ids , product , uom_id , qty = 0 , name = ' ' , type = ' out_invoice ' , partner_id = False , fposition_id = False , price_unit = False , currency_id = False , context = None , company_id = None ) :
2009-01-06 13:31:53 +00:00
if context is None :
context = { }
2011-07-04 14:14:10 +00:00
company_id = company_id if company_id != None else context . get ( ' company_id ' , False )
context = dict ( context )
2012-09-09 12:42:59 +00:00
context . update ( { ' company_id ' : company_id , ' force_company ' : company_id } )
2008-09-03 13:47:19 +00:00
if not partner_id :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Partner Defined! ' ) , _ ( " You must first select a partner! " ) )
2008-07-22 15:11:28 +00:00
if not product :
if type in ( ' in_invoice ' , ' in_refund ' ) :
2011-11-14 21:33:19 +00:00
return { ' value ' : { } , ' domain ' : { ' product_uom ' : [ ] } }
2008-07-22 15:11:28 +00:00
else :
2011-11-14 21:33:19 +00:00
return { ' value ' : { ' price_unit ' : 0.0 } , ' domain ' : { ' product_uom ' : [ ] } }
2010-11-19 13:48:01 +00:00
part = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id , context = context )
2010-08-12 21:10:05 +00:00
fpos_obj = self . pool . get ( ' account.fiscal.position ' )
2010-11-19 13:48:01 +00:00
fpos = fposition_id and fpos_obj . browse ( cr , uid , fposition_id , context = context ) or False
2009-01-19 16:49:29 +00:00
2010-05-11 13:04:20 +00:00
if part . lang :
context . update ( { ' lang ' : part . lang } )
2009-01-26 15:28:25 +00:00
result = { }
2008-07-22 15:11:28 +00:00
res = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product , context = context )
2010-08-14 05:05:55 +00:00
2013-01-24 14:20:52 +00:00
result [ ' name ' ] = res . partner_ref
2008-07-22 15:11:28 +00:00
if type in ( ' out_invoice ' , ' out_refund ' ) :
2012-07-27 01:52:02 +00:00
a = res . property_account_income . id
2008-07-22 15:11:28 +00:00
if not a :
a = res . categ_id . property_account_income_categ . id
else :
2012-07-27 01:52:02 +00:00
a = res . property_account_expense . id
2008-07-22 15:11:28 +00:00
if not a :
a = res . categ_id . property_account_expense_categ . id
2010-08-12 21:10:05 +00:00
a = fpos_obj . map_account ( cr , uid , fpos , a )
2008-07-22 15:11:28 +00:00
if a :
result [ ' account_id ' ] = a
2009-01-26 15:28:25 +00:00
if type in ( ' out_invoice ' , ' out_refund ' ) :
2010-12-20 10:40:35 +00:00
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 )
2013-01-18 11:33:09 +00:00
if res . description_sale :
result [ ' name ' ] + = ' \n ' + res . description_sale
2009-01-26 15:28:25 +00:00
else :
2010-12-20 10:40:35 +00:00
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 )
2013-01-18 11:33:09 +00:00
if res . description_purchase :
result [ ' name ' ] + = ' \n ' + res . description_purchase
2010-12-20 10:40:35 +00:00
tax_id = fpos_obj . map_tax ( cr , uid , fpos , taxes )
2010-12-10 12:13:27 +00:00
2009-01-26 15:28:25 +00:00
if type in ( ' in_invoice ' , ' in_refund ' ) :
2010-10-17 20:31:19 +00:00
result . update ( { ' price_unit ' : price_unit or res . standard_price , ' invoice_line_tax_id ' : tax_id } )
2009-01-26 15:28:25 +00:00
else :
result . update ( { ' price_unit ' : res . list_price , ' invoice_line_tax_id ' : tax_id } )
2012-12-05 09:40:45 +00:00
result [ ' uos_id ' ] = uom_id or res . uom_id . id
domain = { ' uos_id ' : [ ( ' category_id ' , ' = ' , res . uom_id . category_id . id ) ] }
2009-12-24 08:43:23 +00:00
2009-12-04 10:29:03 +00:00
res_final = { ' value ' : result , ' domain ' : domain }
2009-12-24 08:43:23 +00:00
2010-08-12 21:10:05 +00:00
if not company_id or not currency_id :
2009-12-04 10:29:03 +00:00
return res_final
2009-12-24 08:43:23 +00:00
2010-11-19 13:48:01 +00:00
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 )
2010-02-09 08:31:46 +00:00
2009-12-29 06:00:26 +00:00
if company . currency_id . id != currency . id :
2011-03-07 06:12:02 +00:00
if type in ( ' in_invoice ' , ' in_refund ' ) :
res_final [ ' value ' ] [ ' price_unit ' ] = res . standard_price
2009-12-04 10:29:03 +00:00
new_price = res_final [ ' value ' ] [ ' price_unit ' ] * currency . rate
res_final [ ' value ' ] [ ' price_unit ' ] = new_price
2010-06-08 11:44:24 +00:00
2013-01-05 23:29:19 +00:00
if result [ ' uos_id ' ] and result [ ' uos_id ' ] != res . uom_id . id :
selected_uom = self . pool . get ( ' product.uom ' ) . browse ( cr , uid , result [ ' uos_id ' ] , context = context )
new_price = self . pool . get ( ' product.uom ' ) . _compute_price ( cr , uid , res . uom_id . id , res_final [ ' value ' ] [ ' price_unit ' ] , result [ ' uos_id ' ] )
res_final [ ' value ' ] [ ' price_unit ' ] = new_price
2009-12-04 10:29:03 +00:00
return res_final
2008-07-22 15:11:28 +00:00
2012-03-07 10:42:05 +00:00
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 , currency_id = False , context = None , company_id = None ) :
2011-07-04 14:16:07 +00:00
if context is None :
context = { }
company_id = company_id if company_id != None else context . get ( ' company_id ' , False )
context = dict ( context )
context . update ( { ' company_id ' : company_id } )
2010-12-17 08:39:47 +00:00
warning = { }
2012-03-05 06:48:45 +00:00
res = self . product_id_change ( cr , uid , ids , product , uom , qty , name , type , partner_id , fposition_id , price_unit , currency_id , context = context )
2010-06-08 09:14:47 +00:00
if not uom :
res [ ' value ' ] [ ' price_unit ' ] = 0.0
2010-12-17 10:36:58 +00:00
if product and uom :
2010-12-17 10:18:21 +00:00
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 :
2012-08-17 05:51:34 +00:00
warning = {
2010-12-17 10:18:21 +00:00
' title ' : _ ( ' Warning! ' ) ,
2012-08-06 15:44:10 +00:00
' message ' : _ ( ' The selected unit of measure is not compatible with the unit of measure of the product. ' )
2012-08-17 05:51:34 +00:00
}
res [ ' value ' ] . update ( { ' uos_id ' : prod . uom_id . id } )
2010-12-17 10:36:58 +00:00
return { ' value ' : res [ ' value ' ] , ' warning ' : warning }
2010-06-08 09:14:47 +00:00
return res
2010-06-08 11:44:24 +00:00
2009-01-06 13:31:53 +00:00
def move_line_get ( self , cr , uid , invoice_id , context = None ) :
2008-07-22 15:11:28 +00:00
res = [ ]
tax_obj = self . pool . get ( ' account.tax ' )
cur_obj = self . pool . get ( ' res.currency ' )
2010-11-19 13:48:01 +00:00
if context is None :
context = { }
inv = self . pool . get ( ' account.invoice ' ) . browse ( cr , uid , invoice_id , context = context )
2013-05-17 08:00:31 +00:00
company_currency = self . pool [ ' res.company ' ] . browse ( cr , uid , inv . company_id . id ) . currency_id . id
2008-07-22 15:11:28 +00:00
for line in inv . invoice_line :
mres = self . move_line_get_item ( cr , uid , line , context )
if not mres :
continue
res . append ( mres )
tax_code_found = False
2010-06-05 21:39:55 +00:00
for tax in tax_obj . compute_all ( cr , uid , line . invoice_line_tax_id ,
2008-07-22 15:11:28 +00:00
( line . price_unit * ( 1.0 - ( line [ ' discount ' ] or 0.0 ) / 100.0 ) ) ,
2012-03-05 10:16:05 +00:00
line . quantity , line . product_id ,
2010-06-05 21:39:55 +00:00
inv . partner_id ) [ ' taxes ' ] :
2008-07-22 15:11:28 +00:00
if inv . type in ( ' out_invoice ' , ' in_invoice ' ) :
tax_code_id = tax [ ' base_code_id ' ]
tax_amount = line . price_subtotal * tax [ ' base_sign ' ]
else :
tax_code_id = tax [ ' ref_base_code_id ' ]
tax_amount = line . price_subtotal * tax [ ' ref_base_sign ' ]
if tax_code_found :
if not tax_code_id :
continue
res . append ( self . move_line_get_item ( cr , uid , line , context ) )
res [ - 1 ] [ ' price ' ] = 0.0
res [ - 1 ] [ ' account_analytic_id ' ] = False
elif not tax_code_id :
continue
tax_code_found = True
res [ - 1 ] [ ' tax_code_id ' ] = tax_code_id
res [ - 1 ] [ ' tax_amount ' ] = cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , tax_amount , context = { ' date ' : inv . date_invoice } )
return res
2009-01-06 13:31:53 +00:00
def move_line_get_item ( self , cr , uid , line , context = None ) :
2008-07-22 15:11:28 +00:00
return {
' type ' : ' src ' ,
2012-07-14 20:36:23 +00:00
' name ' : line . name . split ( ' \n ' ) [ 0 ] [ : 64 ] ,
2008-07-22 15:11:28 +00:00
' price_unit ' : line . price_unit ,
' quantity ' : line . quantity ,
' price ' : line . price_subtotal ,
' account_id ' : line . account_id . id ,
' product_id ' : line . product_id . id ,
' uos_id ' : line . uos_id . id ,
' account_analytic_id ' : line . account_analytic_id . id ,
2008-11-06 07:29:50 +00:00
' taxes ' : line . invoice_line_tax_id ,
2008-07-22 15:11:28 +00:00
}
#
2009-01-26 15:28:25 +00:00
# Set the tax field according to the account and the fiscal position
2008-07-22 15:11:28 +00:00
#
2012-02-16 18:50:48 +00:00
def onchange_account_id ( self , cr , uid , ids , product_id , partner_id , inv_type , fposition_id , account_id ) :
2009-01-26 15:28:25 +00:00
if not account_id :
2008-07-22 15:11:28 +00:00
return { }
2012-09-30 10:50:06 +00:00
unique_tax_ids = [ ]
2009-01-19 16:49:29 +00:00
fpos = fposition_id and self . pool . get ( ' account.fiscal.position ' ) . browse ( cr , uid , fposition_id ) or False
2012-09-30 11:45:25 +00:00
account = self . pool . get ( ' account.account ' ) . browse ( cr , uid , account_id )
2012-09-30 10:50:06 +00:00
if not product_id :
taxes = account . tax_ids
unique_tax_ids = self . pool . get ( ' account.fiscal.position ' ) . map_tax ( cr , uid , fpos , taxes )
else :
product_change_result = self . product_id_change ( cr , uid , ids , product_id , False , type = inv_type ,
partner_id = partner_id , fposition_id = fposition_id ,
company_id = account . company_id . id )
if product_change_result and ' value ' in product_change_result and ' invoice_line_tax_id ' in product_change_result [ ' value ' ] :
unique_tax_ids = product_change_result [ ' value ' ] [ ' invoice_line_tax_id ' ]
return { ' value ' : { ' invoice_line_tax_id ' : unique_tax_ids } }
2010-10-20 07:00:04 +00:00
2006-12-07 13:41:40 +00:00
class account_invoice_tax ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " account.invoice.tax "
_description = " Invoice Tax "
2010-09-16 13:51:02 +00:00
2010-09-09 13:07:06 +00:00
def _count_factor ( self , cr , uid , ids , name , args , context = None ) :
res = { }
for invoice_tax in self . browse ( cr , uid , ids , context = context ) :
res [ invoice_tax . id ] = {
' factor_base ' : 1.0 ,
' factor_tax ' : 1.0 ,
}
if invoice_tax . amount < > 0.0 :
factor_tax = invoice_tax . tax_amount / invoice_tax . amount
res [ invoice_tax . id ] [ ' factor_tax ' ] = factor_tax
2010-09-16 13:51:02 +00:00
2010-09-09 13:07:06 +00:00
if invoice_tax . base < > 0.0 :
factor_base = invoice_tax . base_amount / invoice_tax . base
res [ invoice_tax . id ] [ ' factor_base ' ] = factor_base
2010-09-16 13:51:02 +00:00
2010-09-09 13:07:06 +00:00
return res
2010-09-16 13:51:02 +00:00
2008-07-22 15:11:28 +00:00
_columns = {
' invoice_id ' : fields . many2one ( ' account.invoice ' , ' Invoice Line ' , ondelete = ' cascade ' , select = True ) ,
2009-01-28 13:46:13 +00:00
' name ' : fields . char ( ' Tax Description ' , size = 64 , required = True ) ,
2008-07-22 15:11:28 +00:00
' account_id ' : fields . many2one ( ' account.account ' , ' Tax Account ' , required = True , domain = [ ( ' type ' , ' <> ' , ' view ' ) , ( ' type ' , ' <> ' , ' income ' ) , ( ' type ' , ' <> ' , ' closed ' ) ] ) ,
2012-07-10 21:21:15 +00:00
' account_analytic_id ' : fields . many2one ( ' account.analytic.account ' , ' Analytic account ' ) ,
2010-03-06 20:52:19 +00:00
' base ' : fields . float ( ' Base ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
' amount ' : fields . float ( ' Amount ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2008-07-22 15:11:28 +00:00
' manual ' : fields . boolean ( ' Manual ' ) ,
2009-12-21 13:14:12 +00:00
' sequence ' : fields . integer ( ' Sequence ' , help = " Gives the sequence order when displaying a list of invoice tax. " ) ,
2009-01-27 11:15:46 +00:00
' base_code_id ' : fields . many2one ( ' account.tax.code ' , ' Base Code ' , help = " The account basis of the tax declaration. " ) ,
2010-03-06 20:52:19 +00:00
' base_amount ' : fields . float ( ' Base Code Amount ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2009-01-27 11:15:46 +00:00
' tax_code_id ' : fields . many2one ( ' account.tax.code ' , ' Tax Code ' , help = " The tax basis of the tax declaration. " ) ,
2010-03-06 20:52:19 +00:00
' tax_amount ' : fields . float ( ' Tax Code Amount ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2011-01-06 11:32:21 +00:00
' company_id ' : fields . related ( ' account_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = ' Company ' , store = True , readonly = True ) ,
2011-07-01 23:41:24 +00:00
' factor_base ' : fields . function ( _count_factor , string = ' Multipication factor for Base code ' , type = ' float ' , multi = " all " ) ,
' factor_tax ' : fields . function ( _count_factor , string = ' Multipication factor Tax code ' , type = ' float ' , multi = " all " )
2008-07-22 15:11:28 +00:00
}
2009-11-13 05:41:16 +00:00
2010-06-16 11:51:39 +00:00
def base_change ( self , cr , uid , ids , base , currency_id = False , company_id = False , date_invoice = False ) :
2009-03-19 09:47:23 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
company_obj = self . pool . get ( ' res.company ' )
2010-08-30 06:28:31 +00:00
company_currency = False
2010-09-09 13:07:06 +00:00
factor = 1
if ids :
factor = self . read ( cr , uid , ids [ 0 ] , [ ' factor_base ' ] ) [ ' factor_base ' ]
2009-11-13 05:41:16 +00:00
if company_id :
2010-06-16 11:51:39 +00:00
company_currency = company_obj . read ( cr , uid , [ company_id ] , [ ' currency_id ' ] ) [ 0 ] [ ' currency_id ' ] [ 0 ]
2009-03-19 09:47:23 +00:00
if currency_id and company_currency :
2010-09-09 13:07:06 +00:00
base = cur_obj . compute ( cr , uid , currency_id , company_currency , base * factor , context = { ' date ' : date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
2008-07-22 15:11:28 +00:00
return { ' value ' : { ' base_amount ' : base } }
2009-10-24 10:54:02 +00:00
2010-06-16 11:51:39 +00:00
def amount_change ( self , cr , uid , ids , amount , currency_id = False , company_id = False , date_invoice = False ) :
2009-03-19 09:47:23 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
company_obj = self . pool . get ( ' res.company ' )
2010-08-26 04:20:06 +00:00
company_currency = False
2010-09-09 13:07:06 +00:00
factor = 1
2010-08-30 10:27:03 +00:00
if ids :
2010-09-09 13:07:06 +00:00
factor = self . read ( cr , uid , ids [ 0 ] , [ ' factor_tax ' ] ) [ ' factor_tax ' ]
2009-03-19 09:47:23 +00:00
if company_id :
2010-06-16 11:51:39 +00:00
company_currency = company_obj . read ( cr , uid , [ company_id ] , [ ' currency_id ' ] ) [ 0 ] [ ' currency_id ' ] [ 0 ]
2009-03-19 09:47:23 +00:00
if currency_id and company_currency :
2010-09-09 13:07:06 +00:00
amount = cur_obj . compute ( cr , uid , currency_id , company_currency , amount * factor , context = { ' date ' : date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
2010-08-26 04:20:06 +00:00
return { ' value ' : { ' tax_amount ' : amount } }
2009-11-13 05:41:16 +00:00
2008-07-22 15:11:28 +00:00
_order = ' sequence '
_defaults = {
2010-10-20 07:00:04 +00:00
' manual ' : 1 ,
' base_amount ' : 0.0 ,
' tax_amount ' : 0.0 ,
2008-07-22 15:11:28 +00:00
}
2010-11-19 13:48:01 +00:00
def compute ( self , cr , uid , invoice_id , context = None ) :
2008-07-22 15:11:28 +00:00
tax_grouped = { }
tax_obj = self . pool . get ( ' account.tax ' )
cur_obj = self . pool . get ( ' res.currency ' )
2010-11-19 13:48:01 +00:00
inv = self . pool . get ( ' account.invoice ' ) . browse ( cr , uid , invoice_id , context = context )
2008-07-22 15:11:28 +00:00
cur = inv . currency_id
2013-05-17 08:00:31 +00:00
company_currency = self . pool [ ' res.company ' ] . browse ( cr , uid , inv . company_id . id ) . currency_id . id
2008-07-22 15:11:28 +00:00
for line in inv . invoice_line :
2012-03-05 10:16:05 +00:00
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 , line . product_id , inv . partner_id ) [ ' taxes ' ] :
2008-07-22 15:11:28 +00:00
val = { }
val [ ' invoice_id ' ] = inv . id
val [ ' name ' ] = tax [ ' name ' ]
2008-11-20 19:46:20 +00:00
val [ ' amount ' ] = tax [ ' amount ' ]
2008-07-22 15:11:28 +00:00
val [ ' manual ' ] = False
val [ ' sequence ' ] = tax [ ' sequence ' ]
2012-09-29 13:08:22 +00:00
val [ ' base ' ] = cur_obj . round ( cr , uid , cur , tax [ ' price_unit ' ] * line [ ' quantity ' ] )
2008-07-22 15:11:28 +00:00
if inv . type in ( ' out_invoice ' , ' in_invoice ' ) :
val [ ' base_code_id ' ] = tax [ ' base_code_id ' ]
val [ ' tax_code_id ' ] = tax [ ' tax_code_id ' ]
2009-02-19 17:32:34 +00:00
val [ ' base_amount ' ] = cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , val [ ' base ' ] * tax [ ' base_sign ' ] , context = { ' date ' : inv . date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
val [ ' tax_amount ' ] = cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , val [ ' amount ' ] * tax [ ' tax_sign ' ] , context = { ' date ' : inv . date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
2008-07-22 15:11:28 +00:00
val [ ' account_id ' ] = tax [ ' account_collected_id ' ] or line . account_id . id
2012-07-10 21:21:15 +00:00
val [ ' account_analytic_id ' ] = tax [ ' account_analytic_collected_id ' ]
2008-07-22 15:11:28 +00:00
else :
val [ ' base_code_id ' ] = tax [ ' ref_base_code_id ' ]
val [ ' tax_code_id ' ] = tax [ ' ref_tax_code_id ' ]
2009-02-19 17:32:34 +00:00
val [ ' base_amount ' ] = cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , val [ ' base ' ] * tax [ ' ref_base_sign ' ] , context = { ' date ' : inv . date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
val [ ' tax_amount ' ] = cur_obj . compute ( cr , uid , inv . currency_id . id , company_currency , val [ ' amount ' ] * tax [ ' ref_tax_sign ' ] , context = { ' date ' : inv . date_invoice or time . strftime ( ' % Y- % m- %d ' ) } , round = False )
2008-07-22 15:11:28 +00:00
val [ ' account_id ' ] = tax [ ' account_paid_id ' ] or line . account_id . id
2012-07-10 21:21:15 +00:00
val [ ' account_analytic_id ' ] = tax [ ' account_analytic_paid_id ' ]
2008-07-22 15:11:28 +00:00
2012-07-10 21:21:15 +00:00
key = ( val [ ' tax_code_id ' ] , val [ ' base_code_id ' ] , val [ ' account_id ' ] , val [ ' account_analytic_id ' ] )
2008-07-22 15:11:28 +00:00
if not key in tax_grouped :
tax_grouped [ key ] = val
else :
tax_grouped [ key ] [ ' amount ' ] + = val [ ' amount ' ]
tax_grouped [ key ] [ ' base ' ] + = val [ ' base ' ]
tax_grouped [ key ] [ ' base_amount ' ] + = val [ ' base_amount ' ]
tax_grouped [ key ] [ ' tax_amount ' ] + = val [ ' tax_amount ' ]
2008-11-20 19:46:20 +00:00
for t in tax_grouped . values ( ) :
2010-10-07 09:03:42 +00:00
t [ ' base ' ] = cur_obj . round ( cr , uid , cur , t [ ' base ' ] )
2008-11-20 19:46:20 +00:00
t [ ' amount ' ] = cur_obj . round ( cr , uid , cur , t [ ' amount ' ] )
2009-02-19 17:32:34 +00:00
t [ ' base_amount ' ] = cur_obj . round ( cr , uid , cur , t [ ' base_amount ' ] )
t [ ' tax_amount ' ] = cur_obj . round ( cr , uid , cur , t [ ' tax_amount ' ] )
2008-07-22 15:11:28 +00:00
return tax_grouped
def move_line_get ( self , cr , uid , invoice_id ) :
res = [ ]
2008-12-10 14:29:55 +00:00
cr . execute ( ' SELECT * FROM account_invoice_tax WHERE invoice_id= %s ' , ( invoice_id , ) )
2008-07-22 15:11:28 +00:00
for t in cr . dictfetchall ( ) :
if not t [ ' amount ' ] \
and not t [ ' tax_code_id ' ] \
and not t [ ' tax_amount ' ] :
continue
res . append ( {
' type ' : ' tax ' ,
' name ' : t [ ' name ' ] ,
' price_unit ' : t [ ' amount ' ] ,
' quantity ' : 1 ,
' price ' : t [ ' amount ' ] or 0.0 ,
' account_id ' : t [ ' account_id ' ] ,
' tax_code_id ' : t [ ' tax_code_id ' ] ,
2012-07-10 21:21:15 +00:00
' tax_amount ' : t [ ' tax_amount ' ] ,
2012-07-12 21:09:24 +00:00
' account_analytic_id ' : t [ ' account_analytic_id ' ] ,
2008-07-22 15:11:28 +00:00
} )
return res
2010-12-27 07:37:46 +00:00
2010-05-14 04:48:36 +00:00
class res_partner ( osv . osv ) :
""" Inherits partner and adds invoice information in the partner form """
_inherit = ' res.partner '
_columns = {
2010-06-05 21:39:55 +00:00
' invoice_ids ' : fields . one2many ( ' account.invoice.line ' , ' partner_id ' , ' Invoices ' , readonly = True ) ,
}
2011-04-29 05:01:18 +00:00
2013-04-07 21:23:33 +00:00
def _find_accounting_partner ( self , partner ) :
2013-03-05 16:20:15 +00:00
'''
Find the partner for which the accounting entries will be created
'''
2013-04-22 15:34:49 +00:00
return partner . commercial_partner_id
2013-03-05 16:20:15 +00:00
2011-03-29 11:01:35 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2011-12-14 09:35:31 +00:00
default = default or { }
2011-03-29 10:40:36 +00:00
default . update ( { ' invoice_ids ' : [ ] } )
2011-03-29 10:11:09 +00:00
return super ( res_partner , self ) . copy ( cr , uid , id , default , context )
2011-04-29 05:01:18 +00:00
2010-07-02 10:55:58 +00:00
2012-12-21 09:59:02 +00:00
class mail_compose_message ( osv . Model ) :
2012-11-21 10:21:37 +00:00
_inherit = ' mail.compose.message '
2012-03-27 11:44:44 +00:00
2012-11-21 10:21:37 +00:00
def send_mail ( self , cr , uid , ids , context = None ) :
context = context or { }
if context . get ( ' default_model ' ) == ' account.invoice ' and context . get ( ' default_res_id ' ) and context . get ( ' mark_invoice_as_sent ' ) :
2012-12-21 09:59:02 +00:00
context = dict ( context , mail_post_autofollow = True )
2012-11-21 10:21:37 +00:00
self . pool . get ( ' account.invoice ' ) . write ( cr , uid , [ context [ ' default_res_id ' ] ] , { ' sent ' : True } , context = context )
2013-03-05 10:48:01 +00:00
self . pool . get ( ' account.invoice ' ) . message_post ( cr , uid , [ context [ ' default_res_id ' ] ] , body = _ ( " Invoice sent " ) , context = context )
2012-11-21 10:21:37 +00:00
return super ( mail_compose_message , self ) . send_mail ( cr , uid , ids , context = context )
2012-03-27 11:44:44 +00:00
2010-07-08 14:25:59 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: