2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2008-06-16 11:00:21 +00:00
##############################################################################
2009-11-13 05:41:16 +00:00
#
2009-10-14 11:15:34 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-06-16 11:00:21 +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.
2008-06-16 11:00:21 +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.
2008-06-16 11:00:21 +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/>.
2008-08-24 14:45:43 +00:00
#
##############################################################################
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
2013-07-10 15:00:42 +00:00
from openerp . tools . translate import _
class procurement_order ( osv . osv ) :
_name = " procurement.order "
_inherit = " procurement.order "
_columns = {
' task_id ' : fields . many2one ( ' project.task ' , ' Task ' ) ,
' sale_line_id ' : fields . many2one ( ' sale.order.line ' , ' Sales order line ' )
}
def _is_procurement_task ( self , cr , uid , procurement , context = None ) :
2013-08-13 16:16:54 +00:00
return procurement . product_id . type == ' service ' and procurement . product_id . auto_create_task or False
2013-07-10 15:00:42 +00:00
def _assign ( self , cr , uid , procurement , context = None ) :
res = super ( procurement_order , self ) . _assign ( cr , uid , procurement , context = context )
if not res :
#if there isn't any specific procurement.rule defined for the product, we may want to create a task
if self . _is_procurement_task ( cr , uid , procurement , context = context ) :
return True
return res
def _run ( self , cr , uid , procurement , context = None ) :
if self . _is_procurement_task ( cr , uid , procurement , context = context ) and not procurement . task_id :
#create a task for the procurement
return self . _create_service_task ( cr , uid , procurement , context = context )
return super ( procurement_order , self ) . _run ( cr , uid , procurement , context = context )
def _check ( self , cr , uid , procurement , context = None ) :
2013-09-17 06:43:59 +00:00
if self . _is_procurement_task ( cr , uid , procurement , context = context ) :
return procurement . task_id and procurement . task_id . stage_id . closed or False
2013-07-10 15:00:42 +00:00
return super ( procurement_order , self ) . _check ( cr , uid , procurement , context = context )
def _convert_qty_company_hours ( self , cr , uid , procurement , context = None ) :
product_uom = self . pool . get ( ' product.uom ' )
company_time_uom_id = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid ) . company_id . project_time_mode_id
if procurement . product_uom . id != company_time_uom_id . id and procurement . product_uom . category_id . id == company_time_uom_id . category_id . id :
planned_hours = product_uom . _compute_qty ( cr , uid , procurement . product_uom . id , procurement . product_qty , company_time_uom_id . id )
else :
planned_hours = procurement . product_qty
return planned_hours
def _get_project ( self , cr , uid , procurement , context = None ) :
project_project = self . pool . get ( ' project.project ' )
project = procurement . product_id . project_id
if not project and procurement . sale_line_id :
# find the project corresponding to the analytic account of the sales order
account = procurement . sale_line_id . order_id . project_id
project_ids = project_project . search ( cr , uid , [ ( ' analytic_account_id ' , ' = ' , account . id ) ] )
projects = project_project . browse ( cr , uid , project_ids , context = context )
2013-09-10 15:48:22 +00:00
project = projects and projects [ 0 ] or False
return project
def _create_service_task ( self , cr , uid , procurement , context = None ) :
project_task = self . pool . get ( ' project.task ' )
project = self . _get_project ( cr , uid , procurement , context = context )
planned_hours = self . _convert_qty_company_hours ( cr , uid , procurement , context = context )
task_id = project_task . create ( cr , uid , {
' name ' : ' %s : %s ' % ( procurement . origin or ' ' , procurement . product_id . name ) ,
' date_deadline ' : procurement . date_planned ,
' planned_hours ' : planned_hours ,
' remaining_hours ' : planned_hours ,
' partner_id ' : procurement . sale_line_id and procurement . sale_line_id . order_id . partner_id . id or False ,
' user_id ' : procurement . product_id . product_manager . id ,
' procurement_id ' : procurement . id ,
' description ' : procurement . name + ' \n ' ,
' project_id ' : project and project . id or False ,
' company_id ' : procurement . company_id . id ,
} , context = context )
2013-12-11 15:48:40 +00:00
self . write ( cr , uid , [ procurement . id ] , { ' task_id ' : task_id } , context = context )
2013-09-10 15:48:22 +00:00
self . project_task_create_note ( cr , uid , [ procurement . id ] , context = context )
return task_id
def project_task_create_note ( self , cr , uid , ids , context = None ) :
for procurement in self . browse ( cr , uid , ids , context = context ) :
body = _ ( " Task created " )
self . message_post ( cr , uid , [ procurement . id ] , body = body , context = context )
if procurement . sale_line_id and procurement . sale_line_id . order_id :
procurement . sale_line_id . order_id . message_post ( body = body )
2013-07-10 15:00:42 +00:00
2008-08-24 14:45:43 +00:00
2013-06-27 12:53:06 +00:00
class ProjectTaskStageMrp ( osv . Model ) :
""" Override project.task.type model to add a ' closed ' boolean field allowing
to know that tasks in this stage are considered as closed . Indeed since
OpenERP 8.0 status is not present on tasks anymore , only stage_id . """
_name = ' project.task.type '
_inherit = ' project.task.type '
_columns = {
2013-07-18 08:44:51 +00:00
' closed ' : fields . boolean ( ' Close ' , help = " Tasks in this stage are considered as closed. " ) ,
2013-06-27 12:53:06 +00:00
}
_defaults = {
' closed ' : False ,
}
2008-09-08 22:53:40 +00:00
class project_task ( osv . osv ) :
2008-08-24 14:45:43 +00:00
_name = " project.task "
_inherit = " project.task "
_columns = {
2011-04-14 11:49:50 +00:00
' procurement_id ' : fields . many2one ( ' procurement.order ' , ' Procurement ' , ondelete = ' set null ' ) ,
2012-12-21 16:48:08 +00:00
' sale_line_id ' : fields . related ( ' procurement_id ' , ' sale_line_id ' , type = ' many2one ' , relation = ' sale.order.line ' , store = True , string = ' Sales Order Line ' ) ,
2008-08-24 14:45:43 +00:00
}
2010-04-08 05:46:02 +00:00
2013-06-27 12:53:06 +00:00
def _validate_subflows ( self , cr , uid , ids , context = None ) :
2013-09-10 15:48:22 +00:00
proc_obj = self . pool . get ( " procurement.order " )
for task in self . browse ( cr , uid , ids , context = context ) :
2008-08-24 14:45:43 +00:00
if task . procurement_id :
2013-09-10 15:48:22 +00:00
proc_obj . check ( cr , uid , [ task . procurement_id . id ] , context = context )
2008-07-23 14:41:47 +00:00
2013-06-27 12:53:06 +00:00
def write ( self , cr , uid , ids , values , context = None ) :
""" When closing tasks, validate subflows. """
2013-07-10 12:25:26 +00:00
res = super ( project_task , self ) . write ( cr , uid , ids , values , context = context )
2013-06-27 12:53:06 +00:00
if values . get ( ' stage_id ' ) :
stage = self . pool . get ( ' project.task.type ' ) . browse ( cr , uid , values . get ( ' stage_id ' ) , context = context )
if stage . closed :
self . _validate_subflows ( cr , uid , ids , context = context )
2013-07-10 12:25:26 +00:00
return res
2010-09-01 21:34:07 +00:00
2010-07-08 13:33:42 +00:00
class product_product ( osv . osv ) :
_inherit = " product.product "
_columns = {
2013-07-10 15:00:42 +00:00
' project_id ' : fields . many2one ( ' project.project ' , ' Project ' , ondelete = ' set null ' , ) ,
' auto_create_task ' : fields . boolean ( ' Create Task Automatically ' , help = " Thick this option if you want to create a task automatically each time this product is sold " ) ,
2010-07-08 13:33:42 +00:00
}
2013-06-27 12:53:06 +00:00
2013-09-17 06:43:59 +00:00
class sale_order_line ( osv . osv ) :
_inherit = ' sale.order.line '
def need_procurement ( self , cr , uid , ids , context = None ) :
#when sale is installed alone, there is no need to create procurements, but with project_mrp
#we must create a procurement for each service that has the auto_create_task boolean set to True.
for line in self . browse ( cr , uid , ids , context = context ) :
if line . product_id and line . product_id . type == ' service ' and line . product_id . auto_create_task :
return True
return super ( sale_order_line , self ) . need_procurement ( cr , uid , ids , context = context )
2011-04-19 09:26:25 +00:00
class sale_order ( osv . osv ) :
2013-07-10 15:00:42 +00:00
_inherit = ' sale.order '
2011-04-27 10:06:34 +00:00
2011-04-19 09:26:25 +00:00
def _picked_rate ( self , cr , uid , ids , name , arg , context = None ) :
if not ids :
return { }
2011-04-28 07:44:26 +00:00
res_sale = { }
2011-04-27 10:06:34 +00:00
res = super ( sale_order , self ) . _picked_rate ( cr , uid , ids , name , arg , context = context )
2013-07-18 08:44:51 +00:00
cr . execute ( ''' select sol.order_id as sale_id, stage.closed as task_closed ,
2011-09-16 11:38:32 +00:00
t . id as task_id , sum ( sol . product_uom_qty ) as total
2011-04-19 09:26:25 +00:00
from project_task as t
2011-09-16 11:38:32 +00:00
left join sale_order_line as sol on sol . id = t . sale_line_id
2013-07-18 08:44:51 +00:00
left join project_task_type as stage on stage . id = t . stage_id
where sol . order_id in % s group by sol . order_id , stage . closed , t . id ''' ,(tuple(ids),))
2011-04-27 10:06:34 +00:00
sale_task_data = cr . dictfetchall ( )
2011-04-20 10:50:18 +00:00
2011-04-27 10:06:34 +00:00
if not sale_task_data :
return res
2011-09-16 11:38:32 +00:00
2011-04-28 07:44:26 +00:00
for id in ids :
2011-09-16 07:34:52 +00:00
res_sale [ id ] = {
' number_of_done ' : 0 ,
' total_no_task ' : 0 ,
}
2011-09-16 11:38:32 +00:00
#compute the sum of quantity for each SO
cr . execute ( ''' select sol.order_id as sale_id, sum(sol.product_uom_qty) as total
from sale_order_line sol where sol . order_id in % s group by sol . order_id ''' ,(tuple(ids),))
total_qtty_ref = cr . dictfetchall ( )
for item in total_qtty_ref :
res_sale [ item [ ' sale_id ' ] ] [ ' number_of_stockable ' ] = item [ ' total ' ]
2011-04-28 07:44:26 +00:00
2011-04-27 10:06:34 +00:00
for item in sale_task_data :
2011-04-28 07:44:26 +00:00
res_sale [ item [ ' sale_id ' ] ] [ ' total_no_task ' ] + = item [ ' total ' ]
2013-07-18 08:44:51 +00:00
if item [ ' task_closed ' ] :
2011-09-16 11:38:32 +00:00
res_sale [ item [ ' sale_id ' ] ] [ ' number_of_done ' ] + = item [ ' total ' ]
2011-09-16 07:34:52 +00:00
for sale in self . browse ( cr , uid , ids , context = context ) :
2012-01-02 10:08:34 +00:00
if ' number_of_stockable ' in res_sale [ sale . id ] :
res_sale [ sale . id ] [ ' number_of_stockable ' ] - = res_sale [ sale . id ] [ ' total_no_task ' ]
#adjust previously percentage because now we must also count the product of type service
res [ sale . id ] = res [ sale . id ] * float ( res_sale [ sale . id ] [ ' number_of_stockable ' ] ) / ( res_sale [ sale . id ] [ ' number_of_stockable ' ] + res_sale [ sale . id ] [ ' total_no_task ' ] )
#add the task
res [ sale . id ] + = res_sale [ sale . id ] [ ' number_of_done ' ] * 100 / ( res_sale [ sale . id ] [ ' number_of_stockable ' ] + res_sale [ sale . id ] [ ' total_no_task ' ] )
2011-04-19 09:26:25 +00:00
return res
2011-04-27 10:06:34 +00:00
2011-04-19 09:26:25 +00:00
_columns = {
2011-04-28 07:44:26 +00:00
' picked_rate ' : fields . function ( _picked_rate , method = True , string = ' Picked ' , type = ' float ' ) ,
}
2008-07-23 14:41:47 +00:00