2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-13 05:41:16 +00:00
#
2008-12-01 13:00:56 +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
#
##############################################################################
2010-08-10 05:46:09 +00:00
from datetime import datetime , timedelta
2010-06-22 06:38:37 +00:00
from dateutil . relativedelta import relativedelta
2010-09-29 11:33:49 +00:00
import time
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
from openerp . tools . translate import _
from openerp . tools import DEFAULT_SERVER_DATE_FORMAT , DEFAULT_SERVER_DATETIME_FORMAT , DATETIME_FORMATS_MAP , float_compare
2012-12-17 15:23:03 +00:00
import openerp . addons . decimal_precision as dp
2013-11-21 12:06:11 +00:00
from openerp import workflow
2010-03-06 20:52:19 +00:00
2006-12-07 13:41:40 +00:00
class sale_order ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " sale.order "
2012-09-09 10:11:56 +00:00
_inherit = [ ' mail.thread ' , ' ir.needaction_mixin ' ]
2010-12-13 06:07:23 +00:00
_description = " Sales Order "
2012-12-18 18:17:18 +00:00
_track = {
' state ' : {
2013-06-27 14:46:47 +00:00
' sale.mt_order_confirmed ' : lambda self , cr , uid , obj , ctx = None : obj . state in [ ' manual ' ] ,
' sale.mt_order_sent ' : lambda self , cr , uid , obj , ctx = None : obj . state in [ ' sent ' ]
2012-12-18 18:17:18 +00:00
} ,
}
2009-08-26 13:41:53 +00:00
2010-04-13 10:35:39 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2008-07-22 15:11:28 +00:00
if not default :
default = { }
default . update ( {
2013-06-26 05:36:42 +00:00
' date_order ' : fields . date . context_today ( self , cr , uid , context = context ) ,
2009-08-26 13:41:53 +00:00
' state ' : ' draft ' ,
' invoice_ids ' : [ ] ,
2010-10-21 09:30:04 +00:00
' date_confirm ' : False ,
2013-11-27 08:46:25 +00:00
' client_order_ref ' : ' ' ,
2008-07-22 15:11:28 +00:00
' name ' : self . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' sale.order ' ) ,
} )
2010-04-13 10:35:39 +00:00
return super ( sale_order , self ) . copy ( cr , uid , id , default , context = context )
2008-07-22 15:11:28 +00:00
2010-04-13 10:35:39 +00:00
def _amount_line_tax ( self , cr , uid , line , context = None ) :
2008-12-07 12:45:27 +00:00
val = 0.0
2012-03-29 12:41:38 +00:00
for c in self . pool . get ( ' account.tax ' ) . compute_all ( cr , uid , line . tax_id , line . price_unit * ( 1 - ( line . discount or 0.0 ) / 100.0 ) , line . product_uom_qty , line . product_id , line . order_id . partner_id ) [ ' taxes ' ] :
2010-10-08 06:13:09 +00:00
val + = c . get ( ' amount ' , 0.0 )
2008-12-07 12:45:27 +00:00
return val
2008-07-22 15:11:28 +00:00
2013-12-18 13:19:42 +00:00
def _amount_all_wrapper ( self , cr , uid , ids , field_name , arg , context = None ) :
""" Wrapper because of direct method passing as parameter for function fields """
return self . _amount_all ( cr , uid , ids , field_name , arg , context = context )
2010-04-13 10:35:39 +00:00
def _amount_all ( self , cr , uid , ids , field_name , arg , context = None ) :
2010-06-22 07:15:50 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2008-07-22 15:11:28 +00:00
res = { }
2010-06-22 07:15:50 +00:00
for order in self . browse ( cr , uid , ids , context = context ) :
2008-12-07 12:45:27 +00:00
res [ order . id ] = {
' amount_untaxed ' : 0.0 ,
' amount_tax ' : 0.0 ,
' amount_total ' : 0.0 ,
}
val = val1 = 0.0
2009-08-26 13:41:53 +00:00
cur = order . pricelist_id . currency_id
2008-07-22 15:11:28 +00:00
for line in order . order_line :
2008-12-07 12:45:27 +00:00
val1 + = line . price_subtotal
2010-04-13 10:35:39 +00:00
val + = self . _amount_line_tax ( cr , uid , line , context = context )
2009-08-26 13:41:53 +00:00
res [ order . id ] [ ' amount_tax ' ] = cur_obj . round ( cr , uid , cur , val )
res [ order . id ] [ ' amount_untaxed ' ] = cur_obj . round ( cr , uid , cur , val1 )
res [ order . id ] [ ' amount_total ' ] = res [ order . id ] [ ' amount_untaxed ' ] + res [ order . id ] [ ' amount_tax ' ]
2008-07-22 15:11:28 +00:00
return res
2008-08-24 23:23:45 +00:00
def _invoiced_rate ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for sale in self . browse ( cursor , user , ids , context = context ) :
2008-09-08 22:53:40 +00:00
if sale . invoiced :
res [ sale . id ] = 100.0
continue
2008-08-24 23:23:45 +00:00
tot = 0.0
for invoice in sale . invoice_ids :
2009-08-26 13:41:53 +00:00
if invoice . state not in ( ' draft ' , ' cancel ' ) :
2008-08-24 23:23:45 +00:00
tot + = invoice . amount_untaxed
if tot :
2009-05-27 07:22:12 +00:00
res [ sale . id ] = min ( 100.0 , tot * 100.0 / ( sale . amount_untaxed or 1.00 ) )
2008-08-24 23:23:45 +00:00
else :
res [ sale . id ] = 0.0
return res
2012-09-11 11:21:33 +00:00
def _invoice_exists ( self , cursor , user , ids , name , arg , context = None ) :
2012-09-07 11:28:34 +00:00
res = { }
for sale in self . browse ( cursor , user , ids , context = context ) :
2012-09-11 11:21:33 +00:00
res [ sale . id ] = False
if sale . invoice_ids :
res [ sale . id ] = True
2012-09-07 11:28:34 +00:00
return res
2008-07-22 15:11:28 +00:00
def _invoiced ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for sale in self . browse ( cursor , user , ids , context = context ) :
res [ sale . id ] = True
2012-02-16 16:52:53 +00:00
invoice_existence = False
2008-07-22 15:11:28 +00:00
for invoice in sale . invoice_ids :
2012-02-14 12:56:53 +00:00
if invoice . state != ' cancel ' :
2012-02-16 16:52:53 +00:00
invoice_existence = True
if invoice . state != ' paid ' :
res [ sale . id ] = False
break
2012-09-11 11:21:33 +00:00
if not invoice_existence or sale . state == ' manual ' :
2008-07-22 15:11:28 +00:00
res [ sale . id ] = False
return res
2010-04-13 10:35:39 +00:00
def _invoiced_search ( self , cursor , user , obj , name , args , context = None ) :
2008-07-22 15:11:28 +00:00
if not len ( args ) :
return [ ]
clause = ' '
2010-11-03 12:30:07 +00:00
sale_clause = ' '
2008-07-22 15:11:28 +00:00
no_invoiced = False
for arg in args :
if arg [ 1 ] == ' = ' :
if arg [ 2 ] :
clause + = ' AND inv.state = \' paid \' '
else :
2010-11-03 12:30:07 +00:00
clause + = ' AND inv.state != \' cancel \' AND sale.state != \' cancel \' AND inv.state <> \' paid \' AND rel.order_id = sale.id '
sale_clause = ' , sale_order AS sale '
2008-07-22 15:11:28 +00:00
no_invoiced = True
2010-11-03 11:33:16 +00:00
2008-07-22 15:11:28 +00:00
cursor . execute ( ' SELECT rel.order_id ' \
2010-11-03 12:30:07 +00:00
' FROM sale_order_invoice_rel AS rel, account_invoice AS inv ' + sale_clause + \
2008-07-22 15:11:28 +00:00
' WHERE rel.invoice_id = inv.id ' + clause )
res = cursor . fetchall ( )
if no_invoiced :
cursor . execute ( ' SELECT sale.id ' \
' FROM sale_order AS sale ' \
' WHERE sale.id NOT IN ' \
' (SELECT rel.order_id ' \
2010-11-03 12:30:07 +00:00
' FROM sale_order_invoice_rel AS rel) and sale.state != \' cancel \' ' )
2008-07-22 15:11:28 +00:00
res . extend ( cursor . fetchall ( ) )
if not res :
return [ ( ' id ' , ' = ' , 0 ) ]
return [ ( ' id ' , ' in ' , [ x [ 0 ] for x in res ] ) ]
2010-04-13 10:35:39 +00:00
def _get_order ( self , cr , uid , ids , context = None ) :
2008-12-13 06:05:19 +00:00
result = { }
for line in self . pool . get ( ' sale.order.line ' ) . browse ( cr , uid , ids , context = context ) :
result [ line . order_id . id ] = True
return result . keys ( )
2013-06-14 14:16:43 +00:00
2013-01-22 11:08:57 +00:00
def _get_default_company ( self , cr , uid , context = None ) :
2013-06-14 14:33:17 +00:00
company_id = self . pool . get ( ' res.users ' ) . _get_company ( cr , uid , context = context )
2013-01-22 11:08:57 +00:00
if not company_id :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' There is no default company for the current user! ' ) )
return company_id
2011-01-17 11:20:56 +00:00
2008-07-22 15:11:28 +00:00
_columns = {
2011-10-04 10:14:10 +00:00
' name ' : fields . char ( ' Order Reference ' , size = 64 , required = True ,
2012-05-23 12:55:34 +00:00
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , select = True ) ,
2010-12-13 06:07:23 +00:00
' origin ' : fields . char ( ' Source Document ' , size = 64 , help = " Reference of the document that generated this sales order request. " ) ,
2014-03-11 09:49:11 +00:00
' client_order_ref ' : fields . char ( ' Reference/Description ' , size = 64 ) ,
2008-07-22 15:11:28 +00:00
' state ' : fields . selection ( [
2012-02-29 09:46:32 +00:00
( ' draft ' , ' Draft Quotation ' ) ,
( ' sent ' , ' Quotation Sent ' ) ,
2012-05-01 12:34:46 +00:00
( ' cancel ' , ' Cancelled ' ) ,
2009-08-26 13:41:53 +00:00
( ' waiting_date ' , ' Waiting Schedule ' ) ,
2012-12-20 11:43:56 +00:00
( ' progress ' , ' Sales Order ' ) ,
2012-09-20 17:22:49 +00:00
( ' manual ' , ' Sale to Invoice ' ) ,
2009-08-26 13:41:53 +00:00
( ' invoice_except ' , ' Invoice Exception ' ) ,
( ' done ' , ' Done ' ) ,
2012-12-20 11:47:30 +00:00
] , ' Status ' , readonly = True , track_visibility = ' onchange ' ,
2012-12-21 16:48:08 +00:00
help = " Gives the status of the quotation or sales order. \n The exception status is automatically set when a cancel operation occurs in the processing of a document linked to the sales order. \n The ' Waiting Schedule ' status is set when the invoice is confirmed but waiting for the scheduler to run on the order date. " , select = True ) ,
2012-05-23 12:55:34 +00:00
' date_order ' : fields . date ( ' Date ' , required = True , readonly = True , select = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } ) ,
2011-07-07 09:25:31 +00:00
' create_date ' : fields . datetime ( ' Creation Date ' , readonly = True , select = True , help = " Date on which sales order is created. " ) ,
2011-01-17 11:20:56 +00:00
' date_confirm ' : fields . date ( ' Confirmation Date ' , readonly = True , select = True , help = " Date on which sales order is confirmed. " ) ,
2012-12-20 11:47:30 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Salesperson ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , select = True , track_visibility = ' onchange ' ) ,
' partner_id ' : fields . many2one ( ' res.partner ' , ' Customer ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , required = True , change_default = True , select = True , track_visibility = ' always ' ) ,
2012-05-23 12:55:34 +00:00
' partner_invoice_id ' : fields . many2one ( ' res.partner ' , ' Invoice Address ' , readonly = True , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , help = " Invoice address for current sales order. " ) ,
2012-10-03 09:29:39 +00:00
' partner_shipping_id ' : fields . many2one ( ' res.partner ' , ' Delivery Address ' , readonly = True , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , help = " Delivery address for current sales order. " ) ,
2008-07-22 15:11:28 +00:00
' order_policy ' : fields . selection ( [
2012-09-09 10:11:56 +00:00
( ' manual ' , ' On Demand ' ) ,
2012-05-23 12:55:34 +00:00
] , ' Create Invoice ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } ,
2013-04-04 15:14:51 +00:00
help = """ This field controls how invoice and delivery operations are synchronized. """ ) ,
2012-05-23 12:55:34 +00:00
' pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' Pricelist ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , help = " Pricelist for current sales order. " ) ,
2012-12-05 08:37:31 +00:00
' currency_id ' : fields . related ( ' pricelist_id ' , ' currency_id ' , type = " many2one " , relation = " res.currency " , string = " Currency " , readonly = True , required = True ) ,
2012-10-26 15:34:36 +00:00
' project_id ' : fields . many2one ( ' account.analytic.account ' , ' Contract / Analytic ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } , help = " The analytic account related to a sales order. " ) ,
2008-07-22 15:11:28 +00:00
2012-05-23 12:55:34 +00:00
' order_line ' : fields . one2many ( ' sale.order.line ' , ' order_id ' , ' Order Lines ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' sent ' : [ ( ' readonly ' , False ) ] } ) ,
2010-12-13 06:07:23 +00:00
' invoice_ids ' : fields . many2many ( ' account.invoice ' , ' sale_order_invoice_rel ' , ' order_id ' , ' invoice_id ' , ' Invoices ' , readonly = True , help = " This is the list of invoices that have been generated for this sales order. The same sales order may have been invoiced in several times (by line for example). " ) ,
2012-12-06 06:52:14 +00:00
' invoiced_rate ' : fields . function ( _invoiced_rate , string = ' Invoiced Ratio ' , type = ' float ' ) ,
2011-07-01 23:41:24 +00:00
' invoiced ' : fields . function ( _invoiced , string = ' Paid ' ,
2010-12-13 06:07:23 +00:00
fnct_search = _invoiced_search , type = ' boolean ' , help = " It indicates that an invoice has been paid. " ) ,
2012-09-11 11:21:33 +00:00
' invoice_exists ' : fields . function ( _invoice_exists , string = ' Invoiced ' ,
2012-12-21 16:48:08 +00:00
fnct_search = _invoiced_search , type = ' boolean ' , help = " It indicates that sales order has at least one invoice. " ) ,
2012-06-28 12:51:23 +00:00
' note ' : fields . text ( ' Terms and conditions ' ) ,
2008-12-07 12:45:27 +00:00
2013-12-18 13:19:42 +00:00
' amount_untaxed ' : fields . function ( _amount_all_wrapper , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Untaxed Amount ' ,
2012-12-18 18:17:18 +00:00
store = {
2009-08-20 15:32:05 +00:00
' sale.order ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' order_line ' ] , 10 ) ,
2009-08-26 13:41:53 +00:00
' sale.order.line ' : ( _get_order , [ ' price_unit ' , ' tax_id ' , ' discount ' , ' product_uom_qty ' ] , 10 ) ,
2008-12-13 06:05:19 +00:00
} ,
2012-12-20 11:47:30 +00:00
multi = ' sums ' , help = " The amount without tax. " , track_visibility = ' always ' ) ,
2013-12-18 13:19:42 +00:00
' amount_tax ' : fields . function ( _amount_all_wrapper , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Taxes ' ,
2012-12-18 18:17:18 +00:00
store = {
2009-08-20 15:32:05 +00:00
' sale.order ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' order_line ' ] , 10 ) ,
2009-08-26 13:41:53 +00:00
' sale.order.line ' : ( _get_order , [ ' price_unit ' , ' tax_id ' , ' discount ' , ' product_uom_qty ' ] , 10 ) ,
2008-12-13 06:05:19 +00:00
} ,
2010-12-13 06:07:23 +00:00
multi = ' sums ' , help = " The tax amount. " ) ,
2013-12-18 13:19:42 +00:00
' amount_total ' : fields . function ( _amount_all_wrapper , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Total ' ,
2012-12-18 18:17:18 +00:00
store = {
2009-08-20 15:32:05 +00:00
' sale.order ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' order_line ' ] , 10 ) ,
2009-08-26 13:41:53 +00:00
' sale.order.line ' : ( _get_order , [ ' price_unit ' , ' tax_id ' , ' discount ' , ' product_uom_qty ' ] , 10 ) ,
2008-12-13 06:05:19 +00:00
} ,
2010-12-13 06:07:23 +00:00
multi = ' sums ' , help = " The total amount. " ) ,
2008-12-07 12:45:27 +00:00
2012-12-21 16:48:08 +00:00
' invoice_quantity ' : fields . selection ( [ ( ' order ' , ' Ordered Quantities ' ) ] , ' Invoice on ' , help = " The sales order will automatically create the invoice proposition (draft invoice). " , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2009-08-26 13:41:53 +00:00
' payment_term ' : fields . many2one ( ' account.payment.term ' , ' Payment Term ' ) ,
2009-11-20 13:47:42 +00:00
' fiscal_position ' : fields . many2one ( ' account.fiscal.position ' , ' Fiscal Position ' ) ,
2013-06-14 14:16:43 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' ) ,
2008-07-22 15:11:28 +00:00
}
_defaults = {
2012-02-13 18:07:41 +00:00
' date_order ' : fields . date . context_today ,
2012-09-09 10:11:56 +00:00
' order_policy ' : ' manual ' ,
2013-01-22 11:08:57 +00:00
' company_id ' : _get_default_company ,
2010-06-22 07:15:50 +00:00
' state ' : ' draft ' ,
2008-07-22 15:11:28 +00:00
' user_id ' : lambda obj , cr , uid , context : uid ,
2012-11-29 05:57:43 +00:00
' name ' : lambda obj , cr , uid , context : ' / ' ,
2010-06-22 07:15:50 +00:00
' invoice_quantity ' : ' order ' ,
2008-07-22 15:11:28 +00:00
' partner_invoice_id ' : lambda self , cr , uid , context : context . get ( ' partner_id ' , False ) and self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ context [ ' partner_id ' ] ] , [ ' invoice ' ] ) [ ' invoice ' ] ,
' partner_shipping_id ' : lambda self , cr , uid , context : context . get ( ' partner_id ' , False ) and self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ context [ ' partner_id ' ] ] , [ ' delivery ' ] ) [ ' delivery ' ] ,
2013-03-01 08:29:28 +00:00
' note ' : lambda self , cr , uid , context : self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context ) . company_id . sale_note
2008-07-22 15:11:28 +00:00
}
2010-12-21 05:04:12 +00:00
_sql_constraints = [
2011-11-14 09:05:20 +00:00
( ' name_uniq ' , ' unique(name, company_id) ' , ' Order Reference must be unique per Company! ' ) ,
2010-12-21 05:04:12 +00:00
]
2014-01-15 14:05:27 +00:00
_order = ' date_order desc, id desc '
2008-07-22 15:11:28 +00:00
# Form filling
2009-01-21 11:21:21 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2010-04-13 10:35:39 +00:00
sale_orders = self . read ( cr , uid , ids , [ ' state ' ] , context = context )
2008-09-20 12:36:51 +00:00
unlink_ids = [ ]
for s in sale_orders :
2009-08-26 13:41:53 +00:00
if s [ ' state ' ] in [ ' draft ' , ' cancel ' ] :
2008-09-20 12:36:51 +00:00
unlink_ids . append ( s [ ' id ' ] )
else :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' Invalid Action! ' ) , _ ( ' In order to delete a confirmed sales order, you must cancel it before! ' ) )
2011-09-18 13:41:16 +00:00
2009-01-21 11:21:21 +00:00
return osv . osv . unlink ( self , cr , uid , unlink_ids , context = context )
2008-12-01 13:00:56 +00:00
2012-11-09 06:35:31 +00:00
def copy_quotation ( self , cr , uid , ids , context = None ) :
2012-11-09 05:27:48 +00:00
id = self . copy ( cr , uid , ids [ 0 ] , context = None )
view_ref = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' sale ' , ' view_order_form ' )
view_id = view_ref and view_ref [ 1 ] or False ,
return {
' type ' : ' ir.actions.act_window ' ,
' name ' : _ ( ' Sales Order ' ) ,
' res_model ' : ' sale.order ' ,
' res_id ' : id ,
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' view_id ' : view_id ,
' target ' : ' current ' ,
2012-11-09 06:35:31 +00:00
' nodestroy ' : True ,
2012-11-09 05:27:48 +00:00
}
2012-03-05 17:14:23 +00:00
def onchange_pricelist_id ( self , cr , uid , ids , pricelist_id , order_lines , context = None ) :
2012-11-13 08:09:08 +00:00
context = context or { }
2012-10-10 11:12:05 +00:00
if not pricelist_id :
2011-09-21 07:33:59 +00:00
return { }
2012-10-10 11:12:05 +00:00
value = {
' currency_id ' : self . pool . get ( ' product.pricelist ' ) . browse ( cr , uid , pricelist_id , context = context ) . currency_id . id
}
if not order_lines :
return { ' value ' : value }
2011-09-21 07:33:59 +00:00
warning = {
' title ' : _ ( ' Pricelist Warning! ' ) ,
' message ' : _ ( ' If you change the pricelist of this order (and eventually the currency), prices of existing order lines will not be updated. ' )
}
2012-10-10 11:12:05 +00:00
return { ' warning ' : warning , ' value ' : value }
2011-09-21 07:33:59 +00:00
2013-02-25 09:02:36 +00:00
def get_salenote ( self , cr , uid , ids , partner_id , context = None ) :
2013-02-15 13:33:09 +00:00
context_lang = context . copy ( )
if partner_id :
partner_lang = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id , context = context ) . lang
context_lang . update ( { ' lang ' : partner_lang } )
2013-02-25 09:02:36 +00:00
return self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context_lang ) . company_id . sale_note
2013-02-15 13:33:09 +00:00
2012-11-26 09:26:58 +00:00
def onchange_partner_id ( self , cr , uid , ids , part , context = None ) :
2008-07-22 15:11:28 +00:00
if not part :
2012-03-05 13:25:43 +00:00
return { ' value ' : { ' partner_invoice_id ' : False , ' partner_shipping_id ' : False , ' payment_term ' : False , ' fiscal_position ' : False } }
2010-02-03 11:43:14 +00:00
2012-11-26 09:26:58 +00:00
part = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , part , context = context )
addr = self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ part . id ] , [ ' delivery ' , ' invoice ' , ' contact ' ] )
2008-10-20 20:49:11 +00:00
pricelist = part . property_product_pricelist and part . property_product_pricelist . id or False
payment_term = part . property_payment_term and part . property_payment_term . id or False
2009-01-19 13:59:11 +00:00
fiscal_position = part . property_account_position and part . property_account_position . id or False
2010-02-05 08:56:30 +00:00
dedicated_salesman = part . user_id and part . user_id . id or uid
2010-02-03 11:43:14 +00:00
val = {
' partner_invoice_id ' : addr [ ' invoice ' ] ,
' partner_shipping_id ' : addr [ ' delivery ' ] ,
' payment_term ' : payment_term ,
' fiscal_position ' : fiscal_position ,
' user_id ' : dedicated_salesman ,
}
2009-03-08 18:54:10 +00:00
if pricelist :
val [ ' pricelist_id ' ] = pricelist
2013-02-25 09:02:36 +00:00
sale_note = self . get_salenote ( cr , uid , ids , part . id , context = context )
2013-03-01 08:29:28 +00:00
if sale_note : val . update ( { ' note ' : sale_note } )
2009-08-26 13:41:53 +00:00
return { ' value ' : val }
2008-07-22 15:11:28 +00:00
2010-04-13 10:35:39 +00:00
def create ( self , cr , uid , vals , context = None ) :
2013-03-05 10:48:01 +00:00
if context is None :
context = { }
if vals . get ( ' name ' , ' / ' ) == ' / ' :
2012-11-29 05:57:43 +00:00
vals [ ' name ' ] = self . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' sale.order ' ) or ' / '
2013-12-06 13:51:11 +00:00
if vals . get ( ' partner_id ' ) and any ( f not in vals for f in [ ' partner_invoice_id ' , ' partner_shipping_id ' , ' pricelist_id ' ] ) :
defaults = self . onchange_partner_id ( cr , uid , [ ] , vals [ ' partner_id ' ] , context ) [ ' value ' ]
vals = dict ( defaults , * * vals )
2013-03-05 10:48:01 +00:00
context . update ( { ' mail_create_nolog ' : True } )
new_id = super ( sale_order , self ) . create ( cr , uid , vals , context = context )
self . message_post ( cr , uid , [ new_id ] , body = _ ( " Quotation created " ) , context = context )
return new_id
2008-12-01 13:00:56 +00:00
2010-04-13 10:35:39 +00:00
def button_dummy ( self , cr , uid , ids , context = None ) :
2008-07-22 15:11:28 +00:00
return True
2006-12-07 13:41:40 +00:00
2012-02-15 17:09:11 +00:00
# FIXME: deprecated method, overriders should be using _prepare_invoice() instead.
# can be removed after 6.1.
2010-04-13 10:35:39 +00:00
def _inv_get ( self , cr , uid , order , context = None ) :
2008-07-22 15:11:28 +00:00
return { }
2012-02-01 18:31:23 +00:00
def _prepare_invoice ( self , cr , uid , order , lines , context = None ) :
2012-02-15 17:09:11 +00:00
""" Prepare the dict of values to create the new invoice for a
2012-12-21 16:48:08 +00:00
sales order . This method may be overridden to implement custom
2012-02-15 17:09:11 +00:00
invoice generation ( making sure to call super ( ) to establish
a clean extension chain ) .
: param browse_record order : sale . order record to invoice
: param list ( int ) line : list of invoice line IDs that must be
attached to the invoice
: return : dict of value to create ( ) the invoice
2012-02-01 18:31:23 +00:00
"""
2010-04-13 10:35:39 +00:00
if context is None :
context = { }
2012-02-01 18:31:23 +00:00
journal_ids = self . pool . get ( ' account.journal ' ) . search ( cr , uid ,
[ ( ' type ' , ' = ' , ' sale ' ) , ( ' company_id ' , ' = ' , order . company_id . id ) ] ,
limit = 1 )
2010-06-22 07:00:51 +00:00
if not journal_ids :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) ,
2012-07-25 11:07:02 +00:00
_ ( ' Please define sales journal for this company: " %s " (id: %d ). ' ) % ( order . company_id . name , order . company_id . id ) )
2012-02-15 17:09:11 +00:00
invoice_vals = {
2010-12-29 14:53:10 +00:00
' name ' : order . client_order_ref or ' ' ,
2008-07-22 15:11:28 +00:00
' origin ' : order . name ,
' type ' : ' out_invoice ' ,
2011-01-17 08:05:56 +00:00
' reference ' : order . client_order_ref or order . name ,
2012-02-01 18:31:23 +00:00
' account_id ' : order . partner_id . property_account_receivable . id ,
2012-11-26 15:51:39 +00:00
' partner_id ' : order . partner_invoice_id . id ,
2009-12-02 11:20:06 +00:00
' journal_id ' : journal_ids [ 0 ] ,
2009-08-26 13:41:53 +00:00
' invoice_line ' : [ ( 6 , 0 , lines ) ] ,
' currency_id ' : order . pricelist_id . currency_id . id ,
2008-07-22 15:11:28 +00:00
' comment ' : order . note ,
2012-02-01 18:31:23 +00:00
' payment_term ' : order . payment_term and order . payment_term . id or False ,
2010-05-19 06:31:40 +00:00
' fiscal_position ' : order . fiscal_position . id or order . partner_id . property_account_position . id ,
2012-02-01 18:31:23 +00:00
' date_invoice ' : context . get ( ' date_invoice ' , False ) ,
2010-10-15 09:42:54 +00:00
' company_id ' : order . company_id . id ,
2012-09-21 08:13:39 +00:00
' user_id ' : order . user_id and order . user_id . id or False
2008-07-22 15:11:28 +00:00
}
2012-02-01 18:31:23 +00:00
2012-02-15 17:09:11 +00:00
# Care for deprecated _inv_get() hook - FIXME: to be removed after 6.1
invoice_vals . update ( self . _inv_get ( cr , uid , order , context = context ) )
return invoice_vals
2012-02-01 18:31:23 +00:00
def _make_invoice ( self , cr , uid , order , lines , context = None ) :
inv_obj = self . pool . get ( ' account.invoice ' )
obj_invoice_line = self . pool . get ( ' account.invoice.line ' )
if context is None :
context = { }
invoiced_sale_line_ids = self . pool . get ( ' sale.order.line ' ) . search ( cr , uid , [ ( ' order_id ' , ' = ' , order . id ) , ( ' invoiced ' , ' = ' , True ) ] , context = context )
from_line_invoice_ids = [ ]
for invoiced_sale_line_id in self . pool . get ( ' sale.order.line ' ) . browse ( cr , uid , invoiced_sale_line_ids , context = context ) :
for invoice_line_id in invoiced_sale_line_id . invoice_lines :
if invoice_line_id . invoice_id . id not in from_line_invoice_ids :
from_line_invoice_ids . append ( invoice_line_id . invoice_id . id )
for preinv in order . invoice_ids :
if preinv . state not in ( ' cancel ' , ) and preinv . id not in from_line_invoice_ids :
for preline in preinv . invoice_line :
inv_line_id = obj_invoice_line . copy ( cr , uid , preline . id , { ' invoice_id ' : False , ' price_unit ' : - preline . price_unit } )
lines . append ( inv_line_id )
inv = self . _prepare_invoice ( cr , uid , order , lines , context = context )
2010-04-13 10:35:39 +00:00
inv_id = inv_obj . create ( cr , uid , inv , context = context )
2012-02-01 18:31:23 +00:00
data = inv_obj . onchange_payment_term_date_invoice ( cr , uid , [ inv_id ] , inv [ ' payment_term ' ] , time . strftime ( DEFAULT_SERVER_DATE_FORMAT ) )
2009-08-26 13:41:53 +00:00
if data . get ( ' value ' , False ) :
2008-12-02 10:17:42 +00:00
inv_obj . write ( cr , uid , [ inv_id ] , data [ ' value ' ] , context = context )
2008-07-22 15:11:28 +00:00
inv_obj . button_compute ( cr , uid , [ inv_id ] )
return inv_id
2012-02-29 09:46:32 +00:00
def print_quotation ( self , cr , uid , ids , context = None ) :
2012-05-25 15:17:40 +00:00
'''
2012-12-21 16:48:08 +00:00
This function prints the sales order and mark it as sent , so that we can see more easily the next step of the workflow
2012-05-25 15:17:40 +00:00
'''
2012-05-25 13:35:36 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time '
2013-02-01 06:59:48 +00:00
self . signal_quotation_sent ( cr , uid , ids )
2014-02-12 23:00:02 +00:00
return self . pool [ ' report ' ] . get_action ( cr , uid , ids , ' sale.report_saleorder ' , context = context )
2012-08-07 11:06:16 +00:00
2010-10-11 11:43:11 +00:00
def manual_invoice ( self , cr , uid , ids , context = None ) :
2012-12-21 16:48:08 +00:00
""" create invoices for the given sales orders (ids), and open the form
2012-07-23 13:14:53 +00:00
view of one of the newly created invoices
"""
2010-10-14 08:13:33 +00:00
mod_obj = self . pool . get ( ' ir.model.data ' )
2013-01-31 04:46:08 +00:00
2012-12-21 16:48:08 +00:00
# create invoices through the sales orders' workflow
2012-07-23 13:14:53 +00:00
inv_ids0 = set ( inv . id for sale in self . browse ( cr , uid , ids , context ) for inv in sale . invoice_ids )
2013-01-31 04:46:08 +00:00
self . signal_manual_invoice ( cr , uid , ids )
2012-07-23 13:14:53 +00:00
inv_ids1 = set ( inv . id for sale in self . browse ( cr , uid , ids , context ) for inv in sale . invoice_ids )
# determine newly created invoices
new_inv_ids = list ( inv_ids1 - inv_ids0 )
2011-11-25 10:52:37 +00:00
2010-10-28 13:16:19 +00:00
res = mod_obj . get_object_reference ( cr , uid , ' account ' , ' invoice_form ' )
2010-10-29 04:17:01 +00:00
res_id = res and res [ 1 ] or False ,
2011-11-25 10:52:37 +00:00
2010-10-29 04:17:01 +00:00
return {
2011-05-09 09:41:00 +00:00
' name ' : _ ( ' Customer Invoices ' ) ,
2010-10-11 11:43:11 +00:00
' view_type ' : ' form ' ,
2010-10-14 08:13:33 +00:00
' view_mode ' : ' form ' ,
2010-10-29 04:17:01 +00:00
' view_id ' : [ res_id ] ,
2010-10-11 11:43:11 +00:00
' res_model ' : ' account.invoice ' ,
2010-10-14 08:13:33 +00:00
' context ' : " { ' type ' : ' out_invoice ' } " ,
2010-10-11 11:43:11 +00:00
' type ' : ' ir.actions.act_window ' ,
2010-10-21 09:30:04 +00:00
' nodestroy ' : True ,
2010-10-17 11:59:01 +00:00
' target ' : ' current ' ,
2012-07-23 13:14:53 +00:00
' res_id ' : new_inv_ids and new_inv_ids [ 0 ] or False ,
2010-10-17 11:59:01 +00:00
}
2010-10-11 11:43:11 +00:00
2012-03-06 05:08:47 +00:00
def action_view_invoice ( self , cr , uid , ids , context = None ) :
2012-05-25 13:35:36 +00:00
'''
2012-12-21 16:48:08 +00:00
This function returns an action that display existing invoices of given sales order ids . It can either be a in a list or in a form view , if there is only one invoice to show .
2012-05-25 13:35:36 +00:00
'''
2012-03-06 05:08:47 +00:00
mod_obj = self . pool . get ( ' ir.model.data ' )
2012-08-24 07:04:44 +00:00
act_obj = self . pool . get ( ' ir.actions.act_window ' )
result = mod_obj . get_object_reference ( cr , uid , ' account ' , ' action_invoice_tree1 ' )
id = result and result [ 1 ] or False
result = act_obj . read ( cr , uid , [ id ] , context = context ) [ 0 ]
2012-05-25 13:35:36 +00:00
#compute the number of invoices to display
2012-03-06 05:08:47 +00:00
inv_ids = [ ]
for so in self . browse ( cr , uid , ids , context = context ) :
2012-05-25 13:35:36 +00:00
inv_ids + = [ invoice . id for invoice in so . invoice_ids ]
#choose the view_mode accordingly
2012-03-19 05:27:15 +00:00
if len ( inv_ids ) > 1 :
2012-08-24 07:04:44 +00:00
result [ ' domain ' ] = " [( ' id ' , ' in ' ,[ " + ' , ' . join ( map ( str , inv_ids ) ) + " ])] "
2012-03-19 05:27:15 +00:00
else :
res = mod_obj . get_object_reference ( cr , uid , ' account ' , ' invoice_form ' )
2012-08-24 07:04:44 +00:00
result [ ' views ' ] = [ ( res and res [ 1 ] or False , ' form ' ) ]
result [ ' res_id ' ] = inv_ids and inv_ids [ 0 ] or False
2012-03-19 05:27:15 +00:00
return result
2012-09-16 14:45:29 +00:00
def test_no_product ( self , cr , uid , order , context ) :
for line in order . order_line :
2012-09-16 15:05:17 +00:00
if line . product_id and ( line . product_id . type < > ' service ' ) :
2012-09-16 14:45:29 +00:00
return False
2012-09-06 13:13:10 +00:00
return True
2012-09-21 08:13:39 +00:00
2012-12-15 17:05:59 +00:00
def action_invoice_create ( self , cr , uid , ids , grouped = False , states = None , date_invoice = False , context = None ) :
2012-03-05 17:14:23 +00:00
if states is None :
states = [ ' confirmed ' , ' done ' , ' exception ' ]
2008-07-22 15:11:28 +00:00
res = False
invoices = { }
invoice_ids = [ ]
2010-06-24 09:45:18 +00:00
invoice = self . pool . get ( ' account.invoice ' )
2010-10-15 09:42:54 +00:00
obj_sale_order_line = self . pool . get ( ' sale.order.line ' )
2011-09-24 11:25:29 +00:00
partner_currency = { }
2010-06-22 07:15:50 +00:00
if context is None :
context = { }
2009-11-13 05:41:16 +00:00
# If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
2009-09-24 10:46:21 +00:00
# last day of the last month as invoice date
2012-12-15 17:05:59 +00:00
if date_invoice :
context [ ' date_invoice ' ] = date_invoice
2010-12-13 06:43:09 +00:00
for o in self . browse ( cr , uid , ids , context = context ) :
2011-09-24 11:25:29 +00:00
currency_id = o . pricelist_id . currency_id . id
if ( o . partner_id . id in partner_currency ) and ( partner_currency [ o . partner_id . id ] < > currency_id ) :
raise osv . except_osv (
2012-08-07 11:31:37 +00:00
_ ( ' Error! ' ) ,
2011-09-24 11:25:29 +00:00
_ ( ' You cannot group sales having different currencies for the same partner. ' ) )
partner_currency [ o . partner_id . id ] = currency_id
2008-07-22 15:11:28 +00:00
lines = [ ]
for line in o . order_line :
2010-07-18 19:43:57 +00:00
if line . invoiced :
2010-09-27 09:13:56 +00:00
continue
2010-07-18 19:43:57 +00:00
elif ( line . state in states ) :
2008-07-22 15:11:28 +00:00
lines . append ( line . id )
2010-10-15 09:42:54 +00:00
created_lines = obj_sale_order_line . invoice_line_create ( cr , uid , lines )
2008-07-22 15:11:28 +00:00
if created_lines :
2014-03-25 10:32:26 +00:00
invoices . setdefault ( o . partner_invoice_id . id or o . partner_id . id , [ ] ) . append ( ( o , created_lines ) )
2008-07-22 15:11:28 +00:00
if not invoices :
2010-12-13 06:43:09 +00:00
for o in self . browse ( cr , uid , ids , context = context ) :
2008-07-22 15:11:28 +00:00
for i in o . invoice_ids :
if i . state == ' draft ' :
return i . id
for val in invoices . values ( ) :
if grouped :
2010-10-15 08:48:13 +00:00
res = self . _make_invoice ( cr , uid , val [ 0 ] [ 0 ] , reduce ( lambda x , y : x + y , [ l for o , l in val ] , [ ] ) , context = context )
2010-06-24 09:45:18 +00:00
invoice_ref = ' '
2009-11-26 13:54:00 +00:00
for o , l in val :
2010-06-24 09:45:18 +00:00
invoice_ref + = o . name + ' | '
2009-11-26 13:54:00 +00:00
self . write ( cr , uid , [ o . id ] , { ' state ' : ' progress ' } )
2008-12-14 16:46:57 +00:00
cr . execute ( ' insert into sale_order_invoice_rel (order_id,invoice_id) values ( %s , %s ) ' , ( o . id , res ) )
2013-03-21 11:30:59 +00:00
#remove last '|' in invoice_ref
2013-03-20 14:43:36 +00:00
if len ( invoice_ref ) > = 1 :
invoice_ref = invoice_ref [ : - 1 ]
2010-06-24 09:45:18 +00:00
invoice . write ( cr , uid , [ res ] , { ' origin ' : invoice_ref , ' name ' : invoice_ref } )
2008-07-22 15:11:28 +00:00
else :
for order , il in val :
2009-09-24 10:46:21 +00:00
res = self . _make_invoice ( cr , uid , order , il , context = context )
2008-07-22 15:11:28 +00:00
invoice_ids . append ( res )
2009-08-26 13:41:53 +00:00
self . write ( cr , uid , [ order . id ] , { ' state ' : ' progress ' } )
2008-12-14 16:46:57 +00:00
cr . execute ( ' insert into sale_order_invoice_rel (order_id,invoice_id) values ( %s , %s ) ' , ( order . id , res ) )
2008-07-22 15:11:28 +00:00
return res
2010-04-13 10:35:39 +00:00
def action_invoice_cancel ( self , cr , uid , ids , context = None ) :
2012-11-29 15:33:30 +00:00
self . write ( cr , uid , ids , { ' state ' : ' invoice_except ' } , context = context )
2008-07-22 15:11:28 +00:00
return True
2010-02-09 08:31:46 +00:00
2010-04-13 10:35:39 +00:00
def action_invoice_end ( self , cr , uid , ids , context = None ) :
2012-11-29 16:26:29 +00:00
for this in self . browse ( cr , uid , ids , context = context ) :
for line in this . order_line :
2009-12-16 06:26:10 +00:00
if line . state == ' exception ' :
2012-11-29 16:26:29 +00:00
line . write ( { ' state ' : ' confirmed ' } )
if this . state == ' invoice_except ' :
this . write ( { ' state ' : ' progress ' } )
2009-12-16 06:26:10 +00:00
return True
2010-02-09 08:31:46 +00:00
2010-04-13 10:35:39 +00:00
def action_cancel ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
2008-07-22 15:11:28 +00:00
sale_order_line_obj = self . pool . get ( ' sale.order.line ' )
[IMP] Workflow api changes: [account_payment, account_voucher, hr_holidays, hr_payroll, hr_timesheet_sheet, l10n_in_hr_payroll, point_of_sale, procurement, purchase, sale, sale_stock].
bzr revid: tta@openerp.com-20130204082943-vfevxeb7za6r4sy7
bzr revid: tta@openerp.com-20130204112949-07l1v3ru215iglut
2013-02-04 11:29:49 +00:00
account_invoice_obj = self . pool . get ( ' account.invoice ' )
2010-04-13 10:35:39 +00:00
for sale in self . browse ( cr , uid , ids , context = context ) :
2008-07-22 15:11:28 +00:00
for inv in sale . invoice_ids :
2009-08-26 13:41:53 +00:00
if inv . state not in ( ' draft ' , ' cancel ' ) :
2008-07-22 15:11:28 +00:00
raise osv . except_osv (
2012-07-25 11:07:02 +00:00
_ ( ' Cannot cancel this sales order! ' ) ,
_ ( ' First cancel all invoices attached to this sales order. ' ) )
2009-08-26 13:41:53 +00:00
for r in self . read ( cr , uid , ids , [ ' invoice_ids ' ] ) :
[IMP] Workflow api changes: [account_payment, account_voucher, hr_holidays, hr_payroll, hr_timesheet_sheet, l10n_in_hr_payroll, point_of_sale, procurement, purchase, sale, sale_stock].
bzr revid: tta@openerp.com-20130204082943-vfevxeb7za6r4sy7
bzr revid: tta@openerp.com-20130204112949-07l1v3ru215iglut
2013-02-04 11:29:49 +00:00
account_invoice_obj . signal_invoice_cancel ( cr , uid , r [ ' invoice_ids ' ] )
2008-07-22 15:11:28 +00:00
sale_order_line_obj . write ( cr , uid , [ l . id for l in sale . order_line ] ,
{ ' state ' : ' cancel ' } )
2009-08-26 13:41:53 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' } )
2008-07-22 15:11:28 +00:00
return True
2012-07-13 22:51:31 +00:00
2012-05-18 11:39:37 +00:00
def action_button_confirm ( self , cr , uid , ids , context = None ) :
2012-07-25 11:07:02 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time. '
2013-01-31 04:46:08 +00:00
self . signal_order_confirm ( cr , uid , ids )
2012-05-18 11:39:37 +00:00
2012-12-21 16:48:08 +00:00
# redisplay the record as a sales order
2012-06-06 13:56:05 +00:00
view_ref = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' sale ' , ' view_order_form ' )
view_id = view_ref and view_ref [ 1 ] or False ,
2012-05-18 11:39:37 +00:00
return {
2012-06-06 13:56:05 +00:00
' type ' : ' ir.actions.act_window ' ,
2012-05-18 11:39:37 +00:00
' name ' : _ ( ' Sales Order ' ) ,
2012-06-06 13:56:05 +00:00
' res_model ' : ' sale.order ' ,
' res_id ' : ids [ 0 ] ,
2012-05-18 11:39:37 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' view_id ' : view_id ,
' target ' : ' current ' ,
2012-06-06 13:56:05 +00:00
' nodestroy ' : True ,
2012-05-18 11:39:37 +00:00
}
2008-07-22 15:11:28 +00:00
2012-02-13 18:07:41 +00:00
def action_wait ( self , cr , uid , ids , context = None ) :
2012-11-13 08:09:08 +00:00
context = context or { }
2008-07-22 15:11:28 +00:00
for o in self . browse ( cr , uid , ids ) :
2011-11-15 05:59:06 +00:00
if not o . order_line :
2012-12-21 16:48:08 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' You cannot confirm a sales order which has no line. ' ) )
2012-09-16 14:45:29 +00:00
noprod = self . test_no_product ( cr , uid , o , context )
if ( o . order_policy == ' manual ' ) or noprod :
2012-02-14 12:25:20 +00:00
self . write ( cr , uid , [ o . id ] , { ' state ' : ' manual ' , ' date_confirm ' : fields . date . context_today ( self , cr , uid , context = context ) } )
2012-09-17 06:21:00 +00:00
else :
self . write ( cr , uid , [ o . id ] , { ' state ' : ' progress ' , ' date_confirm ' : fields . date . context_today ( self , cr , uid , context = context ) } )
2008-07-22 15:11:28 +00:00
self . pool . get ( ' sale.order.line ' ) . button_confirm ( cr , uid , [ x . id for x in o . order_line ] )
2010-06-22 07:15:50 +00:00
return True
2008-07-22 15:11:28 +00:00
2012-05-25 13:35:36 +00:00
def action_quotation_send ( self , cr , uid , ids , context = None ) :
'''
This function opens a window to compose an email , with the edi sale template message loaded by default
'''
2012-07-25 11:07:02 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time. '
2012-10-23 11:56:28 +00:00
ir_model_data = self . pool . get ( ' ir.model.data ' )
try :
template_id = ir_model_data . get_object_reference ( cr , uid , ' sale ' , ' email_template_edi_sale ' ) [ 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 :
compose_form_id = False
2012-09-11 09:40:07 +00:00
ctx = dict ( context )
ctx . update ( {
' default_model ' : ' sale.order ' ,
' default_res_id ' : ids [ 0 ] ,
2012-10-23 11:56:28 +00:00
' default_use_template ' : bool ( template_id ) ,
2012-09-11 09:40:07 +00:00
' default_template_id ' : template_id ,
2012-11-13 11:20:38 +00:00
' default_composition_mode ' : ' comment ' ,
2012-09-20 09:58:25 +00:00
' mark_so_as_sent ' : True
} )
2012-02-29 09:46:32 +00:00
return {
2012-10-23 11:56:28 +00:00
' type ' : ' ir.actions.act_window ' ,
2012-02-29 09:46:32 +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-02-29 09:46:32 +00:00
' target ' : ' new ' ,
' context ' : ctx ,
}
2012-09-09 10:11:56 +00:00
def action_done ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' done ' } , context = context )
2012-09-21 08:13:39 +00:00
2014-05-05 08:57:55 +00:00
def onchange_fiscal_position ( self , cr , uid , ids , fiscal_position , order_lines , context = None ) :
order_line = [ ]
fiscal_obj = self . pool . get ( ' account.fiscal.position ' )
product_obj = self . pool . get ( ' product.product ' )
line_obj = self . pool . get ( ' sale.order.line ' )
fpos = False
if fiscal_position :
fpos = fiscal_obj . browse ( cr , uid , fiscal_position , context = context )
for line in order_lines :
# create (0, 0, { fields })
# update (1, ID, { fields })
if line [ 0 ] in [ 0 , 1 ] :
taxes_id = None
if line [ 2 ] . get ( ' product_id ' ) :
taxes_id = product_obj . browse ( cr , uid , line [ 2 ] [ ' product_id ' ] , context = context ) . taxes_id
elif line [ 1 ] :
2014-05-05 09:23:00 +00:00
# don't change taxes if they are no product defined
2014-05-05 08:57:55 +00:00
taxes_id = line_obj . browse ( cr , uid , line [ 1 ] , context = context ) . product_id . taxes_id
if taxes_id :
line [ 2 ] [ ' tax_id ' ] = [ [ 6 , 0 , fiscal_obj . map_tax ( cr , uid , fpos , taxes_id ) ] ]
order_line . append ( line )
# link (4, ID)
# link all (6, 0, IDS)
elif line [ 0 ] in [ 4 , 6 ] :
line_ids = line [ 0 ] == 4 and [ line [ 1 ] ] or line [ 2 ]
for line_id in line_ids :
taxes_id = line_obj . browse ( cr , uid , line_id , context = context ) . product_id . taxes_id
order_line . append ( [ 1 , line_id , { ' tax_id ' : [ [ 6 , 0 , fiscal_obj . map_tax ( cr , uid , fpos , taxes_id ) ] ] } ] )
else :
order_line . append ( line )
return { ' value ' : { ' order_line ' : order_line } }
2012-09-09 10:11:56 +00:00
2006-12-07 13:41:40 +00:00
2007-09-11 14:14:15 +00:00
# TODO add a field price_unit_uos
# - update it on change product and unit price
# - use it in report if there is a uos
2006-12-07 13:41:40 +00:00
class sale_order_line ( osv . osv ) :
2010-08-18 10:49:46 +00:00
2010-04-13 10:35:39 +00:00
def _amount_line ( self , cr , uid , ids , field_name , arg , context = None ) :
2010-06-05 21:39:55 +00:00
tax_obj = self . pool . get ( ' account.tax ' )
2009-08-26 13:41:53 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2010-06-22 07:15:50 +00:00
res = { }
2010-12-13 06:43:09 +00:00
if context is None :
context = { }
2010-04-13 10:35:39 +00:00
for line in self . browse ( cr , uid , ids , context = context ) :
2010-07-13 08:22:18 +00:00
price = line . price_unit * ( 1 - ( line . discount or 0.0 ) / 100.0 )
2012-03-29 12:41:38 +00:00
taxes = tax_obj . compute_all ( cr , uid , line . tax_id , price , line . product_uom_qty , line . product_id , line . order_id . partner_id )
2008-07-22 15:11:28 +00:00
cur = line . order_id . pricelist_id . currency_id
2010-06-05 21:39:55 +00:00
res [ line . id ] = cur_obj . round ( cr , uid , cur , taxes [ ' total ' ] )
2008-07-22 15:11:28 +00:00
return res
2011-09-07 05:07:01 +00:00
def _get_uom_id ( self , cr , uid , * args ) :
2011-09-15 08:54:54 +00:00
try :
proxy = self . pool . get ( ' ir.model.data ' )
result = proxy . get_object_reference ( cr , uid , ' product ' , ' product_uom_unit ' )
return result [ 1 ]
except Exception , ex :
return False
2011-11-04 04:50:18 +00:00
2012-11-29 16:26:29 +00:00
def _fnct_line_invoiced ( self , cr , uid , ids , field_name , args , context = None ) :
res = dict . fromkeys ( ids , False )
for this in self . browse ( cr , uid , ids , context = context ) :
res [ this . id ] = this . invoice_lines and \
all ( iline . invoice_id . state != ' cancel ' for iline in this . invoice_lines )
return res
def _order_lines_from_invoice ( self , cr , uid , ids , context = None ) :
# direct access to the m2m table is the less convoluted way to achieve this (and is ok ACL-wise)
cr . execute ( """ SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN
sale_order_line sol ON ( sol . order_id = rel . order_id )
WHERE rel . invoice_id = ANY ( % s ) """ , (list(ids),))
return [ i [ 0 ] for i in cr . fetchall ( ) ]
2008-07-22 15:11:28 +00:00
_name = ' sale.order.line '
2010-12-13 06:07:23 +00:00
_description = ' Sales Order Line '
2008-07-22 15:11:28 +00:00
_columns = {
2010-02-16 14:27:23 +00:00
' order_id ' : fields . many2one ( ' sale.order ' , ' Order Reference ' , required = True , ondelete = ' cascade ' , select = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2013-05-22 13:08:42 +00:00
' name ' : fields . text ( ' Description ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-12-13 06:07:23 +00:00
' sequence ' : fields . integer ( ' Sequence ' , help = " Gives the sequence order when displaying a list of sales order lines. " ) ,
2012-12-11 05:15:31 +00:00
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , domain = [ ( ' sale_ok ' , ' = ' , True ) ] , change_default = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-08-04 18:59:19 +00:00
' invoice_lines ' : fields . many2many ( ' account.invoice.line ' , ' sale_order_line_invoice_rel ' , ' order_line_id ' , ' invoice_id ' , ' Invoice Lines ' , readonly = True ) ,
2012-11-29 16:26:29 +00:00
' invoiced ' : fields . function ( _fnct_line_invoiced , string = ' Invoiced ' , type = ' boolean ' ,
2013-03-12 12:12:18 +00:00
store = {
' account.invoice ' : ( _order_lines_from_invoice , [ ' state ' ] , 10 ) ,
' sale.order.line ' : ( lambda self , cr , uid , ids , ctx = None : ids , [ ' invoice_lines ' ] , 10 ) } ) ,
2012-07-11 13:06:15 +00:00
' price_unit ' : fields . float ( ' Unit Price ' , required = True , digits_compute = dp . get_precision ( ' Product Price ' ) , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-10-10 11:33:23 +00:00
' type ' : fields . selection ( [ ( ' make_to_stock ' , ' from stock ' ) , ( ' make_to_order ' , ' on order ' ) ] , ' Procurement Method ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
2012-10-31 13:08:08 +00:00
help = " From stock: When needed, the product is taken from the stock or we wait for replenishment. \n On order: When needed, the product is purchased or produced. " ) ,
2012-07-10 12:24:31 +00:00
' price_subtotal ' : fields . function ( _amount_line , string = ' Subtotal ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2010-10-21 09:30:04 +00:00
' tax_id ' : fields . many2many ( ' account.tax ' , ' sale_order_tax ' , ' order_line_id ' , ' tax_id ' , ' Taxes ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-10-31 11:03:26 +00:00
' address_allotment_id ' : fields . many2one ( ' res.partner ' , ' Allotment Partner ' , help = " A partner to whom the particular product needs to be allotted. " ) ,
2012-05-23 14:42:45 +00:00
' product_uom_qty ' : fields . float ( ' Quantity ' , digits_compute = dp . get_precision ( ' Product UoS ' ) , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-10-21 09:30:04 +00:00
' product_uom ' : fields . many2one ( ' product.uom ' , ' Unit of Measure ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2011-10-04 09:44:22 +00:00
' product_uos_qty ' : fields . float ( ' Quantity (UoS) ' , digits_compute = dp . get_precision ( ' Product UoS ' ) , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2009-01-27 11:15:46 +00:00
' product_uos ' : fields . many2one ( ' product.uom ' , ' Product UoS ' ) ,
2012-09-21 08:13:39 +00:00
' discount ' : fields . float ( ' Discount ( % ) ' , digits_compute = dp . get_precision ( ' Discount ' ) , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-10-21 09:30:04 +00:00
' th_weight ' : fields . float ( ' Weight ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2012-05-04 11:57:48 +00:00
' state ' : fields . selection ( [ ( ' cancel ' , ' Cancelled ' ) , ( ' draft ' , ' Draft ' ) , ( ' confirmed ' , ' Confirmed ' ) , ( ' exception ' , ' Exception ' ) , ( ' done ' , ' Done ' ) ] , ' Status ' , required = True , readonly = True ,
2012-10-12 11:42:58 +00:00
help = ' * The \' Draft \' status is set when the related sales order in draft status. \
\n * The \' Confirmed \' status is set when the related sales order is confirmed. \
\n * The \' Exception \' status is set when the related sales order is set as exception. \
\n * The \' Done \' status is set when the sales order line has been picked. \
\n * The \' Cancelled \' status is set when a user cancel the sales order related. ' ) ,
2010-12-09 12:52:30 +00:00
' order_partner_id ' : fields . related ( ' order_id ' , ' partner_id ' , type = ' many2one ' , relation = ' res.partner ' , store = True , string = ' Customer ' ) ,
2012-05-04 12:13:26 +00:00
' salesman_id ' : fields . related ( ' order_id ' , ' user_id ' , type = ' many2one ' , relation = ' res.users ' , store = True , string = ' Salesperson ' ) ,
2012-09-21 08:13:39 +00:00
' company_id ' : fields . related ( ' order_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = ' Company ' , store = True , readonly = True ) ,
2008-07-22 15:11:28 +00:00
}
2013-03-08 17:06:08 +00:00
_order = ' order_id desc, sequence, id '
2008-07-22 15:11:28 +00:00
_defaults = {
2011-09-07 05:07:01 +00:00
' product_uom ' : _get_uom_id ,
2010-06-22 07:15:50 +00:00
' discount ' : 0.0 ,
' product_uom_qty ' : 1 ,
' product_uos_qty ' : 1 ,
2010-10-21 09:30:04 +00:00
' sequence ' : 10 ,
2010-06-22 07:15:50 +00:00
' state ' : ' draft ' ,
2012-10-12 05:16:40 +00:00
' type ' : ' make_to_stock ' ,
2010-12-31 06:45:06 +00:00
' price_unit ' : 0.0 ,
2008-07-22 15:11:28 +00:00
}
2009-08-26 13:41:53 +00:00
2012-09-21 09:35:20 +00:00
def _get_line_qty ( self , cr , uid , line , context = None ) :
2012-09-21 08:13:39 +00:00
if ( line . order_id . invoice_quantity == ' order ' ) :
if line . product_uos :
return line . product_uos_qty or 0.0
2012-10-04 13:32:41 +00:00
return line . product_uom_qty
2012-09-21 08:13:39 +00:00
2012-09-21 09:35:20 +00:00
def _get_line_uom ( self , cr , uid , line , context = None ) :
2012-09-21 08:13:39 +00:00
if ( line . order_id . invoice_quantity == ' order ' ) :
if line . product_uos :
return line . product_uos . id
2012-10-04 13:32:41 +00:00
return line . product_uom . id
2012-09-21 08:13:39 +00:00
2012-02-01 18:28:09 +00:00
def _prepare_order_line_invoice_line ( self , cr , uid , line , account_id = False , context = None ) :
2012-02-15 17:09:11 +00:00
""" Prepare the dict of values to create the new invoice line for a
2012-12-21 16:48:08 +00:00
sales order line . This method may be overridden to implement custom
2012-02-15 17:09:11 +00:00
invoice generation ( making sure to call super ( ) to establish
a clean extension chain ) .
: param browse_record line : sale . order . line record to invoice
: param int account_id : optional ID of a G / L account to force
( this is used for returning products including service )
: return : dict of values to create ( ) the invoice line
2012-01-31 10:53:22 +00:00
"""
2012-09-09 10:11:56 +00:00
res = { }
2012-01-27 04:54:58 +00:00
if not line . invoiced :
if not account_id :
2008-07-22 15:11:28 +00:00
if line . product_id :
2012-07-27 01:52:02 +00:00
account_id = line . product_id . property_account_income . id
2012-01-27 04:54:58 +00:00
if not account_id :
account_id = line . product_id . categ_id . property_account_income_categ . id
if not account_id :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) ,
2012-07-25 11:07:02 +00:00
_ ( ' Please define income account for this product: " %s " (id: %d ). ' ) % \
2012-01-27 04:54:58 +00:00
( line . product_id . name , line . product_id . id , ) )
2008-07-22 15:11:28 +00:00
else :
2010-10-20 11:06:17 +00:00
prop = self . pool . get ( ' ir.property ' ) . get ( cr , uid ,
2008-07-22 15:11:28 +00:00
' property_account_income_categ ' , ' product.category ' ,
2010-10-20 11:06:17 +00:00
context = context )
2012-01-27 04:54:58 +00:00
account_id = prop and prop . id or False
2012-09-21 09:35:20 +00:00
uosqty = self . _get_line_qty ( cr , uid , line , context = context )
uos_id = self . _get_line_uom ( cr , uid , line , context = context )
2012-01-27 04:54:58 +00:00
pu = 0.0
if uosqty :
pu = round ( line . price_unit * line . product_uom_qty / uosqty ,
2012-07-11 13:06:15 +00:00
self . pool . get ( ' decimal.precision ' ) . precision_get ( cr , uid , ' Product Price ' ) )
2012-01-27 04:54:58 +00:00
fpos = line . order_id . fiscal_position or False
account_id = self . pool . get ( ' account.fiscal.position ' ) . map_account ( cr , uid , fpos , account_id )
if not account_id :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) ,
2012-07-31 12:42:10 +00:00
_ ( ' There is no Fiscal Position defined or Income category account defined for default properties of Product categories. ' ) )
2012-09-09 10:11:56 +00:00
res = {
2012-01-27 04:54:58 +00:00
' name ' : line . name ,
2012-10-08 12:17:45 +00:00
' sequence ' : line . sequence ,
2012-01-27 04:54:58 +00:00
' origin ' : line . order_id . name ,
' account_id ' : account_id ,
' price_unit ' : pu ,
' quantity ' : uosqty ,
' discount ' : line . discount ,
' uos_id ' : uos_id ,
' product_id ' : line . product_id . id or False ,
' invoice_line_tax_id ' : [ ( 6 , 0 , [ x . id for x in line . tax_id ] ) ] ,
' account_analytic_id ' : line . order_id . project_id and line . order_id . project_id . id or False ,
}
2012-01-31 10:53:22 +00:00
2012-09-09 10:11:56 +00:00
return res
2012-01-27 04:54:58 +00:00
def invoice_line_create ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
create_ids = [ ]
2012-01-31 10:53:22 +00:00
sales = set ( )
2012-01-27 04:54:58 +00:00
for line in self . browse ( cr , uid , ids , context = context ) :
2012-02-01 18:28:09 +00:00
vals = self . _prepare_order_line_invoice_line ( cr , uid , line , False , context )
2012-01-27 04:54:58 +00:00
if vals :
inv_id = self . pool . get ( ' account.invoice.line ' ) . create ( cr , uid , vals , context = context )
2013-03-12 12:12:18 +00:00
self . write ( cr , uid , [ line . id ] , { ' invoice_lines ' : [ ( 4 , inv_id ) ] } , context = context )
2012-01-31 10:53:22 +00:00
sales . add ( line . order_id . id )
2008-07-22 15:11:28 +00:00
create_ids . append ( inv_id )
2009-05-20 13:47:11 +00:00
# Trigger workflow events
2012-01-31 10:53:22 +00:00
for sale_id in sales :
2013-11-21 12:06:11 +00:00
workflow . trg_write ( uid , ' sale.order ' , sale_id , cr )
2008-07-22 15:11:28 +00:00
return create_ids
2010-04-13 10:35:39 +00:00
def button_cancel ( self , cr , uid , ids , context = None ) :
2008-12-14 16:46:57 +00:00
for line in self . browse ( cr , uid , ids , context = context ) :
if line . invoiced :
2012-12-21 16:48:08 +00:00
raise osv . except_osv ( _ ( ' Invalid Action! ' ) , _ ( ' You cannot cancel a sales order line that has already been invoiced. ' ) )
2009-08-26 13:41:53 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' cancel ' } )
2008-12-14 16:46:57 +00:00
2010-04-13 10:35:39 +00:00
def button_confirm ( self , cr , uid , ids , context = None ) :
2009-08-26 13:41:53 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' confirmed ' } )
2008-07-22 15:11:28 +00:00
2010-04-13 10:35:39 +00:00
def button_done ( self , cr , uid , ids , context = None ) :
2009-08-26 13:41:53 +00:00
res = self . write ( cr , uid , ids , { ' state ' : ' done ' } )
2010-04-13 10:35:39 +00:00
for line in self . browse ( cr , uid , ids , context = context ) :
2013-11-21 12:06:11 +00:00
workflow . trg_write ( uid , ' sale.order ' , line . order_id . id , cr )
2008-07-22 15:11:28 +00:00
return res
def uos_change ( self , cr , uid , ids , product_uos , product_uos_qty = 0 , product_id = None ) :
product_obj = self . pool . get ( ' product.product ' )
if not product_id :
return { ' value ' : { ' product_uom ' : product_uos ,
2009-08-26 13:41:53 +00:00
' product_uom_qty ' : product_uos_qty } , ' domain ' : { } }
2008-07-22 15:11:28 +00:00
product = product_obj . browse ( cr , uid , product_id )
value = {
2009-08-26 13:41:53 +00:00
' product_uom ' : product . uom_id . id ,
2008-07-22 15:11:28 +00:00
}
# FIXME must depend on uos/uom of the product and not only of the coeff.
try :
value . update ( {
2009-08-26 13:41:53 +00:00
' product_uom_qty ' : product_uos_qty / product . uos_coeff ,
' th_weight ' : product_uos_qty / product . uos_coeff * product . weight
2008-07-22 15:11:28 +00:00
} )
except ZeroDivisionError :
pass
2009-08-26 13:41:53 +00:00
return { ' value ' : value }
2008-07-22 15:11:28 +00:00
2013-12-06 13:51:11 +00:00
def create ( self , cr , uid , values , context = None ) :
if values . get ( ' order_id ' ) and values . get ( ' product_id ' ) and any ( f not in values for f in [ ' name ' , ' price_unit ' , ' type ' , ' product_uom_qty ' , ' product_uom ' ] ) :
order = self . pool [ ' sale.order ' ] . read ( cr , uid , values [ ' order_id ' ] , [ ' pricelist_id ' , ' partner_id ' , ' date_order ' , ' fiscal_position ' ] , context = context )
defaults = self . product_id_change ( cr , uid , [ ] , order [ ' pricelist_id ' ] [ 0 ] , values [ ' product_id ' ] ,
qty = float ( values . get ( ' product_uom_qty ' , False ) ) ,
uom = values . get ( ' product_uom ' , False ) ,
qty_uos = float ( values . get ( ' product_uos_qty ' , False ) ) ,
uos = values . get ( ' product_uos ' , False ) ,
name = values . get ( ' name ' , False ) ,
partner_id = order [ ' partner_id ' ] [ 0 ] ,
date_order = order [ ' date_order ' ] ,
fiscal_position = order [ ' fiscal_position ' ] [ 0 ] if order [ ' fiscal_position ' ] else False ,
flag = False , # Force name update
context = context
) [ ' value ' ]
values = dict ( defaults , * * values )
return super ( sale_order_line , self ) . create ( cr , uid , values , context = context )
2010-04-13 10:35:39 +00:00
def copy_data ( self , cr , uid , id , default = None , context = None ) :
2008-07-22 15:11:28 +00:00
if not default :
default = { }
2012-11-29 16:26:29 +00:00
default . update ( { ' state ' : ' draft ' , ' invoice_lines ' : [ ] } )
2010-04-13 10:35:39 +00:00
return super ( sale_order_line , self ) . copy_data ( cr , uid , id , default , context = context )
2008-07-22 15:11:28 +00:00
def product_id_change ( self , cr , uid , ids , pricelist , product , qty = 0 ,
uom = False , qty_uos = 0 , uos = False , name = ' ' , partner_id = False ,
2011-07-01 15:12:37 +00:00
lang = False , update_tax = True , date_order = False , packaging = False , fiscal_position = False , flag = False , context = None ) :
context = context or { }
2011-09-17 11:40:55 +00:00
lang = lang or context . get ( ' lang ' , False )
2014-04-28 09:36:09 +00:00
if not partner_id :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Customer Defined! ' ) , _ ( ' Before choosing a product, \n select a customer in the sales form. ' ) )
2009-08-26 13:41:53 +00:00
warning = { }
2008-07-22 15:11:28 +00:00
product_uom_obj = self . pool . get ( ' product.uom ' )
partner_obj = self . pool . get ( ' res.partner ' )
product_obj = self . pool . get ( ' product.product ' )
2011-09-17 11:40:55 +00:00
context = { ' lang ' : lang , ' partner_id ' : partner_id }
2014-04-28 09:36:09 +00:00
partner = partner_obj . browse ( cr , uid , partner_id )
lang = partner . lang
2011-09-17 11:40:55 +00:00
context_partner = { ' lang ' : lang , ' partner_id ' : partner_id }
2008-07-22 15:11:28 +00:00
if not product :
2012-10-02 10:29:15 +00:00
return { ' value ' : { ' th_weight ' : 0 ,
2008-07-22 15:11:28 +00:00
' product_uos_qty ' : qty } , ' domain ' : { ' product_uom ' : [ ] ,
2008-09-16 08:51:19 +00:00
' product_uos ' : [ ] } }
2008-07-22 15:11:28 +00:00
if not date_order :
2011-10-11 14:19:21 +00:00
date_order = time . strftime ( DEFAULT_SERVER_DATE_FORMAT )
2008-09-07 23:24:39 +00:00
2012-09-09 10:11:56 +00:00
result = { }
2013-02-07 08:41:29 +00:00
warning_msgs = ' '
2012-11-01 12:57:56 +00:00
product_obj = product_obj . browse ( cr , uid , product , context = context_partner )
2008-09-29 08:49:12 +00:00
2010-06-26 15:15:23 +00:00
uom2 = False
2008-07-22 15:11:28 +00:00
if uom :
uom2 = product_uom_obj . browse ( cr , uid , uom )
2009-08-26 13:41:53 +00:00
if product_obj . uom_id . category_id . id != uom2 . category_id . id :
2008-07-22 15:11:28 +00:00
uom = False
if uos :
2008-09-07 23:24:39 +00:00
if product_obj . uos_id :
2008-07-22 15:11:28 +00:00
uos2 = product_uom_obj . browse ( cr , uid , uos )
2009-08-26 13:41:53 +00:00
if product_obj . uos_id . category_id . id != uos2 . category_id . id :
2008-07-22 15:11:28 +00:00
uos = False
else :
2010-05-25 10:38:59 +00:00
uos = False
2014-04-28 09:36:09 +00:00
fpos = False
if not fiscal_position :
fpos = partner . property_account_position or False
else :
fpos = self . pool . get ( ' account.fiscal.position ' ) . browse ( cr , uid , fiscal_position )
2008-07-22 15:11:28 +00:00
if update_tax : #The quantity only have changed
2009-01-20 06:04:07 +00:00
result [ ' tax_id ' ] = self . pool . get ( ' account.fiscal.position ' ) . map_tax ( cr , uid , fpos , product_obj . taxes_id )
2010-02-19 12:55:26 +00:00
2009-08-26 13:41:53 +00:00
if not flag :
2011-09-17 11:40:55 +00:00
result [ ' name ' ] = self . pool . get ( ' product.product ' ) . name_get ( cr , uid , [ product_obj . id ] , context = context_partner ) [ 0 ] [ 1 ]
2012-07-13 22:51:31 +00:00
if product_obj . description_sale :
result [ ' name ' ] + = ' \n ' + product_obj . description_sale
2008-07-22 15:11:28 +00:00
domain = { }
2009-02-04 22:18:53 +00:00
if ( not uom ) and ( not uos ) :
2008-09-07 23:24:39 +00:00
result [ ' product_uom ' ] = product_obj . uom_id . id
if product_obj . uos_id :
result [ ' product_uos ' ] = product_obj . uos_id . id
result [ ' product_uos_qty ' ] = qty * product_obj . uos_coeff
uos_category_id = product_obj . uos_id . category_id . id
2008-07-22 15:11:28 +00:00
else :
result [ ' product_uos ' ] = False
result [ ' product_uos_qty ' ] = qty
uos_category_id = False
2008-09-07 23:24:39 +00:00
result [ ' th_weight ' ] = qty * product_obj . weight
2008-07-22 15:11:28 +00:00
domain = { ' product_uom ' :
2008-09-07 23:24:39 +00:00
[ ( ' category_id ' , ' = ' , product_obj . uom_id . category_id . id ) ] ,
2008-07-22 15:11:28 +00:00
' product_uos ' :
[ ( ' category_id ' , ' = ' , uos_category_id ) ] }
2010-05-12 13:31:33 +00:00
elif uos and not uom : # only happens if uom is False
2009-02-04 22:18:53 +00:00
result [ ' product_uom ' ] = product_obj . uom_id and product_obj . uom_id . id
result [ ' product_uom_qty ' ] = qty_uos / product_obj . uos_coeff
result [ ' th_weight ' ] = result [ ' product_uom_qty ' ] * product_obj . weight
2008-07-22 15:11:28 +00:00
elif uom : # whether uos is set or not
2008-09-07 23:24:39 +00:00
default_uom = product_obj . uom_id and product_obj . uom_id . id
2008-07-22 15:11:28 +00:00
q = product_uom_obj . _compute_qty ( cr , uid , uom , qty , default_uom )
2008-09-07 23:24:39 +00:00
if product_obj . uos_id :
result [ ' product_uos ' ] = product_obj . uos_id . id
2009-02-04 22:18:53 +00:00
result [ ' product_uos_qty ' ] = qty * product_obj . uos_coeff
2008-07-22 15:11:28 +00:00
else :
result [ ' product_uos ' ] = False
2009-02-04 22:18:53 +00:00
result [ ' product_uos_qty ' ] = qty
result [ ' th_weight ' ] = q * product_obj . weight # Round the quantity up
2008-09-09 13:57:16 +00:00
2010-06-26 15:15:23 +00:00
if not uom2 :
uom2 = product_obj . uom_id
2008-09-09 13:57:16 +00:00
# get unit price
2011-07-06 09:35:40 +00:00
2008-09-09 13:57:16 +00:00
if not pricelist :
2011-05-02 07:12:07 +00:00
warn_msg = _ ( ' You have to select a pricelist or a customer in the sales form ! \n '
' Please set one before choosing a product. ' )
2011-05-04 09:49:34 +00:00
warning_msgs + = _ ( " No Pricelist ! : " ) + warn_msg + " \n \n "
2008-09-09 13:57:16 +00:00
else :
price = self . pool . get ( ' product.pricelist ' ) . price_get ( cr , uid , [ pricelist ] ,
product , qty or 1.0 , partner_id , {
2011-04-04 10:01:41 +00:00
' uom ' : uom or result . get ( ' product_uom ' ) ,
2008-09-09 13:57:16 +00:00
' date ' : date_order ,
} ) [ pricelist ]
if price is False :
2012-07-25 11:07:02 +00:00
warn_msg = _ ( " Cannot find a pricelist line matching this product and quantity. \n "
2011-05-02 07:12:07 +00:00
" You have to change either the product, the quantity or the pricelist. " )
2011-05-04 09:49:34 +00:00
warning_msgs + = _ ( " No valid pricelist line found ! : " ) + warn_msg + " \n \n "
2008-09-09 13:57:16 +00:00
else :
2008-09-29 08:49:12 +00:00
result . update ( { ' price_unit ' : price } )
2011-05-02 07:12:07 +00:00
if warning_msgs :
warning = {
2012-08-07 11:06:16 +00:00
' title ' : _ ( ' Configuration Error! ' ) ,
2011-07-06 09:35:40 +00:00
' message ' : warning_msgs
2011-05-02 07:12:07 +00:00
}
2009-08-26 13:41:53 +00:00
return { ' value ' : result , ' domain ' : domain , ' warning ' : warning }
2008-07-22 15:11:28 +00:00
def product_uom_change ( self , cursor , user , ids , pricelist , product , qty = 0 ,
uom = False , qty_uos = 0 , uos = False , name = ' ' , partner_id = False ,
2011-07-01 15:13:48 +00:00
lang = False , update_tax = True , date_order = False , context = None ) :
context = context or { }
lang = lang or ( ' lang ' in context and context [ ' lang ' ] )
2012-08-08 08:38:35 +00:00
if not uom :
return { ' value ' : { ' price_unit ' : 0.0 , ' product_uom ' : uom or False } }
return self . product_id_change ( cursor , user , ids , pricelist , product ,
2010-05-13 13:21:17 +00:00
qty = qty , uom = uom , qty_uos = qty_uos , uos = uos , name = name ,
2008-07-22 15:11:28 +00:00
partner_id = partner_id , lang = lang , update_tax = update_tax ,
2011-12-22 12:09:59 +00:00
date_order = date_order , context = context )
2009-08-26 13:41:53 +00:00
2010-04-13 10:35:39 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
2010-12-13 06:07:23 +00:00
""" Allows to delete sales order lines in draft,cancel states """
2009-07-28 12:57:21 +00:00
for rec in self . browse ( cr , uid , ids , context = context ) :
2009-08-26 13:41:53 +00:00
if rec . state not in [ ' draft ' , ' cancel ' ] :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' Invalid Action! ' ) , _ ( ' Cannot delete a sales order line which is in state \' %s \' . ' ) % ( rec . state , ) )
2009-07-28 12:57:21 +00:00
return super ( sale_order_line , self ) . unlink ( cr , uid , ids , context = context )
2011-11-25 10:52:37 +00:00
2013-02-11 10:12:57 +00:00
class res_company ( osv . Model ) :
_inherit = " res.company "
_columns = {
2013-03-01 16:28:06 +00:00
' sale_note ' : fields . text ( ' Default Terms and Conditions ' , translate = True , help = " Default terms and conditions for quotations. " ) ,
2013-03-01 08:29:28 +00:00
}
2008-06-20 11:49:23 +00:00
2012-12-21 09:59:02 +00:00
class mail_compose_message ( osv . Model ) :
2012-09-20 09:58:25 +00:00
_inherit = ' mail.compose.message '
2012-12-21 09:59:02 +00:00
2012-09-20 09:58:25 +00:00
def send_mail ( self , cr , uid , ids , context = None ) :
context = context or { }
2013-12-11 17:14:29 +00:00
if context . get ( ' default_model ' ) == ' sale.order ' and context . get ( ' default_res_id ' ) and context . get ( ' mark_so_as_sent ' ) :
2012-12-21 09:59:02 +00:00
context = dict ( context , mail_post_autofollow = True )
2013-12-11 17:14:29 +00:00
self . pool . get ( ' sale.order ' ) . signal_quotation_sent ( cr , uid , [ context [ ' default_res_id ' ] ] )
2012-09-20 09:58:25 +00:00
return super ( mail_compose_message , self ) . send_mail ( cr , uid , ids , context = context )
2009-08-26 13:41:53 +00:00
2013-03-05 10:48:01 +00:00
2013-02-07 07:01:27 +00:00
class account_invoice ( osv . Model ) :
_inherit = ' account.invoice '
2013-03-05 10:48:01 +00:00
2013-02-07 07:01:27 +00:00
def confirm_paid ( self , cr , uid , ids , context = None ) :
2013-03-05 10:48:01 +00:00
sale_order_obj = self . pool . get ( ' sale.order ' )
res = super ( account_invoice , self ) . confirm_paid ( cr , uid , ids , context = context )
so_ids = sale_order_obj . search ( cr , uid , [ ( ' invoice_ids ' , ' in ' , ids ) ] , context = context )
2014-02-19 17:07:46 +00:00
for so_id in so_ids :
sale_order_obj . message_post ( cr , uid , so_id , body = _ ( " Invoice paid " ) , context = context )
2013-02-07 07:01:27 +00:00
return res
2013-03-05 10:48:01 +00:00
2013-04-18 09:00:11 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2013-04-18 16:36:16 +00:00
""" Overwrite unlink method of account invoice to send a trigger to the sale workflow upon invoice deletion """
2013-04-18 09:00:11 +00:00
invoice_ids = self . search ( cr , uid , [ ( ' id ' , ' in ' , ids ) , ( ' state ' , ' in ' , [ ' draft ' , ' cancel ' ] ) ] , context = context )
2013-04-18 16:36:16 +00:00
#if we can't cancel all invoices, do nothing
if len ( invoice_ids ) == len ( ids ) :
#Cancel invoice(s) first before deleting them so that if any sale order is associated with them
#it will trigger the workflow to put the sale order in an 'invoice exception' state
2013-04-18 09:00:11 +00:00
for id in ids :
2013-11-21 12:06:11 +00:00
workflow . trg_validate ( uid , ' account.invoice ' , id , ' invoice_cancel ' , cr )
2013-04-18 09:00:11 +00:00
return super ( account_invoice , self ) . unlink ( cr , uid , ids , context = context )
2010-09-01 20:29:38 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: