2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2008-08-24 14:45:43 +00:00
##############################################################################
2009-11-26 12:30:42 +00:00
#
2008-11-18 10:56:11 +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-08-24 14:45:43 +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-08-24 14:45:43 +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-08-24 14:45:43 +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-26 12:30:42 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2008-08-24 14:45:43 +00:00
#
##############################################################################
2014-07-06 14:44:26 +00:00
from datetime import timedelta
2014-05-30 14:00:28 +00:00
import pytz
2011-09-07 17:25:00 +00:00
2014-07-06 14:44:26 +00:00
from openerp import models , fields , api , _
2015-11-09 09:38:19 +00:00
from openerp . exceptions import AccessError , Warning
2014-07-06 14:44:26 +00:00
class event_type ( models . Model ) :
2010-07-16 06:47:14 +00:00
""" Event Type """
2008-08-24 14:45:43 +00:00
_name = ' event.type '
2014-10-01 08:45:59 +00:00
_description = ' Event Type '
2014-07-06 14:44:26 +00:00
name = fields . Char ( string = ' Event Type ' , required = True )
default_reply_to = fields . Char ( string = ' Default Reply-To ' ,
help = " The email address of the organizer which is put in the ' Reply-To ' of all emails sent automatically at event or registrations confirmation. You can also put your email address of your mail gateway if you use one. " )
default_email_event = fields . Many2one ( ' email.template ' , string = ' Event Confirmation Email ' ,
help = " It will select this default confirmation event mail value when you choose this event " )
default_email_registration = fields . Many2one ( ' email.template ' , string = ' Registration Confirmation Email ' ,
help = " It will select this default confirmation registration mail value when you choose this event " )
default_registration_min = fields . Integer ( string = ' Default Minimum Registration ' , default = 0 ,
help = " It will select this default minimum value when you choose this event " )
default_registration_max = fields . Integer ( string = ' Default Maximum Registration ' , default = 0 ,
help = " It will select this default maximum value when you choose this event " )
class event_event ( models . Model ) :
2010-07-16 06:47:14 +00:00
""" Event """
2008-08-24 14:45:43 +00:00
_name = ' event.event '
2014-09-29 11:15:35 +00:00
_description = ' Event '
2012-12-20 10:00:05 +00:00
_inherit = [ ' mail.thread ' , ' ir.needaction_mixin ' ]
2014-07-06 14:44:26 +00:00
_order = ' date_begin '
2010-07-16 06:47:14 +00:00
2014-07-06 14:44:26 +00:00
name = fields . Char ( string = ' Event Name ' , translate = True , required = True ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
user_id = fields . Many2one ( ' res.users ' , string = ' Responsible User ' ,
default = lambda self : self . env . user ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
type = fields . Many2one ( ' event.type ' , string = ' Type of Event ' ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
2014-07-10 20:49:53 +00:00
seats_max = fields . Integer ( string = ' Maximum Available Seats ' , oldname = ' register_max ' ,
2014-07-06 14:44:26 +00:00
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " You can for each event define a maximum registration level. If you have too much registrations you are not able to confirm your event. (put 0 to ignore this rule ) " )
seats_min = fields . Integer ( string = ' Minimum Reserved Seats ' , oldname = ' register_min ' ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
help = " You can for each event define a minimum registration level. If you do not enough registrations you are not able to confirm your event. (put 0 to ignore this rule ) " )
seats_reserved = fields . Integer ( oldname = ' register_current ' , string = ' Reserved Seats ' ,
store = True , readonly = True , compute = ' _compute_seats ' )
seats_available = fields . Integer ( oldname = ' register_avail ' , string = ' Available Seats ' ,
store = True , readonly = True , compute = ' _compute_seats ' )
seats_unconfirmed = fields . Integer ( oldname = ' register_prospect ' , string = ' Unconfirmed Seat Reservations ' ,
store = True , readonly = True , compute = ' _compute_seats ' )
seats_used = fields . Integer ( oldname = ' register_attended ' , string = ' Number of Participations ' ,
store = True , readonly = True , compute = ' _compute_seats ' )
@api.multi
@api.depends ( ' seats_max ' , ' registration_ids.state ' , ' registration_ids.nb_register ' )
def _compute_seats ( self ) :
""" Determine reserved, available, reserved but unconfirmed and used seats. """
# initialize fields to 0
for event in self :
event . seats_unconfirmed = event . seats_reserved = event . seats_used = 0
# aggregate registrations by event and by state
if self . ids :
state_field = {
' draft ' : ' seats_unconfirmed ' ,
' open ' : ' seats_reserved ' ,
' done ' : ' seats_used ' ,
}
query = """ SELECT event_id, state, sum(nb_register)
FROM event_registration
WHERE event_id IN % s AND state IN ( ' draft ' , ' open ' , ' done ' )
GROUP BY event_id , state
"""
self . _cr . execute ( query , ( tuple ( self . ids ) , ) )
for event_id , state , num in self . _cr . fetchall ( ) :
event = self . browse ( event_id )
event [ state_field [ state ] ] + = num
# compute seats_available
for event in self :
event . seats_available = \
event . seats_max - ( event . seats_reserved + event . seats_used ) \
if event . seats_max > 0 else 0
registration_ids = fields . One2many ( ' event.registration ' , ' event_id ' , string = ' Registrations ' ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
count_registrations = fields . Integer ( string = ' Registrations ' ,
compute = ' _count_registrations ' )
date_begin = fields . Datetime ( string = ' Start Date ' , required = True ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
date_end = fields . Datetime ( string = ' End Date ' , required = True ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
@api.model
def _tz_get ( self ) :
2014-05-30 14:00:28 +00:00
return [ ( x , x ) for x in pytz . all_timezones ]
2014-07-06 14:44:26 +00:00
date_tz = fields . Selection ( ' _tz_get ' , string = ' Timezone ' ,
default = lambda self : self . _context . get ( ' tz ' , ' UTC ' ) )
@api.one
@api.depends ( ' date_tz ' , ' date_begin ' )
def _compute_date_begin_tz ( self ) :
if self . date_begin :
self_in_tz = self . with_context ( tz = ( self . date_tz or ' UTC ' ) )
date_begin = fields . Datetime . from_string ( self . date_begin )
self . date_begin_located = fields . Datetime . to_string ( fields . Datetime . context_timestamp ( self_in_tz , date_begin ) )
else :
self . date_begin_located = False
@api.one
@api.depends ( ' date_tz ' , ' date_end ' )
def _compute_date_end_tz ( self ) :
if self . date_end :
self_in_tz = self . with_context ( tz = ( self . date_tz or ' UTC ' ) )
date_end = fields . Datetime . from_string ( self . date_end )
self . date_end_located = fields . Datetime . to_string ( fields . Datetime . context_timestamp ( self_in_tz , date_end ) )
else :
self . date_end_located = False
2014-10-16 09:14:39 +00:00
@api.one
@api.depends ( ' address_id ' )
def _compute_country ( self ) :
self . country_id = self . address_id . country_id
2014-07-06 14:44:26 +00:00
date_begin_located = fields . Datetime ( string = ' Start Date Located ' , compute = ' _compute_date_begin_tz ' )
date_end_located = fields . Datetime ( string = ' End Date Located ' , compute = ' _compute_date_end_tz ' )
state = fields . Selection ( [
2012-03-28 14:38:53 +00:00
( ' draft ' , ' Unconfirmed ' ) ,
2012-04-30 13:14:04 +00:00
( ' cancel ' , ' Cancelled ' ) ,
2010-07-16 06:47:14 +00:00
( ' confirm ' , ' Confirmed ' ) ,
2014-07-06 14:44:26 +00:00
( ' done ' , ' Done ' )
] , string = ' Status ' , default = ' draft ' , readonly = True , required = True , copy = False ,
help = " If event is created, the status is ' Draft ' . If event is confirmed for the particular dates the status is set to ' Confirmed ' . If the event is over, the status is set to ' Done ' . If event is cancelled the status is set to ' Cancelled ' . " )
2014-08-01 08:11:36 +00:00
email_registration_id = fields . Many2one (
' email.template ' , string = ' Registration Confirmation Email ' ,
domain = [ ( ' model ' , ' = ' , ' event.registration ' ) ] ,
2014-07-06 14:44:26 +00:00
help = ' This field contains the template of the mail that will be automatically sent each time a registration for this event is confirmed. ' )
2014-08-01 08:11:36 +00:00
email_confirmation_id = fields . Many2one (
' email.template ' , string = ' Event Confirmation Email ' ,
domain = [ ( ' model ' , ' = ' , ' event.registration ' ) ] ,
2014-07-06 14:44:26 +00:00
help = " If you set an email template, each participant will receive this email announcing the confirmation of the event. " )
reply_to = fields . Char ( string = ' Reply-To Email ' ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } ,
help = " The email address of the organizer is likely to be put here, with the effect to be in the ' Reply-To ' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one. " )
address_id = fields . Many2one ( ' res.partner ' , string = ' Location ' ,
default = lambda self : self . env . user . company_id . partner_id ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
2014-10-16 09:14:39 +00:00
country_id = fields . Many2one ( ' res.country ' , string = ' Country ' ,
store = True , compute = ' _compute_country ' )
2014-07-06 14:44:26 +00:00
description = fields . Html ( string = ' Description ' , oldname = ' note ' , translate = True ,
readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' , change_default = True ,
default = lambda self : self . env [ ' res.company ' ] . _company_default_get ( ' event.event ' ) ,
required = False , readonly = False , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
organizer_id = fields . Many2one ( ' res.partner ' , string = ' Organizer ' ,
default = lambda self : self . env . user . company_id . partner_id )
is_subscribed = fields . Boolean ( string = ' Subscribed ' ,
compute = ' _compute_subscribe ' )
@api.one
@api.depends ( ' registration_ids ' )
def _count_registrations ( self ) :
self . count_registrations = len ( self . registration_ids )
@api.one
@api.depends ( ' registration_ids.user_id ' , ' registration_ids.state ' )
def _compute_subscribe ( self ) :
""" Determine whether the current user is already subscribed to any event in `self` """
user = self . env . user
self . is_subscribed = any (
reg . user_id == user and reg . state in ( ' open ' , ' done ' )
for reg in self . registration_ids
)
[FIX] models: display_name and name_get mismatch
- display_name uses name_get and not the other way around:
name_get should not call _compute_display_name, _compute_display_name should call name_get.
The previous behaviour was not backward-compatible with the old api.
All the models redefining name_get would have 2 different behaviors between name_get and display_name.
- Do not set an inverse function to display_name:
In most cases, writing on display_name writes on _rec_name (if any, not mandatory).
If the display_name computation is redefined, we need to redefine as well the inverse method to avoid unexpected behaviour
This required to also modify tests in base_import as readonly fields are avoided.
- Remove search method on display_name:
For the same reason as for the first point, it could be good that searching on display_name use name_search (and not the other way around).
However doing this would be very inefficiant (need to do the search, without limit, extract the ids of the name_get result just to generate
a subdomain ('id', 'in', [...]). As in most cases it would anyway mean to search on the _rec_name it's better to directly do so.
- Changing label to avoid mismatch:
In view displaying the list of fields or when a match is made on the label of a field (e.g. when importing csv file,
matching is made on both label and technical name), the fact that display_name field has '
Calling it 'Display Name' will avoid most errors.
- remove display_name definition from website_forum_doc,ir_model:
These fields are doing the same thing as the display_name of the new api, we can remove them.
We need to keep the one for res.partner as it's a stored field.
2014-07-16 08:35:52 +00:00
@api.multi
2014-07-06 14:44:26 +00:00
@api.depends ( ' name ' , ' date_begin ' , ' date_end ' )
[FIX] models: display_name and name_get mismatch
- display_name uses name_get and not the other way around:
name_get should not call _compute_display_name, _compute_display_name should call name_get.
The previous behaviour was not backward-compatible with the old api.
All the models redefining name_get would have 2 different behaviors between name_get and display_name.
- Do not set an inverse function to display_name:
In most cases, writing on display_name writes on _rec_name (if any, not mandatory).
If the display_name computation is redefined, we need to redefine as well the inverse method to avoid unexpected behaviour
This required to also modify tests in base_import as readonly fields are avoided.
- Remove search method on display_name:
For the same reason as for the first point, it could be good that searching on display_name use name_search (and not the other way around).
However doing this would be very inefficiant (need to do the search, without limit, extract the ids of the name_get result just to generate
a subdomain ('id', 'in', [...]). As in most cases it would anyway mean to search on the _rec_name it's better to directly do so.
- Changing label to avoid mismatch:
In view displaying the list of fields or when a match is made on the label of a field (e.g. when importing csv file,
matching is made on both label and technical name), the fact that display_name field has '
Calling it 'Display Name' will avoid most errors.
- remove display_name definition from website_forum_doc,ir_model:
These fields are doing the same thing as the display_name of the new api, we can remove them.
We need to keep the one for res.partner as it's a stored field.
2014-07-16 08:35:52 +00:00
def name_get ( self ) :
result = [ ]
for event in self :
2015-12-01 11:28:12 +00:00
date_begin = fields . Datetime . from_string ( event . date_begin )
date_end = fields . Datetime . from_string ( event . date_end )
dates = [ fields . Date . to_string ( fields . Datetime . context_timestamp ( event , dt ) ) for dt in [ date_begin , date_end ] if dt ]
[FIX] models: display_name and name_get mismatch
- display_name uses name_get and not the other way around:
name_get should not call _compute_display_name, _compute_display_name should call name_get.
The previous behaviour was not backward-compatible with the old api.
All the models redefining name_get would have 2 different behaviors between name_get and display_name.
- Do not set an inverse function to display_name:
In most cases, writing on display_name writes on _rec_name (if any, not mandatory).
If the display_name computation is redefined, we need to redefine as well the inverse method to avoid unexpected behaviour
This required to also modify tests in base_import as readonly fields are avoided.
- Remove search method on display_name:
For the same reason as for the first point, it could be good that searching on display_name use name_search (and not the other way around).
However doing this would be very inefficiant (need to do the search, without limit, extract the ids of the name_get result just to generate
a subdomain ('id', 'in', [...]). As in most cases it would anyway mean to search on the _rec_name it's better to directly do so.
- Changing label to avoid mismatch:
In view displaying the list of fields or when a match is made on the label of a field (e.g. when importing csv file,
matching is made on both label and technical name), the fact that display_name field has '
Calling it 'Display Name' will avoid most errors.
- remove display_name definition from website_forum_doc,ir_model:
These fields are doing the same thing as the display_name of the new api, we can remove them.
We need to keep the one for res.partner as it's a stored field.
2014-07-16 08:35:52 +00:00
dates = sorted ( set ( dates ) )
result . append ( ( event . id , ' %s ( %s ) ' % ( event . name , ' - ' . join ( dates ) ) ) )
return result
2014-07-06 14:44:26 +00:00
@api.one
@api.constrains ( ' seats_max ' , ' seats_available ' )
def _check_seats_limit ( self ) :
if self . seats_max and self . seats_available < 0 :
raise Warning ( _ ( ' No more available seats. ' ) )
@api.one
@api.constrains ( ' date_begin ' , ' date_end ' )
def _check_closing_date ( self ) :
if self . date_end < self . date_begin :
raise Warning ( _ ( ' Closing Date cannot be set before Beginning Date. ' ) )
@api.one
def button_draft ( self ) :
self . state = ' draft '
@api.one
def button_cancel ( self ) :
for event_reg in self . registration_ids :
if event_reg . state == ' done ' :
raise Warning ( _ ( " You have already set a registration for this event as ' Attended ' . Please reset it to draft if you want to cancel this event. " ) )
self . registration_ids . write ( { ' state ' : ' cancel ' } )
self . state = ' cancel '
@api.one
def button_done ( self ) :
self . state = ' done '
@api.one
def confirm_event ( self ) :
if self . email_confirmation_id :
# send reminder that will confirm the event for all the people that were already confirmed
regs = self . registration_ids . filtered ( lambda reg : reg . state not in ( ' draft ' , ' cancel ' ) )
regs . mail_user_confirm ( )
self . state = ' confirm '
@api.one
def button_confirm ( self ) :
""" Confirm Event and send confirmation email to all register peoples """
self . confirm_event ( )
@api.one
def subscribe_to_event ( self ) :
""" Subscribe the current user to a given event """
user = self . env . user
num_of_seats = int ( self . _context . get ( ' ticket ' , 1 ) )
regs = self . registration_ids . filtered ( lambda reg : reg . user_id == user )
# the subscription is done as SUPERUSER_ID because in case we share the
# kanban view, we want anyone to be able to subscribe
if not regs :
regs = regs . sudo ( ) . create ( {
' event_id ' : self . id ,
' email ' : user . email ,
' name ' : user . name ,
' user_id ' : user . id ,
' nb_register ' : num_of_seats ,
} )
2012-04-19 11:21:25 +00:00
else :
2014-07-06 14:44:26 +00:00
regs . write ( { ' nb_register ' : num_of_seats } )
regs . sudo ( ) . confirm_registration ( )
@api.one
def unsubscribe_to_event ( self ) :
""" Unsubscribe the current user from a given event """
# the unsubscription is done as SUPERUSER_ID because in case we share
# the kanban view, we want anyone to be able to unsubscribe
user = self . env . user
regs = self . sudo ( ) . registration_ids . filtered ( lambda reg : reg . user_id == user )
regs . button_reg_cancel ( )
@api.onchange ( ' type ' )
def _onchange_type ( self ) :
if self . type :
self . reply_to = self . type . default_reply_to
self . email_registration_id = self . type . default_email_registration
self . email_confirmation_id = self . type . default_email_event
self . seats_min = self . type . default_registration_min
self . seats_max = self . type . default_registration_max
@api.onchange ( ' date_begin ' )
def _onchange_date_begin ( self ) :
if self . date_begin and not self . date_end :
date_begin = fields . Datetime . from_string ( self . date_begin )
self . date_end = fields . Datetime . to_string ( date_begin + timedelta ( hours = 1 ) )
class event_registration ( models . Model ) :
2014-08-01 08:11:36 +00:00
_name = ' event.registration '
_description = ' Event Registration '
2012-12-20 10:00:05 +00:00
_inherit = [ ' mail.thread ' , ' ir.needaction_mixin ' ]
2012-03-30 09:08:37 +00:00
_order = ' name, create_date desc '
2014-07-06 14:44:26 +00:00
origin = fields . Char ( string = ' Source Document ' , readonly = True ,
help = " Reference of the sales order which created the registration " )
nb_register = fields . Integer ( string = ' Number of Participants ' , required = True , default = 1 ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
event_id = fields . Many2one ( ' event.event ' , string = ' Event ' , required = True ,
readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
partner_id = fields . Many2one ( ' res.partner ' , string = ' Partner ' ,
states = { ' done ' : [ ( ' readonly ' , True ) ] } )
date_open = fields . Datetime ( string = ' Registration Date ' , readonly = True )
date_closed = fields . Datetime ( string = ' Attended Date ' , readonly = True )
reply_to = fields . Char ( string = ' Reply-to Email ' , related = ' event_id.reply_to ' ,
readonly = True )
log_ids = fields . One2many ( ' mail.message ' , ' res_id ' , string = ' Logs ' ,
domain = [ ( ' model ' , ' = ' , _name ) ] )
event_begin_date = fields . Datetime ( string = " Event Start Date " , related = ' event_id.date_begin ' ,
readonly = True )
event_end_date = fields . Datetime ( string = " Event End Date " , related = ' event_id.date_end ' ,
readonly = True )
user_id = fields . Many2one ( ' res.users ' , string = ' User ' , states = { ' done ' : [ ( ' readonly ' , True ) ] } )
company_id = fields . Many2one ( ' res.company ' , string = ' Company ' , related = ' event_id.company_id ' ,
store = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } )
state = fields . Selection ( [
( ' draft ' , ' Unconfirmed ' ) ,
( ' cancel ' , ' Cancelled ' ) ,
( ' open ' , ' Confirmed ' ) ,
( ' done ' , ' Attended ' ) ,
] , string = ' Status ' , default = ' draft ' , readonly = True , copy = False )
email = fields . Char ( string = ' Email ' )
phone = fields . Char ( string = ' Phone ' )
name = fields . Char ( string = ' Name ' , select = True )
@api.one
@api.constrains ( ' event_id ' , ' state ' , ' nb_register ' )
def _check_seats_limit ( self ) :
if self . event_id . seats_max and \
self . event_id . seats_available < ( self . nb_register if self . state == ' draft ' else 0 ) :
raise Warning ( _ ( ' No more available seats. ' ) )
@api.one
def do_draft ( self ) :
self . state = ' draft '
@api.one
def confirm_registration ( self ) :
self . event_id . message_post (
body = _ ( ' New registration confirmed: %s . ' ) % ( self . name or ' ' ) ,
subtype = " event.mt_event_registration " )
self . message_post ( body = _ ( ' Event Registration confirmed. ' ) )
self . state = ' open '
@api.one
def registration_open ( self ) :
""" Open Registration """
self . confirm_registration ( )
self . mail_user ( )
@api.one
def button_reg_close ( self ) :
""" Close Registration """
today = fields . Datetime . now ( )
if self . event_id . date_begin < = today :
self . write ( { ' state ' : ' done ' , ' date_closed ' : today } )
else :
raise Warning ( _ ( " You must wait for the starting day of the event to do this action. " ) )
@api.one
def button_reg_cancel ( self ) :
self . state = ' cancel '
2014-01-27 13:58:28 +00:00
2014-07-06 14:44:26 +00:00
@api.one
def mail_user ( self ) :
""" Send email to user with email_template when registration is done """
if self . event_id . state == ' confirm ' and self . event_id . email_confirmation_id :
self . mail_user_confirm ( )
else :
template = self . event_id . email_registration_id
if template :
mail_message = template . send_mail ( self . id )
@api.one
def mail_user_confirm ( self ) :
""" Send email to user when the event is confirmed """
template = self . event_id . email_confirmation_id
if template :
mail_message = template . send_mail ( self . id )
2015-11-09 09:38:19 +00:00
@api.multi
def message_get_suggested_recipients ( self ) :
recipients = super ( event_registration , self ) . message_get_suggested_recipients ( )
try :
for registration in self :
if registration . partner_id :
self . _message_add_suggested_recipient ( recipients , registration , partner = registration . partner_id , reason = _ ( ' Registrant ' ) )
elif registration . email :
self . _message_add_suggested_recipient ( recipients , registration , email = registration . email , reason = _ ( ' Registrant Email ' ) )
except AccessError : # no read access rights -> ignore suggested recipients
pass
return recipients
2014-07-06 14:44:26 +00:00
@api.onchange ( ' partner_id ' )
def _onchange_partner ( self ) :
if self . partner_id :
2014-09-18 09:07:54 +00:00
contact_id = self . partner_id . address_get ( ) . get ( ' default ' , False )
if contact_id :
contact = self . env [ ' res.partner ' ] . browse ( contact_id )
2014-07-06 14:44:26 +00:00
self . name = contact . name
self . email = contact . email
self . phone = contact . phone
2008-08-24 14:45:43 +00:00
2011-03-02 17:49:20 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: