[IMP]: Create email template fot crm meeting instead of calender atttendee , and clean code
bzr revid: aja@tinyerp.com-20130802085607-pdnwpbqvycxm91di
This commit is contained in:
@@ -296,6 +296,7 @@ property or property parameter."),
|
||||
multi='event_end_date'),
|
||||
'ref': fields.reference('Event Ref', selection=_links_get, size=128),
|
||||
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'needs-action',
|
||||
@@ -403,22 +404,14 @@ property or property parameter."),
|
||||
res = cal.serialize()
|
||||
return res
|
||||
|
||||
def meeting_invitation(self, cr, uid, ids, context=None):
|
||||
meeting_id = self.pool.get('crm.meeting').search(cr, uid, [('attendee_ids','in',ids)])
|
||||
action_id = self.pool.get('ir.actions.act_window').search(cr, uid, [('res_model','=','crm.meeting')], context=context)
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
|
||||
if action_id:
|
||||
base_url += '/meeting/meeting_invitation?db=%s&token=%s&action=%s&id=%s' % (cr.dbname, ids,action_id[0],meeting_id[0]);
|
||||
return base_url
|
||||
|
||||
def _send_mail(self, cr, uid, ids, mail_to, email_from=tools.config.get('email_from', False), context=None):
|
||||
"""
|
||||
Send mail for event invitation to event attendees.
|
||||
@param email_from: email address for user sending the mail
|
||||
@return: True
|
||||
"""
|
||||
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.name
|
||||
mail_id = []
|
||||
local_context = context.copy()
|
||||
color = {
|
||||
'needs-action' : 'grey',
|
||||
'accepted' :'green',
|
||||
@@ -426,56 +419,23 @@ property or property parameter."),
|
||||
'declined':'red',
|
||||
'delegated':'grey'
|
||||
}
|
||||
image_cricle = "<div style='display:inline-block; border-radius: 50% %; width:10px; height:10px; background:%s;'> </div>"
|
||||
for attendee in self.browse(cr, uid, ids, context=context):
|
||||
res_obj = attendee.ref
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
if res_obj:
|
||||
att = {}
|
||||
att_info = [(image_cricle % color.get('needs-action')) + 'You', (image_cricle % color.get('accepted')) + res_obj.organizer+ '<span style= "color:#A9A9A9; ont-size: 9px">- Organizer </br></span>']
|
||||
sub = res_obj.name
|
||||
other_invitation_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])
|
||||
other_invitation_ids.remove(attendee.id)
|
||||
for att2 in self.browse(cr, uid, other_invitation_ids):
|
||||
name = att2.user_id and att2.user_id.name or att2.partner_id and att2.partner_id.name or att2.email
|
||||
att_info.append((image_cricle % color.get(att2.state)) + name)
|
||||
tz = context.get('tz', pytz.timezone('UTC'))
|
||||
allday = False
|
||||
date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(res_obj.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
|
||||
date_deadline = fields.datetime.context_timestamp(cr, uid, datetime.strptime(res_obj.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
|
||||
if res_obj.allday:
|
||||
time = "AllDay" + "," + date.strftime('%B-%d-%Y')
|
||||
tz = ''
|
||||
elif res_obj.duration < 24:
|
||||
duration = date + timedelta(hours= res_obj.duration)
|
||||
time = date.strftime('%B-%d-%Y') + " at (" + date.strftime('%H-%M') + " To " + duration.strftime('%H-%M') + ")"
|
||||
else :
|
||||
time = date.strftime('%B-%d-%Y') + " at " + date.strftime('%H-%M') + " To \n" + date_deadline.strftime('%B-%d-%Y') + " at " + date_deadline.strftime('%H-%M')
|
||||
footer = self.meeting_invitation(cr, uid, attendee.id, context=context)
|
||||
map_url = ''
|
||||
if res_obj.location:
|
||||
map_url = """<span style= "color:#A9A9A9; "> (<a href="http://maps.google.com/maps?oi=map&q=%s">View Map</a>)</span>""" % res_obj.location
|
||||
body_vals = {'user':attendee.user_id and attendee.user_id.name,
|
||||
'name': res_obj.name,
|
||||
'responsible': res_obj.user_id and res_obj.user_id.name or 'OpenERP User',
|
||||
'company': company,
|
||||
'description': res_obj.description or '-',
|
||||
'attendees': ',\n' .join(att_info),
|
||||
'time': time,
|
||||
'tz': tz,
|
||||
'location': res_obj.location or '-',
|
||||
'map' : map_url or '',
|
||||
'organizer' : res_obj.organizer,
|
||||
'url' : footer}
|
||||
body_id = self.pool.get('email.template').search(cr, uid, [('subject', '=', 'Meeting Invitation')], context=context)
|
||||
body = self.pool.get('email.template').browse(cr, uid, body_id[0], context=context).body_html % body_vals
|
||||
model,template_id = data_pool.get_object_reference(cr, uid, 'base_calendar', "crm_email_template_meeting_invitation")
|
||||
model,act_id = data_pool.get_object_reference(cr, uid, 'base_calendar', "view_crm_meeting_calendar")
|
||||
action_id = self.pool.get('ir.actions.act_window').search(cr, uid, [('view_id','=',act_id)], context=context)
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
|
||||
body = self.pool.get('email.template').browse(cr, uid, template_id, context=context).body_html
|
||||
if attendee.email and email_from:
|
||||
ics_file = self.get_ics_file(cr, uid, res_obj, context=context)
|
||||
vals = {'email_from': email_from,
|
||||
'email_to': attendee.email,
|
||||
'state': 'outgoing',
|
||||
'subject': sub,
|
||||
'body_html': body,
|
||||
'auto_delete': True}
|
||||
local_context['att_obj'] = attendee
|
||||
local_context['color'] = color
|
||||
local_context['action_id'] = action_id[0]
|
||||
local_context['dbname'] = cr.dbname
|
||||
local_context['base_url'] = base_url
|
||||
vals = self.pool.get('email.template').generate_email(cr, uid, template_id, res_obj.id, context=local_context)
|
||||
if ics_file:
|
||||
vals['attachment_ids'] = [(0,0,{'name': 'invitation.ics',
|
||||
'datas_fname': 'invitation.ics',
|
||||
|
||||
@@ -135,60 +135,4 @@
|
||||
<field eval="'(False,)'" name="args" />
|
||||
</record>
|
||||
</data>
|
||||
<data>
|
||||
<!--Email template -->
|
||||
<record id="email_template_meeting_invitation" model="email.template">
|
||||
<field name="name">Meeting Invitation</field>
|
||||
<field name="email_from">${object.user_id.email or ''}</field>
|
||||
<field name="subject">Meeting Invitation</field>
|
||||
<field name="email_to" >${object.email}</field>
|
||||
<field name="model_id" ref="base_calendar.model_calendar_attendee"/>
|
||||
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[<html><head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<title>%(name)s</title>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table cellspacing="0" cellpadding="6" border="0" style = "margin: auto; display:block; border:2px solid #8E0000; background: #F8F8F8; border-radius: 2px; width: 600px; height: auto; ">
|
||||
<tr>
|
||||
<td style = "display: block; border: 2px solid #8E0000; height: 45px; width: auto; background : #8E0000; text-align: center; font-family: Arial, sans-serif; font-size: 20px; color:#FFFFFF; ">
|
||||
<div style="text-align: center" > <b>%(name)s </b> </div> </td></tr>
|
||||
<tr>
|
||||
<td> <div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" > <b> Hello %(user)s, </b> <br/>
|
||||
%(organizer)s invited you for the %(name)s meeting of %(company)s. </div></td></tr>
|
||||
<tr><td>
|
||||
<table cellspacing="0" cellpadding="0" border="0" style="margin-top: 15px; margin-left: 10px; background: #F8F8F8">
|
||||
<tr valign="top">
|
||||
<td><div style = "height: 25px; width: 120px; background : # CCCCCC;font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b> When :</b></div></td>
|
||||
<td colspan="1"> <div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >%(time)s <span style= " color:#A9A9A9; "> (%(tz)s) </span></div>
|
||||
</td> </tr>
|
||||
<tr valign="top">
|
||||
<td> <div style = "height: 25px; width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b>Where :</b></div> </td>
|
||||
<td colspan="1"> <div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >%(location)s %(map)s </div></td> </tr>
|
||||
|
||||
<tr valign="top">
|
||||
<td> <div style = "height: 25px; width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b>What :</b></div> </td>
|
||||
<td colspan="3"> <div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >%(description)s</div> </td> </tr>
|
||||
<tr valign="top">
|
||||
<td style = "height: 25px;width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"> <div><b>Attendees:<b></div> </td>
|
||||
<td colspan="3"><div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 10px" > %(attendees)s </div> </td> </tr>
|
||||
</table></td></tr>
|
||||
<tr >
|
||||
<td><div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 10px" ><span style= "margin-top: 50px; margin-left: 200px;" ><a href="%(url)s&view_type=form&status=accepted">Accept</a> | <a href="%(url)s&view_type=form&status=declined">Decline</a></span></div> </td>
|
||||
<tr>
|
||||
<td><div > -- </br> Sent by %(responsible)s from %(company)s.View this meeting detail <a href="%(url)s&view_type=calendar&status=">directly in OpenERP</a></div> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
]]></field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -26,6 +26,9 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from openerp.tools.translate import _
|
||||
from base_calendar import get_real_ids, base_calendar_id2real_id
|
||||
from openerp.addons.base_status.base_state import base_state
|
||||
from datetime import datetime, timedelta, date
|
||||
import pytz
|
||||
from openerp import tools
|
||||
#
|
||||
# crm.meeting is defined here so that it may be used by modules other than crm,
|
||||
# without forcing the installation of crm.
|
||||
@@ -45,27 +48,48 @@ class crm_meeting(base_state, osv.Model):
|
||||
_order = "id desc"
|
||||
_inherit = ["calendar.event", "mail.thread", "ir.needaction_mixin"]
|
||||
|
||||
def _check_status(self, cr, uid, ids, context=None):
|
||||
def _check_status(self, cr, uid, meeting_id, context=None):
|
||||
attendee_pool = self.pool.get('calendar.attendee')
|
||||
user = self.pool.get('res.users').read(cr,uid,uid,['partner_id'],context)
|
||||
for attendee in self.browse(cr,uid,ids,context)[0].attendee_ids:
|
||||
if user['partner_id'][0] == attendee_pool.read(cr,uid,attendee.id,['partner_id'],context)['partner_id'][0]:
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
for attendee in self.browse(cr,uid,meeting_id,context).attendee_ids:
|
||||
if user.partner_id.id == attendee.partner_id.id:
|
||||
return attendee
|
||||
return False
|
||||
|
||||
def _check_attendee(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
res[ids[0]] = False
|
||||
if self._check_status(cr, uid, ids, context):
|
||||
res[ids[0]] = True
|
||||
for meeting_id in ids:
|
||||
res[meeting_id] = False
|
||||
if self._check_status(cr, uid, meeting_id, context):
|
||||
res[meeting_id] = True
|
||||
return res
|
||||
|
||||
def _compute_status(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
res[ids[0]] = 'needs-action'
|
||||
attendee = self._check_status(cr, uid, ids, context)
|
||||
if attendee:
|
||||
res[ids[0]] = attendee.state
|
||||
for meeting_id in ids:
|
||||
res[meeting_id] = 'needs-action'
|
||||
attendee = self._check_status(cr, uid, meeting_id, context)
|
||||
if attendee:
|
||||
res[meeting_id] = attendee.state
|
||||
return res
|
||||
|
||||
def _compute_time(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
tz = context.get('tz', pytz.timezone('UTC'))
|
||||
for meeting in self.browse(cr, uid, ids, context=context):
|
||||
date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(meeting.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
|
||||
date_deadline = fields.datetime.context_timestamp(cr, uid, datetime.strptime(meeting.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
|
||||
event_date = date.strftime('%B-%d-%Y')
|
||||
event_time = date.strftime('%H-%M')
|
||||
res[meeting.id] = False
|
||||
if meeting.allday:
|
||||
time = _("AllDay , %s") % (date_event)
|
||||
elif meeting.duration < 24:
|
||||
duration = date + timedelta(hours= meeting.duration)
|
||||
time = ("%s at ( %s To %s) (%s)") % (str(event_date), str(event_time), str(duration.strftime('%H-%M')), str(tz))
|
||||
else :
|
||||
time = ("%s at %s To\n %s at %s (%s)") % (event_date, event_time, date_deadline.strftime('%B-%d-%Y'), date_deadline.strftime('%H-%M'), tz)
|
||||
res[meeting.id] = time
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
@@ -89,6 +113,7 @@ class crm_meeting(base_state, osv.Model):
|
||||
type="boolean"),
|
||||
'attendee_status': fields.function(_compute_status, string='Attendee Status', \
|
||||
type="selection"),
|
||||
'event_time': fields.function(_compute_time, string='Event Time', type="char"),
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'open',
|
||||
@@ -151,20 +176,22 @@ class crm_meeting(base_state, osv.Model):
|
||||
|
||||
def do_decline(self, cr, uid, ids, context=None, *args):
|
||||
attendee_pool = self.pool.get('calendar.attendee')
|
||||
attendee = self._check_status(cr, uid, ids, context)
|
||||
if attendee:
|
||||
if attendee.state != 'declined':
|
||||
self.message_post(cr, uid, ids, body=_(("%s has Declined Invitation") % (attendee.cn)), context=context)
|
||||
attendee_pool.write(cr, uid, attendee.id, {'state': 'declined'}, context)
|
||||
for meeting_id in ids:
|
||||
attendee = self._check_status(cr, uid, meeting_id, context)
|
||||
if attendee:
|
||||
if attendee.state != 'declined':
|
||||
self.message_post(cr, uid, meeting_id, body=_(("%s has Declined Invitation") % (attendee.cn)), context=context)
|
||||
attendee_pool.write(cr, uid, attendee.id, {'state': 'declined'}, context)
|
||||
return True
|
||||
|
||||
def do_accept(self, cr, uid, ids, context=None, *args):
|
||||
attendee_pool = self.pool.get('calendar.attendee')
|
||||
attendee = self._check_status(cr, uid, ids, context)
|
||||
if attendee:
|
||||
if attendee.state != 'accepted':
|
||||
self.message_post(cr, uid, ids, body=_(("%s has Accepted Invitation") % (attendee.cn)), context=context)
|
||||
attendee_pool.write(cr, uid, attendee.id, {'state': 'accepted'}, context)
|
||||
for meeting_id in ids:
|
||||
attendee = self._check_status(cr, uid, meeting_id, context)
|
||||
if attendee:
|
||||
if attendee.state != 'accepted':
|
||||
self.message_post(cr, uid, meeting_id, body=_(("%s has Accepted Invitation") % (attendee.cn)), context=context)
|
||||
attendee_pool.write(cr, uid, attendee.id, {'state': 'accepted'}, context)
|
||||
return True
|
||||
|
||||
class mail_message(osv.osv):
|
||||
|
||||
@@ -28,5 +28,113 @@
|
||||
<field name="name">Meeting</field>
|
||||
<field name="object">crm.meeting</field>
|
||||
</record>
|
||||
<record id="crm_email_template_meeting_invitation" model="email.template">
|
||||
<field name="name">CRM Meeting Invitation</field>
|
||||
<field name="email_from">${object.user_id.email or ''}</field>
|
||||
<field name="subject">${object.name}</field>
|
||||
<field name="email_to" >${ctx['att_obj'].email}</field>
|
||||
<field name="model_id" ref="base_calendar.model_crm_meeting"/>
|
||||
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<title>${object.name}</title>
|
||||
</head>
|
||||
<body>
|
||||
<table cellspacing="0" cellpadding="6" border="0" style = "margin: auto; display:block; border:2px solid #8E0000; background: #F8F8F8; border-radius: 2px; width: 600px; height: auto; ">
|
||||
<tr>
|
||||
<td style = "display: block; border: 2px solid #8E0000; height: 45px; width: auto;background : #8E0000; text-align: center; font-family: Arial, sans-serif; font-size: 20px; color:#FFFFFF; ">
|
||||
<div style="text-align: center" > <b>${object.name}</b> </div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" > <b>Hello ${ctx['att_obj'].cn}, </b> <br/>
|
||||
${object.organizer} invited you for the ${object.name} meeting of ${object.user_id.company_id.name}. </div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table cellspacing="0" cellpadding="0" border="0" style="margin-top: 15px; margin-left: 10px; background: #F8F8F8">
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<div style = "height: 25px; width: 120px; background : # CCCCCC;font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b> When :</b>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="1">
|
||||
<div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >
|
||||
${object.event_time}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<div style = "height: 25px; width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b>Where :</b>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="1">
|
||||
<div style = "font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >
|
||||
${object.location or ''}
|
||||
% if object.location :
|
||||
<span style= "color:#A9A9A9; ">
|
||||
(<a href="http://maps.google.com/maps?oi=map&q=${object.location}">View Map</a>)
|
||||
</span>
|
||||
% endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>
|
||||
<div style = "height: 25px; width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;"><b>What :</b>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px" >
|
||||
${object.description or ''}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td style = "height: 25px;width: 120px; background : # CCCCCC; font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 14px;">
|
||||
<div><b>Attendees:<b></div>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
% for attendee in object.attendee_ids:
|
||||
<div style='display:inline-block; border-radius: 50%; width:10px; height:10px;background:${ctx['color'][attendee.state]}'>
|
||||
</div>
|
||||
<span style="margin-left:5px">
|
||||
${attendee.cn}
|
||||
</span>
|
||||
% endfor
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr >
|
||||
<td>
|
||||
<div style = " font-family: Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 10px" >
|
||||
<span style= "margin-top: 50px; margin-left: 200px;" >
|
||||
<a href="${ctx['base_url']}/meeting/meeting_invitation?db=${ctx['dbname']}&token=${ctx['att_obj'].id}&action=${ctx['action_id']}&id=${object.id}&view_type=form&status=accepted">Accept</a> |
|
||||
<a href="${ctx['base_url']}/meeting/meeting_invitation?db=${ctx['dbname']}&token=${ctx['att_obj'].id}&action=${ctx['action_id']}&id=${object.id}&view_type=form&status=declined">Declined</a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div >
|
||||
-- </br> Sent by ${object.user_id.name} from ${object.user_id.company_id.name}. View this meeting detail
|
||||
<a href="${ctx['base_url']}/meeting/meeting_invitation?db=${ctx['dbname']}&token=${ctx['att_obj'].id}&action=${ctx['action_id']}&id=${object.id}&view_type=calendar&status=">directly in OpenERP.</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
]]]></field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
Reference in New Issue
Block a user