2008-07-23 14:41:47 +00:00
# -*- encoding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
#
2009-02-04 09:46:57 +00:00
# OpenERP, Open Source Management Solution
2009-01-04 22:12:50 +00:00
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
2008-11-03 19:18:56 +00:00
# $Id$
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
# it under the terms of the GNU 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
# GNU General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
import time
import tools
from osv import fields , osv , orm
import mx . DateTime
2007-04-12 20:08:18 +00:00
import base64
2008-07-08 08:13:12 +00:00
from tools . translate import _
2006-12-07 13:41:40 +00:00
MAX_LEVEL = 15
AVAILABLE_STATES = [
2008-07-22 15:11:28 +00:00
( ' draft ' , ' Draft ' ) ,
( ' open ' , ' Open ' ) ,
( ' cancel ' , ' Cancel ' ) ,
( ' done ' , ' Close ' ) ,
( ' pending ' , ' Pending ' )
2006-12-07 13:41:40 +00:00
]
AVAILABLE_PRIORITIES = [
2008-07-22 15:11:28 +00:00
( ' 5 ' , ' Lowest ' ) ,
( ' 4 ' , ' Low ' ) ,
( ' 3 ' , ' Normal ' ) ,
( ' 2 ' , ' High ' ) ,
( ' 1 ' , ' Highest ' )
2006-12-07 13:41:40 +00:00
]
2007-12-17 20:16:01 +00:00
icon_lst = {
2008-07-22 15:11:28 +00:00
' form ' : ' STOCK_NEW ' ,
' tree ' : ' STOCK_JUSTIFY_FILL ' ,
' calendar ' : ' STOCK_SELECT_COLOR '
2007-12-17 20:16:01 +00:00
}
2006-12-07 13:41:40 +00:00
class crm_case_section ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case.section "
_description = " Case Section "
_columns = {
2008-11-20 16:18:41 +00:00
' name ' : fields . char ( ' Case Section ' , size = 64 , required = True , translate = True ) ,
2008-07-22 15:11:28 +00:00
' code ' : fields . char ( ' Section Code ' , size = 8 ) ,
' active ' : fields . boolean ( ' Active ' ) ,
2009-03-11 08:04:07 +00:00
' allow_unlink ' : fields . boolean ( ' Allow Delete ' , help = " Allows to delete non draft cases " ) ,
2008-07-22 15:11:28 +00:00
' sequence ' : fields . integer ( ' Sequence ' ) ,
2009-01-27 11:15:46 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Responsible User ' ) ,
' reply_to ' : fields . char ( ' Reply-To ' , size = 64 , help = " The email address put in the ' Reply-To ' of all emails sent by Open ERP about cases in this section " ) ,
2008-07-22 15:11:28 +00:00
' parent_id ' : fields . many2one ( ' crm.case.section ' , ' Parent Section ' ) ,
2009-01-27 11:15:46 +00:00
' child_ids ' : fields . one2many ( ' crm.case.section ' , ' parent_id ' , ' Child Sections ' ) ,
2008-07-22 15:11:28 +00:00
}
_defaults = {
' active ' : lambda * a : 1 ,
2009-03-11 08:04:07 +00:00
' allow_unlink ' : lambda * a : 1 ,
2008-07-22 15:11:28 +00:00
}
_sql_constraints = [
( ' code_uniq ' , ' unique (code) ' , ' The code of the section must be unique ! ' )
]
def _check_recursion ( self , cr , uid , ids ) :
level = 100
while len ( ids ) :
cr . execute ( ' select distinct parent_id from crm_case_section where id in ( ' + ' , ' . join ( map ( str , ids ) ) + ' ) ' )
ids = filter ( None , map ( lambda x : x [ 0 ] , cr . fetchall ( ) ) )
if not level :
return False
level - = 1
return True
_constraints = [
2009-02-11 09:35:48 +00:00
( _check_recursion , ' Error ! You cannot create recursive sections. ' , [ ' parent_id ' ] )
2008-07-22 15:11:28 +00:00
]
# Mainly used by the wizard
def menu_create_data ( self , cr , uid , data , menu_lst , context ) :
menus = { }
menus [ 0 ] = data [ ' menu_parent_id ' ]
section = self . browse ( cr , uid , data [ ' section_id ' ] , context )
for ( index , mname , mdomain , latest , view_mode ) in menu_lst :
view_mode = data [ ' menu ' + str ( index ) + ' _option ' ]
if view_mode == ' no ' :
menus [ index ] = data [ ' menu_parent_id ' ]
continue
icon = icon_lst . get ( view_mode . split ( ' , ' ) [ 0 ] , ' STOCK_JUSTIFY_FILL ' )
menu_id = self . pool . get ( ' ir.ui.menu ' ) . create ( cr , uid , {
' name ' : data [ ' menu ' + str ( index ) ] ,
' parent_id ' : menus [ latest ] ,
' icon ' : icon
} )
menus [ index ] = menu_id
action_id = self . pool . get ( ' ir.actions.act_window ' ) . create ( cr , uid , {
' name ' : data [ ' menu ' + str ( index ) ] ,
' res_model ' : ' crm.case ' ,
' domain ' : mdomain . replace ( ' SECTION_ID ' , str ( data [ ' section_id ' ] ) ) ,
' view_type ' : ' form ' ,
' view_mode ' : view_mode ,
} )
seq = 0
for mode in view_mode . split ( ' , ' ) :
self . pool . get ( ' ir.actions.act_window.view ' ) . create ( cr , uid , {
' sequence ' : seq ,
' view_id ' : data [ ' view_ ' + mode ] ,
' view_mode ' : mode ,
' act_window_id ' : action_id ,
' multi ' : True
} )
seq + = 1
self . pool . get ( ' ir.values ' ) . create ( cr , uid , {
' name ' : data [ ' menu ' + str ( index ) ] ,
' key2 ' : ' tree_but_open ' ,
' model ' : ' ir.ui.menu ' ,
' res_id ' : menu_id ,
' value ' : ' ir.actions.act_window, %d ' % action_id ,
' object ' : True
} )
return True
#
# Used when called from .XML file
#
def menu_create ( self , cr , uid , ids , name , menu_parent_id = False , context = { } ) :
menus = { }
menus [ - 1 ] = menu_parent_id
for section in self . browse ( cr , uid , ids , context ) :
for ( index , mname , mdomain , latest ) in [
( 0 , ' ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " )] " , - 1 ) ,
( 1 , ' My ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid)] " , 0 ) ,
( 2 , ' My Unclosed ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' state ' , ' <> ' , ' cancel ' ), ( ' state ' , ' <> ' , ' done ' )] " , 1 ) ,
( 5 , ' My Open ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' state ' , ' = ' , ' open ' )] " , 2 ) ,
( 6 , ' My Pending ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' state ' , ' = ' , ' pending ' )] " , 2 ) ,
( 7 , ' My Draft ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' state ' , ' = ' , ' draft ' )] " , 2 ) ,
( 3 , ' My Late ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' date_deadline ' , ' <= ' ,time.strftime( ' % Y- % m- %d ' )), ( ' state ' , ' <> ' , ' cancel ' ), ( ' state ' , ' <> ' , ' done ' )] " , 1 ) ,
( 4 , ' My Canceled ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' state ' , ' = ' , ' cancel ' )] " , 1 ) ,
( 8 , ' All ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),] " , 0 ) ,
( 9 , ' Unassigned ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,False)] " , 8 ) ,
( 10 , ' Late ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,uid), ( ' date_deadline ' , ' <= ' ,time.strftime( ' % Y- % m- %d ' )), ( ' state ' , ' <> ' , ' cancel ' ), ( ' state ' , ' <> ' , ' done ' )] " , 8 ) ,
( 11 , ' Canceled ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' state ' , ' = ' , ' cancel ' )] " , 8 ) ,
( 12 , ' Unclosed ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' state ' , ' <> ' , ' cancel ' ), ( ' state ' , ' <> ' , ' done ' )] " , 8 ) ,
( 13 , ' Open ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' state ' , ' = ' , ' open ' )] " , 12 ) ,
( 14 , ' Pending ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' state ' , ' = ' , ' pending ' )] " , 12 ) ,
( 15 , ' Draft ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' state ' , ' = ' , ' draft ' )] " , 12 ) ,
( 16 , ' Unassigned ' , " [( ' section_id ' , ' = ' , " + str ( section . id ) + " ),( ' user_id ' , ' = ' ,False),( ' state ' , ' <> ' , ' cancel ' ),( ' state ' , ' <> ' , ' done ' )] " , 12 ) ,
] :
view_mode = ' tree,form '
icon = ' STOCK_JUSTIFY_FILL '
if index == 0 :
view_mode = ' form,tree '
icon = ' STOCK_NEW '
menu_id = self . pool . get ( ' ir.ui.menu ' ) . create ( cr , uid , {
' name ' : mname + name ,
' parent_id ' : menus [ latest ] ,
' icon ' : icon
} )
menus [ index ] = menu_id
action_id = self . pool . get ( ' ir.actions.act_window ' ) . create ( cr , uid , {
' name ' : mname + name + ' Cases ' ,
' res_model ' : ' crm.case ' ,
' domain ' : mdomain ,
' view_type ' : ' form ' ,
' view_mode ' : view_mode ,
} )
self . pool . get ( ' ir.values ' ) . create ( cr , uid , {
' name ' : ' Open Cases ' ,
' key2 ' : ' tree_but_open ' ,
' model ' : ' ir.ui.menu ' ,
' res_id ' : menu_id ,
' value ' : ' ir.actions.act_window, %d ' % action_id ,
' object ' : True
} )
return True
2009-02-04 09:46:57 +00:00
2008-07-22 15:11:28 +00:00
def name_get ( self , cr , uid , ids , context = { } ) :
if not len ( ids ) :
return [ ]
reads = self . read ( cr , uid , ids , [ ' name ' , ' parent_id ' ] , context )
res = [ ]
for record in reads :
name = record [ ' name ' ]
if record [ ' parent_id ' ] :
name = record [ ' parent_id ' ] [ 1 ] + ' / ' + name
res . append ( ( record [ ' id ' ] , name ) )
return res
2006-12-07 13:41:40 +00:00
crm_case_section ( )
class crm_case_categ ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case.categ "
_description = " Category of case "
_columns = {
2008-11-20 16:18:41 +00:00
' name ' : fields . char ( ' Case Category Name ' , size = 64 , required = True , translate = True ) ,
2008-10-31 14:09:59 +00:00
' probability ' : fields . float ( ' Probability ( % ) ' , required = True ) ,
2008-07-22 15:11:28 +00:00
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Case Section ' ) ,
}
_defaults = {
' probability ' : lambda * args : 0.0
}
2006-12-07 13:41:40 +00:00
crm_case_categ ( )
class crm_case_rule ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case.rule "
_description = " Case Rule "
_columns = {
' name ' : fields . char ( ' Rule Name ' , size = 64 , required = True ) ,
' active ' : fields . boolean ( ' Active ' ) ,
' sequence ' : fields . integer ( ' Sequence ' ) ,
2008-10-29 13:34:45 +00:00
' trg_state_from ' : fields . selection ( [ ( ' ' , ' ' ) , ( ' escalate ' , ' Escalate ' ) ] + AVAILABLE_STATES , ' Case State ' , size = 16 ) ,
' trg_state_to ' : fields . selection ( [ ( ' ' , ' ' ) , ( ' escalate ' , ' Escalate ' ) ] + AVAILABLE_STATES , ' Button Pressed ' , size = 16 ) ,
2008-07-22 15:11:28 +00:00
' trg_date_type ' : fields . selection ( [
( ' none ' , ' None ' ) ,
( ' create ' , ' Creation Date ' ) ,
( ' action_last ' , ' Last Action Date ' ) ,
( ' deadline ' , ' Deadline ' ) ,
2008-12-08 17:08:40 +00:00
( ' date ' , ' Date ' ) ,
2008-07-22 15:11:28 +00:00
] , ' Trigger Date ' , size = 16 ) ,
' trg_date_range ' : fields . integer ( ' Delay after trigger date ' ) ,
' trg_date_range_type ' : fields . selection ( [ ( ' minutes ' , ' Minutes ' ) , ( ' hour ' , ' Hours ' ) , ( ' day ' , ' Days ' ) , ( ' month ' , ' Months ' ) ] , ' Delay type ' ) ,
' trg_section_id ' : fields . many2one ( ' crm.case.section ' , ' Section ' ) ,
' trg_categ_id ' : fields . many2one ( ' crm.case.categ ' , ' Category ' , domain = " [( ' section_id ' , ' = ' ,trg_section_id)] " ) ,
' trg_user_id ' : fields . many2one ( ' res.users ' , ' Responsible ' ) ,
' trg_partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' ) ,
' trg_partner_categ_id ' : fields . many2one ( ' res.partner.category ' , ' Partner Category ' ) ,
2008-10-29 13:34:45 +00:00
' trg_priority_from ' : fields . selection ( [ ( ' ' , ' ' ) ] + AVAILABLE_PRIORITIES , ' Minimum Priority ' ) ,
' trg_priority_to ' : fields . selection ( [ ( ' ' , ' ' ) ] + AVAILABLE_PRIORITIES , ' Maximim Priority ' ) ,
2008-07-22 15:11:28 +00:00
' act_method ' : fields . char ( ' Call Object Method ' , size = 64 ) ,
' act_state ' : fields . selection ( [ ( ' ' , ' ' ) ] + AVAILABLE_STATES , ' Set state to ' , size = 16 ) ,
' act_section_id ' : fields . many2one ( ' crm.case.section ' , ' Set section to ' ) ,
' act_user_id ' : fields . many2one ( ' res.users ' , ' Set responsible to ' ) ,
' act_priority ' : fields . selection ( [ ( ' ' , ' ' ) ] + AVAILABLE_PRIORITIES , ' Set priority to ' ) ,
2008-10-29 13:34:45 +00:00
' act_email_cc ' : fields . char ( ' Add watchers (Cc) ' , size = 250 , help = " These people will receive a copy of the futur communication between partner and users by email " ) ,
2008-07-22 15:11:28 +00:00
2008-10-29 13:34:45 +00:00
' act_remind_partner ' : fields . boolean ( ' Remind Partner ' , help = " Check this if you want the rule to send a reminder by email to the partner. " ) ,
' act_remind_user ' : fields . boolean ( ' Remind responsible ' , help = " Check this if you want the rule to send a reminder by email to the user. " ) ,
' act_remind_attach ' : fields . boolean ( ' Remind with attachment ' , help = " Check this if you want that all documents attached to the case be attached to the reminder email sent. " ) ,
2008-07-22 15:11:28 +00:00
' act_mail_to_user ' : fields . boolean ( ' Mail to responsible ' ) ,
' act_mail_to_partner ' : fields . boolean ( ' Mail to partner ' ) ,
' act_mail_to_watchers ' : fields . boolean ( ' Mail to watchers (Cc) ' ) ,
' act_mail_to_email ' : fields . char ( ' Mail to these emails ' , size = 128 ) ,
' act_mail_body ' : fields . text ( ' Mail body ' )
}
_defaults = {
' active ' : lambda * a : 1 ,
' trg_date_type ' : lambda * a : ' none ' ,
' trg_date_range_type ' : lambda * a : ' day ' ,
' act_mail_to_user ' : lambda * a : 0 ,
' act_remind_partner ' : lambda * a : 0 ,
' act_remind_user ' : lambda * a : 0 ,
' act_mail_to_partner ' : lambda * a : 0 ,
' act_mail_to_watchers ' : lambda * a : 0 ,
}
_order = ' sequence '
def _check ( self , cr , uid , ids = False , context = { } ) :
'''
Function called by the sceduler to proccess cases for date actions
Only works on not done and canceled cases
'''
cr . execute ( ' select * from crm_case \
where ( date_action_last < % s or date_action_last is null ) \
and ( date_action_next < = % s or date_action_next is null ) \
and state not in ( \' cancel \' , \' done \' ) ' ,
( time . strftime ( " % Y- % m- %d % H: % M: % S " ) ,
time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) )
ids2 = map ( lambda x : x [ 0 ] , cr . fetchall ( ) or [ ] )
case_obj = self . pool . get ( ' crm.case ' )
cases = case_obj . browse ( cr , uid , ids2 , context )
return case_obj . _action ( cr , uid , cases , False , context = context )
2008-10-27 14:01:29 +00:00
def _check_mail ( self , cr , uid , ids , context = None ) :
caseobj = self . pool . get ( ' crm.case ' )
emptycase = orm . browse_null ( )
for rule in self . browse ( cr , uid , ids ) :
if rule . act_mail_body :
try :
caseobj . format_mail ( emptycase , rule . act_mail_body )
except ( ValueError , KeyError , TypeError ) :
return False
return True
2009-02-04 09:46:57 +00:00
2008-10-27 14:01:29 +00:00
_constraints = [
( _check_mail , ' Error: The mail is not well formated ' , [ ' act_mail_body ' ] ) ,
]
2006-12-07 13:41:40 +00:00
crm_case_rule ( )
def _links_get ( self , cr , uid , context = { } ) :
2008-07-22 15:11:28 +00:00
obj = self . pool . get ( ' res.request.link ' )
ids = obj . search ( cr , uid , [ ] )
res = obj . read ( cr , uid , ids , [ ' object ' , ' name ' ] , context )
return [ ( r [ ' object ' ] , r [ ' name ' ] ) for r in res ]
2006-12-07 13:41:40 +00:00
class crm_case ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case "
_description = " Case "
def _email_last ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for case in self . browse ( cursor , user , ids ) :
if case . history_line :
res [ case . id ] = case . history_line [ 0 ] . description
else :
res [ case . id ] = False
return res
def copy ( self , cr , uid , id , default = None , context = { } ) :
if not default : default = { }
2008-12-04 07:38:03 +00:00
default . update ( { ' state ' : ' draft ' , ' id ' : False , ' history_line ' : [ ] , ' log_ids ' : [ ] } )
2008-07-22 15:11:28 +00:00
return super ( crm_case , self ) . copy ( cr , uid , id , default , context )
_columns = {
2008-12-04 07:38:03 +00:00
' id ' : fields . integer ( ' ID ' , readonly = True ) ,
2009-03-09 07:13:23 +00:00
' name ' : fields . char ( ' Description ' , size = 64 , required = True ) ,
2008-07-22 15:11:28 +00:00
' priority ' : fields . selection ( AVAILABLE_PRIORITIES , ' Priority ' ) ,
' active ' : fields . boolean ( ' Active ' ) ,
' description ' : fields . text ( ' Your action ' ) ,
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Section ' , required = True , select = True ) ,
' categ_id ' : fields . many2one ( ' crm.case.categ ' , ' Category ' , domain = " [( ' section_id ' , ' = ' ,section_id)] " ) ,
' planned_revenue ' : fields . float ( ' Planned Revenue ' ) ,
' planned_cost ' : fields . float ( ' Planned Costs ' ) ,
2008-10-31 14:09:59 +00:00
' probability ' : fields . float ( ' Probability ( % ) ' ) ,
2008-07-22 15:11:28 +00:00
' email_from ' : fields . char ( ' Partner Email ' , size = 128 ) ,
' email_cc ' : fields . char ( ' Watchers Emails ' , size = 252 ) ,
' email_last ' : fields . function ( _email_last , method = True ,
string = ' Latest E-Mail ' , type = ' text ' ) ,
' partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' ) ,
' partner_address_id ' : fields . many2one ( ' res.partner.address ' , ' Partner Contact ' , domain = " [( ' partner_id ' , ' = ' ,partner_id)] " ) ,
' som ' : fields . many2one ( ' res.partner.som ' , ' State of Mind ' ) ,
' date ' : fields . datetime ( ' Date ' ) ,
2008-12-04 07:38:03 +00:00
' create_date ' : fields . datetime ( ' Created ' , readonly = True ) ,
2008-07-22 15:11:28 +00:00
' date_deadline ' : fields . datetime ( ' Deadline ' ) ,
' date_closed ' : fields . datetime ( ' Closed ' , readonly = True ) ,
' canal_id ' : fields . many2one ( ' res.partner.canal ' , ' Channel ' ) ,
2008-10-31 14:09:59 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Responsible ' ) ,
2008-11-07 00:01:52 +00:00
' history_line ' : fields . one2many ( ' crm.case.history ' , ' case_id ' , ' Communication ' , readonly = 1 ) ,
' log_ids ' : fields . one2many ( ' crm.case.log ' , ' case_id ' , ' Logs History ' , readonly = 1 ) ,
2008-08-28 23:08:10 +00:00
' state ' : fields . selection ( AVAILABLE_STATES , ' Status ' , size = 16 , readonly = True ) ,
2008-07-22 15:11:28 +00:00
' ref ' : fields . reference ( ' Reference ' , selection = _links_get , size = 128 ) ,
' ref2 ' : fields . reference ( ' Reference 2 ' , selection = _links_get , size = 128 ) ,
' date_action_last ' : fields . datetime ( ' Last Action ' , readonly = 1 ) ,
' date_action_next ' : fields . datetime ( ' Next Action ' , readonly = 1 ) ,
}
def _get_default_partner_address ( self , cr , uid , context ) :
if not context . get ( ' portal ' , False ) :
return False
return self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context ) . address_id . id
def _get_default_partner ( self , cr , uid , context ) :
if not context . get ( ' portal ' , False ) :
return False
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context )
if not user . address_id :
return False
return user . address_id . partner_id . id
def _get_default_email ( self , cr , uid , context ) :
if not context . get ( ' portal ' , False ) :
return False
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context )
if not user . address_id :
return False
return user . address_id . email
def _get_default_user ( self , cr , uid , context ) :
if context . get ( ' portal ' , False ) :
return False
return uid
_defaults = {
' active ' : lambda * a : 1 ,
' user_id ' : _get_default_user ,
' partner_id ' : _get_default_partner ,
' partner_address_id ' : _get_default_partner_address ,
' email_from ' : _get_default_email ,
2008-10-31 14:09:59 +00:00
' state ' : lambda * a : ' open ' ,
2008-07-22 15:11:28 +00:00
' priority ' : lambda * a : AVAILABLE_PRIORITIES [ 2 ] [ 0 ] ,
2009-03-11 13:34:51 +00:00
' date ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
2008-07-22 15:11:28 +00:00
}
2008-08-19 13:28:54 +00:00
_order = ' priority, date_deadline desc, date desc,id desc '
2008-07-22 15:11:28 +00:00
2008-10-31 15:30:22 +00:00
def unlink ( self , cr , uid , ids , context = { } ) :
for case in self . browse ( cr , uid , ids , context ) :
2009-03-11 08:04:07 +00:00
if ( not case . section_id . allow_unlink ) and ( case . state < > ' draft ' ) :
2008-10-31 15:30:22 +00:00
raise osv . except_osv ( _ ( ' Warning ! ' ) ,
_ ( ' You can not delete this case. You should better cancel it. ' ) )
return super ( crm_case , self ) . unlink ( cr , uid , ids , context )
2008-07-22 15:11:28 +00:00
def _action ( self , cr , uid , cases , state_to , scrit = None , context = { } ) :
if not scrit :
scrit = [ ]
action_ids = self . pool . get ( ' crm.case.rule ' ) . search ( cr , uid , scrit )
level = MAX_LEVEL
while len ( action_ids ) and level :
newactions = [ ]
actions = self . pool . get ( ' crm.case.rule ' ) . browse ( cr , uid , action_ids , context )
for case in cases :
for action in actions :
ok = True
ok = ok and ( not action . trg_state_from or action . trg_state_from == case . state )
ok = ok and ( not action . trg_state_to or action . trg_state_to == state_to )
ok = ok and ( not action . trg_section_id or action . trg_section_id . id == case . section_id . id )
ok = ok and ( not action . trg_categ_id or action . trg_categ_id . id == case . categ_id . id )
ok = ok and ( not action . trg_user_id . id or action . trg_user_id . id == case . user_id . id )
ok = ok and ( not action . trg_partner_id . id or action . trg_partner_id . id == case . partner_id . id )
ok = ok and (
not action . trg_partner_categ_id . id or
(
case . partner_id . id and
( action . trg_partner_categ_id . id in map ( lambda x : x . id , case . partner_id . category_id or [ ] ) )
)
)
ok = ok and ( not action . trg_priority_from or action . trg_priority_from > = case . priority )
ok = ok and ( not action . trg_priority_to or action . trg_priority_to < = case . priority )
if not ok :
continue
base = False
if action . trg_date_type == ' create ' :
base = mx . DateTime . strptime ( case . create_date [ : 19 ] , ' % Y- % m- %d % H: % M: % S ' )
elif action . trg_date_type == ' action_last ' :
if case . date_action_last :
base = mx . DateTime . strptime ( case . date_action_last , ' % Y- % m- %d % H: % M: % S ' )
else :
base = mx . DateTime . strptime ( case . create_date [ : 19 ] , ' % Y- % m- %d % H: % M: % S ' )
elif action . trg_date_type == ' deadline ' and case . date_deadline :
2009-03-05 12:24:31 +00:00
base = mx . DateTime . strptime ( case . date_deadline , ' % Y- % m- %d % H: % M: % S ' )
2008-12-08 17:08:40 +00:00
elif action . trg_date_type == ' date ' and case . date :
2009-03-05 12:24:31 +00:00
base = mx . DateTime . strptime ( case . date , ' % Y- % m- %d % H: % M: % S ' )
2008-07-22 15:11:28 +00:00
if base :
fnct = {
' minutes ' : lambda interval : mx . DateTime . RelativeDateTime ( minutes = interval ) ,
' day ' : lambda interval : mx . DateTime . RelativeDateTime ( days = interval ) ,
' hour ' : lambda interval : mx . DateTime . RelativeDateTime ( hours = interval ) ,
' month ' : lambda interval : mx . DateTime . RelativeDateTime ( months = interval ) ,
}
d = base + fnct [ action . trg_date_range_type ] ( action . trg_date_range )
dt = d . strftime ( ' % Y- % m- %d % H: % M: % S ' )
ok = ( dt < = time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) and \
( ( not case . date_action_next ) or \
( dt > = case . date_action_next and \
case . date_action_last < case . date_action_next ) )
if not ok :
if not case . date_action_next or dt < case . date_action_next :
case . date_action_next = dt
self . write ( cr , uid , [ case . id ] , { ' date_action_next ' : dt } , context )
else :
ok = action . trg_date_type == ' none '
if ok :
write = { }
if action . act_state :
case . state = action . act_state
write [ ' state ' ] = action . act_state
if action . act_section_id :
case . section_id = action . act_section_id
write [ ' section_id ' ] = action . act_section_id . id
if action . act_user_id :
case . user_id = action . act_user_id
write [ ' user_id ' ] = action . act_user_id . id
if action . act_priority :
case . priority = action . act_priority
write [ ' priority ' ] = action . act_priority
if action . act_email_cc :
if ' @ ' in ( case . email_cc or ' ' ) :
write [ ' email_cc ' ] = case . email_cc + ' , ' + action . act_email_cc
else :
write [ ' email_cc ' ] = action . act_email_cc
write [ ' date_action_last ' ] = time . strftime ( ' % Y- % m- %d % H: % M: % S ' )
self . write ( cr , uid , [ case . id ] , write , context )
caseobj = self . pool . get ( ' crm.case ' )
if action . act_remind_user :
caseobj . remind_user ( cr , uid , [ case . id ] , context , attach = action . act_remind_attach )
if action . act_remind_partner :
caseobj . remind_partner ( cr , uid , [ case . id ] , context , attach = action . act_remind_attach )
if action . act_method :
getattr ( caseobj , ' act_method ' ) ( cr , uid , [ case . id ] , action , context )
emails = [ ]
if action . act_mail_to_user :
if case . user_id and case . user_id . address_id :
emails . append ( case . user_id . address_id . email )
if action . act_mail_to_partner :
emails . append ( case . email_from )
if action . act_mail_to_watchers :
emails + = ( case . email_cc or ' ' ) . split ( ' , ' )
if action . act_mail_to_email :
emails + = ( action . act_mail_to_email or ' ' ) . split ( ' , ' )
emails = filter ( None , emails )
if len ( emails ) and action . act_mail_body :
self . email_send ( cr , uid , case , emails , action . act_mail_body )
break
action_ids = newactions
level - = 1
return True
2009-02-04 09:46:57 +00:00
2009-01-29 16:55:34 +00:00
def format_body ( self , body ) :
return tools . ustr ( body . encode ( ' ascii ' , ' replace ' ) )
2008-07-22 15:11:28 +00:00
2008-10-27 14:01:29 +00:00
def format_mail ( self , case , body ) :
2008-07-22 15:11:28 +00:00
data = {
' case_id ' : case . id ,
' case_subject ' : case . name ,
' case_date ' : case . date ,
2008-10-27 13:05:17 +00:00
' case_user ' : ( case . user_id and case . user_id . name ) or ' / ' ,
2008-07-22 15:11:28 +00:00
' case_user_email ' : ( case . user_id and case . user_id . address_id and case . user_id . address_id . email ) or ' / ' ,
' case_user_phone ' : ( case . user_id and case . user_id . address_id and case . user_id . address_id . phone ) or ' / ' ,
' email_from ' : case . email_from ,
' partner ' : ( case . partner_id and case . partner_id . name ) or ' / ' ,
' partner_email ' : ( case . partner_address_id and case . partner_address_id . email ) or ' / ' ,
}
2009-01-29 16:55:34 +00:00
return self . format_body ( body ) % data
2008-10-27 14:01:29 +00:00
def email_send ( self , cr , uid , case , emails , body , context = { } ) :
body = self . format_mail ( case , body )
2008-07-22 15:11:28 +00:00
if case . user_id and case . user_id . address_id and case . user_id . address_id . email :
emailfrom = case . user_id . address_id . email
else :
emailfrom = case . section_id . reply_to
tools . email_send ( emailfrom , emails , ' [ ' + str ( case . id ) + ' ] ' + case . name , body , reply_to = case . section_id . reply_to , tinycrm = str ( case . id ) )
return True
def __log ( self , cr , uid , cases , keyword , context = { } ) :
if not self . pool . get ( ' res.partner.event.type ' ) . check ( cr , uid , ' crm_case_ ' + keyword ) :
return False
for case in cases :
if case . partner_id :
2008-12-08 17:08:40 +00:00
translated_keyword = keyword
if ' translated_keyword ' in context :
translated_keyword = context [ ' translated_keyword ' ]
name = _ ( ' Case ' ) + ' ' + translated_keyword + ' : ' + case . name
2008-07-22 15:11:28 +00:00
if isinstance ( name , str ) :
name = unicode ( name , ' utf-8 ' )
if len ( name ) > 64 :
name = name [ : 61 ] + ' ... '
self . pool . get ( ' res.partner.event ' ) . create ( cr , uid , {
' name ' : name ,
' som ' : ( case . som or False ) and case . som . id ,
' description ' : case . description ,
' partner_id ' : case . partner_id . id ,
' date ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
' canal_id ' : ( case . canal_id or False ) and case . canal_id . id ,
' user_id ' : uid ,
' document ' : ' crm.case, %i ' % case . id ,
} )
return True
def __history ( self , cr , uid , cases , keyword , history = False , email = False , context = { } ) :
for case in cases :
data = {
' name ' : keyword ,
' som ' : case . som . id ,
' canal_id ' : case . canal_id . id ,
' user_id ' : uid ,
2009-01-12 10:42:43 +00:00
' date ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
2008-10-31 14:09:59 +00:00
' case_id ' : case . id ,
' section_id ' : case . section_id . id
2008-07-22 15:11:28 +00:00
}
obj = self . pool . get ( ' crm.case.log ' )
if history and case . description :
obj = self . pool . get ( ' crm.case.history ' )
data [ ' description ' ] = case . description
data [ ' email ' ] = email or \
( case . user_id and case . user_id . address_id and \
case . user_id . address_id . email ) or False
obj . create ( cr , uid , data , context )
return True
2008-11-02 15:49:28 +00:00
_history = __history
2008-07-22 15:11:28 +00:00
def create ( self , cr , uid , * args , * * argv ) :
res = super ( crm_case , self ) . create ( cr , uid , * args , * * argv )
cases = self . browse ( cr , uid , [ res ] )
cases [ 0 ] . state # to fill the browse record cache
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' draft ' , context = { ' translated_keyword ' : _ ( ' draft ' ) } )
2008-07-22 15:11:28 +00:00
self . _action ( cr , uid , cases , ' draft ' )
return res
def remind_partner ( self , cr , uid , ids , context = { } , attach = False ) :
return self . remind_user ( cr , uid , ids , context , attach ,
destination = False )
def remind_user ( self , cr , uid , ids , context = { } , attach = False ,
destination = True ) :
for case in self . browse ( cr , uid , ids ) :
2008-10-06 15:30:37 +00:00
if case . section_id . reply_to and case . email_from :
2008-07-22 15:11:28 +00:00
src = case . email_from
2008-10-06 15:30:37 +00:00
dest = case . section_id . reply_to
2008-07-22 15:11:28 +00:00
body = case . email_last or case . description
if not destination :
src , dest = dest , src
if case . user_id . signature :
body + = ' \n \n %s ' % ( case . user_id . signature )
dest = [ dest ]
2008-11-24 11:15:30 +00:00
attach_to_send = None
if attach :
attach_ids = self . pool . get ( ' ir.attachment ' ) . search ( cr , uid , [ ( ' res_model ' , ' = ' , ' crm.case ' ) , ( ' res_id ' , ' = ' , case . id ) ] )
attach_to_send = self . pool . get ( ' ir.attachment ' ) . read ( cr , uid , attach_ids , [ ' datas_fname ' , ' datas ' ] )
attach_to_send = map ( lambda x : ( x [ ' datas_fname ' ] , base64 . decodestring ( x [ ' datas ' ] ) ) , attach_to_send )
# Send an email
tools . email_send (
2009-02-04 09:46:57 +00:00
src ,
dest ,
2008-11-24 11:15:30 +00:00
" Reminder: [ %s ] %s " % ( str ( case . id ) , case . name , ) ,
2009-01-29 16:55:34 +00:00
self . format_body ( body ) ,
2009-02-04 09:46:57 +00:00
reply_to = case . section_id . reply_to ,
2008-11-24 11:15:30 +00:00
tinycrm = str ( case . id ) ,
attach = attach_to_send
)
2008-07-22 15:11:28 +00:00
return True
def add_reply ( self , cursor , user , ids , context = None ) :
for case in self . browse ( cursor , user , ids , context = context ) :
if case . history_line :
description = case . history_line [ 0 ] . description
self . write ( cursor , user , case . id , {
' description ' : ' > ' + description . replace ( ' \n ' , ' \n > ' ) ,
} , context = context )
return True
def case_log ( self , cr , uid , ids , context = { } , email = False , * args ) :
cases = self . browse ( cr , uid , ids )
2008-12-08 17:08:40 +00:00
self . __history ( cr , uid , cases , _ ( ' Historize ' ) , history = True , email = email )
2008-07-22 15:11:28 +00:00
return self . write ( cr , uid , ids , { ' description ' : False , ' som ' : False ,
' canal_id ' : False } )
def case_log_reply ( self , cr , uid , ids , context = { } , email = False , * args ) :
cases = self . browse ( cr , uid , ids )
for case in cases :
if not case . email_from :
raise osv . except_osv ( _ ( ' Error! ' ) ,
_ ( ' You must put a Partner eMail to use this action! ' ) )
2009-02-04 09:46:57 +00:00
if not case . description :
raise osv . except_osv ( _ ( ' Error! ' ) ,
_ ( ' Can not send mail with empty body,you should have description in the body ' ) )
2008-12-08 17:08:40 +00:00
self . __history ( cr , uid , cases , _ ( ' Send ' ) , history = True , email = False )
2008-07-22 15:11:28 +00:00
for case in cases :
self . write ( cr , uid , [ case . id ] , {
' description ' : False ,
' som ' : False ,
' canal_id ' : False ,
} )
emails = [ case . email_from ] + ( case . email_cc or ' ' ) . split ( ' , ' )
emails = filter ( None , emails )
2009-02-04 09:38:58 +00:00
body = case . description or ' '
2008-07-22 15:11:28 +00:00
if case . user_id . signature :
body + = ' \n \n %s ' % ( case . user_id . signature )
2008-11-24 11:15:30 +00:00
tools . email_send (
2009-02-04 09:46:57 +00:00
case . user_id . address_id . email ,
2008-11-24 11:15:30 +00:00
emails ,
2009-02-04 09:46:57 +00:00
' [ ' + str ( case . id ) + ' ] ' + case . name ,
2009-01-29 16:55:34 +00:00
self . format_body ( body ) ,
2009-02-04 09:46:57 +00:00
reply_to = case . section_id . reply_to ,
2008-11-24 11:15:30 +00:00
tinycrm = str ( case . id )
)
2008-07-22 15:11:28 +00:00
return True
def onchange_partner_id ( self , cr , uid , ids , part , email = False ) :
if not part :
return { ' value ' : { ' partner_address_id ' : False } }
addr = self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ part ] , [ ' contact ' ] )
data = { ' partner_address_id ' : addr [ ' contact ' ] }
if addr [ ' contact ' ] and not email :
data [ ' email_from ' ] = self . pool . get ( ' res.partner.address ' ) . browse ( cr , uid , addr [ ' contact ' ] ) . email
return { ' value ' : data }
def onchange_categ_id ( self , cr , uid , ids , categ , context = { } ) :
if not categ :
return { ' value ' : { } }
cat = self . pool . get ( ' crm.case.categ ' ) . browse ( cr , uid , categ , context ) . probability
return { ' value ' : { ' probability ' : cat } }
def onchange_partner_address_id ( self , cr , uid , ids , part , email = False ) :
if not part :
return { ' value ' : { } }
data = { }
if not email :
data [ ' email_from ' ] = self . pool . get ( ' res.partner.address ' ) . browse ( cr , uid , part ) . email
return { ' value ' : data }
def case_close ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
cases [ 0 ] . state # to fill the browse record cache
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' done ' , context = { ' translated_keyword ' : _ ( ' done ' ) } )
self . __history ( cr , uid , cases , _ ( ' Close ' ) )
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' done ' , ' date_closed ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) } )
#
# We use the cache of cases to keep the old case state
#
self . _action ( cr , uid , cases , ' done ' )
return True
def case_escalate ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
for case in cases :
data = { ' active ' : True , ' user_id ' : False }
if case . section_id . parent_id :
data [ ' section_id ' ] = case . section_id . parent_id . id
if case . section_id . parent_id . user_id :
data [ ' user_id ' ] = case . section_id . parent_id . user_id . id
else :
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( ' You can not escalate this case. \n You are already at the top level. ' ) )
self . write ( cr , uid , ids , data )
2008-12-08 17:08:40 +00:00
self . __history ( cr , uid , cases , _ ( ' Escalate ' ) )
2008-07-22 15:11:28 +00:00
self . _action ( cr , uid , cases , ' escalate ' )
return True
def case_open ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' open ' , context = { ' translated_keyword ' : _ ( ' open ' ) } )
self . __history ( cr , uid , cases , _ ( ' Open ' ) )
2008-07-22 15:11:28 +00:00
for case in cases :
data = { ' state ' : ' open ' , ' active ' : True }
if not case . user_id :
data [ ' user_id ' ] = uid
self . write ( cr , uid , ids , data )
self . _action ( cr , uid , cases , ' open ' )
return True
def emails_get ( self , cr , uid , id , context = { } ) :
case = self . browse ( cr , uid , id )
return ( ( case . user_id and case . user_id . address_id and case . user_id . address_id . email ) or False , case . email_from , case . email_cc , case . priority )
def case_cancel ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
cases [ 0 ] . state # to fill the browse record cache
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' cancel ' , context = { ' translated_keyword ' : _ ( ' cancel ' ) } )
self . __history ( cr , uid , cases , _ ( ' Cancel ' ) )
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' , ' active ' : True } )
self . _action ( cr , uid , cases , ' cancel ' )
return True
def case_pending ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
cases [ 0 ] . state # to fill the browse record cache
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' pending ' , context = { ' translated_keyword ' : _ ( ' draft ' ) } )
self . __history ( cr , uid , cases , _ ( ' Pending ' ) )
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' pending ' , ' active ' : True } )
self . _action ( cr , uid , cases , ' pending ' )
return True
def case_reset ( self , cr , uid , ids , * args ) :
cases = self . browse ( cr , uid , ids )
cases [ 0 ] . state # to fill the browse record cache
2008-12-08 17:08:40 +00:00
self . __log ( cr , uid , cases , ' draft ' , context = { ' translated_keyword ' : _ ( ' draft ' ) } )
self . __history ( cr , uid , cases , _ ( ' Draft ' ) )
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' draft ' , ' active ' : True } )
self . _action ( cr , uid , cases , ' draft ' )
return True
2006-12-07 13:41:40 +00:00
crm_case ( )
2007-06-18 07:30:01 +00:00
class crm_case_log ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case.log "
2008-10-31 14:09:59 +00:00
_description = " Case Communication History "
2008-07-22 15:11:28 +00:00
_order = " id desc "
_columns = {
' name ' : fields . char ( ' Action ' , size = 64 ) ,
' som ' : fields . many2one ( ' res.partner.som ' , ' State of Mind ' ) ,
' date ' : fields . datetime ( ' Date ' ) ,
' canal_id ' : fields . many2one ( ' res.partner.canal ' , ' Channel ' ) ,
2008-10-31 14:09:59 +00:00
' section_id ' : fields . many2one ( ' crm.case.section ' , ' Section ' ) ,
2008-07-22 15:11:28 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' User Responsible ' , readonly = True ) ,
' case_id ' : fields . many2one ( ' crm.case ' , ' Case ' , required = True , ondelete = ' cascade ' )
}
_defaults = {
' date ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
}
2007-06-18 07:30:01 +00:00
crm_case_log ( )
class crm_case_history ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " crm.case.history "
_description = " Case history "
_order = " id desc "
_inherits = { ' crm.case.log ' : " log_id " }
def _note_get ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for hist in self . browse ( cursor , user , ids , context or { } ) :
res [ hist . id ] = ( hist . email or ' / ' ) + ' ( ' + str ( hist . date ) + ' ) \n '
res [ hist . id ] + = ( hist . description or ' ' )
return res
_columns = {
' description ' : fields . text ( ' Description ' ) ,
' note ' : fields . function ( _note_get , method = True , string = " Description " , type = " text " ) ,
' email ' : fields . char ( ' Email ' , size = 84 ) ,
' log_id ' : fields . many2one ( ' crm.case.log ' , ' Log ' , ondelete = ' cascade ' ) ,
}
2006-12-07 13:41:40 +00:00
crm_case_history ( )
2008-07-23 14:41:47 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: