initial commit
This commit is contained in:
commit
fd1d573036
7
__init__.py
Normal file
7
__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
||||||
|
from . import populate
|
||||||
|
from . import wizard
|
57
__manifest__.py
Normal file
57
__manifest__.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
{
|
||||||
|
'name': 'Calendar',
|
||||||
|
'version': '1.1',
|
||||||
|
'sequence': 165,
|
||||||
|
'depends': ['base', 'mail', 'onboarding'],
|
||||||
|
'summary': "Schedule employees' meetings",
|
||||||
|
'description': """
|
||||||
|
This is a full-featured calendar system.
|
||||||
|
========================================
|
||||||
|
|
||||||
|
It supports:
|
||||||
|
------------
|
||||||
|
- Calendar of events
|
||||||
|
- Recurring events
|
||||||
|
|
||||||
|
If you need to manage your meetings, you should install the CRM module.
|
||||||
|
""",
|
||||||
|
'category': 'Productivity/Calendar',
|
||||||
|
'demo': [
|
||||||
|
'data/calendar_demo.xml'
|
||||||
|
],
|
||||||
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'security/calendar_security.xml',
|
||||||
|
'data/calendar_cron.xml',
|
||||||
|
'data/mail_template_data.xml',
|
||||||
|
'data/calendar_data.xml',
|
||||||
|
'data/calendar_onboarding_data.xml',
|
||||||
|
'data/mail_activity_type_data.xml',
|
||||||
|
'data/mail_message_subtype_data.xml',
|
||||||
|
'views/mail_activity_views.xml',
|
||||||
|
'views/calendar_templates.xml',
|
||||||
|
'views/calendar_views.xml',
|
||||||
|
'views/res_config_settings_views.xml',
|
||||||
|
'views/res_partner_views.xml',
|
||||||
|
'wizard/calendar_provider_config.xml',
|
||||||
|
'wizard/calendar_popover_delete_wizard.xml',
|
||||||
|
'wizard/mail_activity_schedule_views.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'application': True,
|
||||||
|
'assets': {
|
||||||
|
'web.assets_backend': [
|
||||||
|
'calendar/static/src/**/*',
|
||||||
|
],
|
||||||
|
'web.qunit_suite_tests': [
|
||||||
|
'calendar/static/tests/**/*',
|
||||||
|
],
|
||||||
|
'web.assets_tests': [
|
||||||
|
'calendar/static/tests/tours/**/*',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
BIN
__pycache__/__init__.cpython-311.pyc
Normal file
BIN
__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
4
controllers/__init__.py
Normal file
4
controllers/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import main
|
BIN
controllers/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
controllers/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
controllers/__pycache__/main.cpython-311.pyc
Normal file
BIN
controllers/__pycache__/main.cpython-311.pyc
Normal file
Binary file not shown.
120
controllers/main.py
Normal file
120
controllers/main.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
import odoo.http as http
|
||||||
|
|
||||||
|
from odoo.http import request
|
||||||
|
from odoo.tools.misc import get_lang
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarController(http.Controller):
|
||||||
|
|
||||||
|
# YTI Note: Keep id and kwargs only for retrocompatibility purpose
|
||||||
|
@http.route('/calendar/meeting/accept', type='http', auth="calendar")
|
||||||
|
def accept_meeting(self, token, id, **kwargs):
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('access_token', '=', token),
|
||||||
|
('state', '!=', 'accepted')])
|
||||||
|
attendee.do_accept()
|
||||||
|
return self.view_meeting(token, id)
|
||||||
|
|
||||||
|
@http.route('/calendar/recurrence/accept', type='http', auth="calendar")
|
||||||
|
def accept_recurrence(self, token, id, **kwargs):
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('access_token', '=', token),
|
||||||
|
('state', '!=', 'accepted')])
|
||||||
|
if attendee:
|
||||||
|
attendees = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('event_id', 'in', attendee.event_id.recurrence_id.calendar_event_ids.ids),
|
||||||
|
('partner_id', '=', attendee.partner_id.id),
|
||||||
|
('state', '!=', 'accepted'),
|
||||||
|
])
|
||||||
|
attendees.do_accept()
|
||||||
|
return self.view_meeting(token, id)
|
||||||
|
|
||||||
|
@http.route('/calendar/meeting/decline', type='http', auth="calendar")
|
||||||
|
def decline_meeting(self, token, id, **kwargs):
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('access_token', '=', token),
|
||||||
|
('state', '!=', 'declined')])
|
||||||
|
attendee.do_decline()
|
||||||
|
return self.view_meeting(token, id)
|
||||||
|
|
||||||
|
@http.route('/calendar/recurrence/decline', type='http', auth="calendar")
|
||||||
|
def decline_recurrence(self, token, id, **kwargs):
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('access_token', '=', token),
|
||||||
|
('state', '!=', 'declined')])
|
||||||
|
if attendee:
|
||||||
|
attendees = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('event_id', 'in', attendee.event_id.recurrence_id.calendar_event_ids.ids),
|
||||||
|
('partner_id', '=', attendee.partner_id.id),
|
||||||
|
('state', '!=', 'declined'),
|
||||||
|
])
|
||||||
|
attendees.do_decline()
|
||||||
|
return self.view_meeting(token, id)
|
||||||
|
|
||||||
|
@http.route('/calendar/meeting/view', type='http', auth="calendar")
|
||||||
|
def view_meeting(self, token, id, **kwargs):
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([
|
||||||
|
('access_token', '=', token),
|
||||||
|
('event_id', '=', int(id))])
|
||||||
|
if not attendee:
|
||||||
|
return request.not_found()
|
||||||
|
timezone = attendee.partner_id.tz
|
||||||
|
lang = attendee.partner_id.lang or get_lang(request.env).code
|
||||||
|
event = request.env['calendar.event'].with_context(tz=timezone, lang=lang).sudo().browse(int(id))
|
||||||
|
company = event.user_id and event.user_id.company_id or event.create_uid.company_id
|
||||||
|
|
||||||
|
# If user is internal and logged, redirect to form view of event
|
||||||
|
# otherwise, display the simplifyed web page with event informations
|
||||||
|
if request.session.uid and request.env['res.users'].browse(request.session.uid).user_has_groups('base.group_user'):
|
||||||
|
return request.redirect('/web?db=%s#id=%s&view_type=form&model=calendar.event' % (request.env.cr.dbname, id))
|
||||||
|
|
||||||
|
# NOTE : we don't use request.render() since:
|
||||||
|
# - we need a template rendering which is not lazy, to render before cursor closing
|
||||||
|
# - we need to display the template in the language of the user (not possible with
|
||||||
|
# request.render())
|
||||||
|
response_content = request.env['ir.ui.view'].with_context(lang=lang)._render_template(
|
||||||
|
'calendar.invitation_page_anonymous', {
|
||||||
|
'company': company,
|
||||||
|
'event': event,
|
||||||
|
'attendee': attendee,
|
||||||
|
})
|
||||||
|
return request.make_response(response_content, headers=[('Content-Type', 'text/html')])
|
||||||
|
|
||||||
|
@http.route('/calendar/meeting/join', type='http', auth="user", website=True)
|
||||||
|
def calendar_join_meeting(self, token, **kwargs):
|
||||||
|
event = request.env['calendar.event'].sudo().search([
|
||||||
|
('access_token', '=', token)])
|
||||||
|
if not event:
|
||||||
|
return request.not_found()
|
||||||
|
event.action_join_meeting(request.env.user.partner_id.id)
|
||||||
|
attendee = request.env['calendar.attendee'].sudo().search([('partner_id', '=', request.env.user.partner_id.id), ('event_id', '=', event.id)])
|
||||||
|
return request.redirect('/calendar/meeting/view?token=%s&id=%s' % (attendee.access_token, event.id))
|
||||||
|
|
||||||
|
# Function used, in RPC to check every 5 minutes, if notification to do for an event or not
|
||||||
|
@http.route('/calendar/notify', type='json', auth="user")
|
||||||
|
def notify(self):
|
||||||
|
return request.env['calendar.alarm_manager'].get_next_notif()
|
||||||
|
|
||||||
|
@http.route('/calendar/notify_ack', type='json', auth="user")
|
||||||
|
def notify_ack(self):
|
||||||
|
return request.env['res.partner'].sudo()._set_calendar_last_notif_ack()
|
||||||
|
|
||||||
|
@http.route('/calendar/join_videocall/<string:access_token>', type='http', auth='public')
|
||||||
|
def calendar_join_videocall(self, access_token):
|
||||||
|
event = request.env['calendar.event'].sudo().search([('access_token', '=', access_token)])
|
||||||
|
if not event:
|
||||||
|
return request.not_found()
|
||||||
|
|
||||||
|
# if channel doesn't exist
|
||||||
|
if not event.videocall_channel_id:
|
||||||
|
event._create_videocall_channel()
|
||||||
|
|
||||||
|
return request.redirect(event.videocall_channel_id.invitation_url)
|
||||||
|
|
||||||
|
@http.route('/calendar/check_credentials', type='json', auth='user')
|
||||||
|
def check_calendar_credentials(self):
|
||||||
|
# method should be overwritten by sync providers
|
||||||
|
return request.env['res.users'].check_calendar_credentials()
|
18
data/calendar_cron.xml
Normal file
18
data/calendar_cron.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- Scheduler for Event Alarm-->
|
||||||
|
<record forcecreate="True" id="ir_cron_scheduler_alarm" model="ir.cron">
|
||||||
|
<field name="name">Calendar: Event Reminder</field>
|
||||||
|
<field name="model_id" ref="model_calendar_alarm_manager"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model._send_reminder()</field>
|
||||||
|
<field eval="True" name="active" />
|
||||||
|
<field name="user_id" ref="base.user_root" />
|
||||||
|
<field name="interval_number">1</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="numbercall">-1</field>
|
||||||
|
<field eval="False" name="doall" />
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
49
data/calendar_data.xml
Normal file
49
data/calendar_data.xml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record id="alarm_notif_1" model="calendar.alarm">
|
||||||
|
<field name="name">Notification - 15 Minutes</field>
|
||||||
|
<field name="duration" eval="15" />
|
||||||
|
<field name="interval">minutes</field>
|
||||||
|
<field name="alarm_type">notification</field>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_notif_2" model="calendar.alarm">
|
||||||
|
<field name="name">Notification - 30 Minutes</field>
|
||||||
|
<field name="duration" eval="30" />
|
||||||
|
<field name="interval">minutes</field>
|
||||||
|
<field name="alarm_type">notification</field>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_notif_3" model="calendar.alarm">
|
||||||
|
<field name="name">Notification - 1 Hours</field>
|
||||||
|
<field name="duration" eval="1" />
|
||||||
|
<field name="interval">hours</field>
|
||||||
|
<field name="alarm_type">notification</field>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_notif_4" model="calendar.alarm">
|
||||||
|
<field name="name">Notification - 2 Hours</field>
|
||||||
|
<field name="duration" eval="2" />
|
||||||
|
<field name="interval">hours</field>
|
||||||
|
<field name="alarm_type">notification</field>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_notif_5" model="calendar.alarm">
|
||||||
|
<field name="name">Notification - 1 Days</field>
|
||||||
|
<field name="duration" eval="1" />
|
||||||
|
<field name="interval">days</field>
|
||||||
|
<field name="alarm_type">notification</field>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_mail_1" model="calendar.alarm">
|
||||||
|
<field name="name">Email - 3 Hours</field>
|
||||||
|
<field name="duration" eval="3" />
|
||||||
|
<field name="interval">hours</field>
|
||||||
|
<field name="alarm_type">email</field>
|
||||||
|
<field name="mail_template_id" ref="calendar.calendar_template_meeting_reminder"/>
|
||||||
|
</record>
|
||||||
|
<record id="alarm_mail_2" model="calendar.alarm">
|
||||||
|
<field name="name">Email - 6 Hours</field>
|
||||||
|
<field name="duration" eval="6" />
|
||||||
|
<field name="interval">hours</field>
|
||||||
|
<field name="alarm_type">email</field>
|
||||||
|
<field name="mail_template_id" ref="calendar.calendar_template_meeting_reminder"/>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
125
data/calendar_demo.xml
Normal file
125
data/calendar_demo.xml
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
|
||||||
|
<record id="cal_contact_1" model="calendar.filters">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
<field name="partner_id" ref="base.res_partner_1"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="cal_contact_2" model="calendar.filters">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
<field name="partner_id" ref="base.partner_demo"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="categ_meet1" model="calendar.event.type">
|
||||||
|
<field name="name">Customer Meeting</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="categ_meet2" model="calendar.event.type">
|
||||||
|
<field name="name">Internal Meeting</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="categ_meet3" model="calendar.event.type">
|
||||||
|
<field name="name">Off-site Meeting</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="categ_meet4" model="calendar.event.type">
|
||||||
|
<field name="name">Open Discussion</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="categ_meet5" model="calendar.event.type">
|
||||||
|
<field name="name">Feedback Meeting</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_1" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.res_partner_1')])]"/>
|
||||||
|
<field name="name">Follow-up for Project proposal</field>
|
||||||
|
<field name="description">Meeting to discuss project plan and hash out the details of implementation.</field>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-03 10:20:00')"/>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1')])]"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-03 16:30:00')"/>
|
||||||
|
<field name="duration" eval="6.3"/>
|
||||||
|
<field name="allday" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_2" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_demo"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.partner_root'),ref('base.res_partner_4'),ref('base.res_partner_3')])]"/>
|
||||||
|
<field name="name">Initial discussion</field>
|
||||||
|
<field name="description">Discussion with partner for product.</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet3')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-05 12:00:00')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-05 19:00:00')"/>
|
||||||
|
<field name="allday" eval="False"/>
|
||||||
|
<field name="duration" eval="7.0"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_3" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.partner_admin')])]"/>
|
||||||
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
<field name="name">Pricing Discussion</field>
|
||||||
|
<field name="description">Internal meeting for discussion for new pricing for product and services.</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1'), ref('categ_meet2')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-12 15:55:05')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-12 18:55:05')"/>
|
||||||
|
<field name="duration" eval="3.0"/>
|
||||||
|
<field name="allday" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_4" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_demo"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.partner_demo'),ref('base.res_partner_1')])]"/>
|
||||||
|
<field name="name">Requirements review</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet3')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-20 08:00:00')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-20 10:30:00')"/>
|
||||||
|
<field name="duration" eval="2.5"/>
|
||||||
|
<field name="allday" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_5" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.partner_admin'),ref('base.res_partner_12')])]"/>
|
||||||
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
<field name="name">Changes in Designing</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-22')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-22')"/>
|
||||||
|
<field name="allday" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_6" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_demo"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.partner_root'),ref('base.res_partner_4'),ref('base.res_partner_1'),ref('base.res_partner_12')])]"/>
|
||||||
|
<field name="name">Presentation for new Services</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1'), ref('categ_meet2')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-18 02:00:00')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-18 10:30:00')"/>
|
||||||
|
<field name="duration" eval="8.5"/>
|
||||||
|
<field name="allday" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_event_7" model="calendar.event">
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
<field name="user_id" ref="base.user_demo"/>
|
||||||
|
<field name="partner_ids" eval="[(6,0,[ref('base.res_partner_4')])]"/>
|
||||||
|
<field name="name">Presentation of the new Calendar</field>
|
||||||
|
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1'), ref('categ_meet2')])]"/>
|
||||||
|
<field name="start" eval="time.strftime('%Y-%m-16')"/>
|
||||||
|
<field name="stop" eval="time.strftime('%Y-%m-16')"/>
|
||||||
|
<field name="duration" eval="8.5"/>
|
||||||
|
<field name="allday" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
24
data/calendar_onboarding_data.xml
Normal file
24
data/calendar_onboarding_data.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- ONBOARDING STEPS -->
|
||||||
|
<record id="onboarding_onboarding_step_setup_calendar_integration" model="onboarding.onboarding.step">
|
||||||
|
<field name="title">Connect your calendar</field>
|
||||||
|
<field name="description">With Outlook or Google</field>
|
||||||
|
<field name="button_text">Add</field>
|
||||||
|
<field name="done_text">Done!</field>
|
||||||
|
<field name="panel_step_open_action_name">action_view_start_calendar_sync</field>
|
||||||
|
<field name="step_image" type="base64" file="base/static/img/onboarding_calendar.png"></field>
|
||||||
|
<field name="step_image_filename">onboarding_calendar.png</field>
|
||||||
|
<field name="step_image_alt">Onboarding Calendar Synchronization</field>
|
||||||
|
<field name="sequence">1</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="onboarding_onboarding_calendar" model="onboarding.onboarding">
|
||||||
|
<field name="name">Calendar Onboarding</field>
|
||||||
|
<field name="step_ids" eval="[(4, ref('calendar.onboarding_onboarding_step_setup_calendar_integration'))]"/>
|
||||||
|
<field name="panel_close_action_name">action_close_calendar_onboarding</field>
|
||||||
|
<field name="route_name">calendar</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
8
data/mail_activity_type_data.xml
Normal file
8
data/mail_activity_type_data.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record id="mail.mail_activity_data_meeting" model="mail.activity.type">
|
||||||
|
<field name="category">meeting</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
11
data/mail_message_subtype_data.xml
Normal file
11
data/mail_message_subtype_data.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record id="calendar.subtype_invitation" model="mail.message.subtype">
|
||||||
|
<field name="name">Invitation</field>
|
||||||
|
<field name="res_model">calendar.event</field>
|
||||||
|
<field name="description" eval="False"/>
|
||||||
|
<field name="default" eval="False"/>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
451
data/mail_template_data.xml
Normal file
451
data/mail_template_data.xml
Normal file
|
@ -0,0 +1,451 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<record id="calendar_template_meeting_invitation" model="mail.template">
|
||||||
|
<field name="name">Calendar: Meeting Invitation</field>
|
||||||
|
<field name="model_id" ref="calendar.model_calendar_attendee"/>
|
||||||
|
<field name="subject">Invitation to {{ object.event_id.name }}</field>
|
||||||
|
<field name="email_from">{{ (object.event_id.user_id.email_formatted or user.email_formatted or '') }}</field>
|
||||||
|
<field name="email_to">{{ ('' if object.partner_id.email and object.partner_id.email == object.email else object.email) }}</field>
|
||||||
|
<field name="partner_to">{{ object.partner_id.id if object.partner_id.email and object.partner_id.email == object.email else False }}</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="description">Invitation email to new attendees</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<t t-set="colors" t-value="{'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}"/>
|
||||||
|
<t t-set="customer" t-value=" object.event_id.find_partner_customer()"/>
|
||||||
|
<t t-set="target_responsible" t-value="object.partner_id == object.event_id.partner_id"/>
|
||||||
|
<t t-set="target_customer" t-value="object.partner_id == customer"/>
|
||||||
|
<t t-set="recurrent" t-value="object.recurrence_id and not ctx.get('calendar_template_ignore_recurrence')"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello <t t-out="object.common_name or ''">Wood Corner</t>,<br/><br/>
|
||||||
|
|
||||||
|
<t t-if="not target_responsible">
|
||||||
|
<t t-out="object.event_id.user_id.partner_id.name or ''">Colleen Diaz</t> invited you for the <strong t-out="object.event_id.name or ''">Follow-up for Project proposal</strong> meeting.
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
Your meeting <strong t-out="object.event_id.name or ''">Follow-up for Project proposal</strong> has been booked.
|
||||||
|
</t>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<div style="text-align: center; padding: 16px 0px 16px 0px;">
|
||||||
|
<a t-attf-href="/calendar/meeting/accept?token={{object.access_token}}&id={{object.event_id.id}}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Accept</a>
|
||||||
|
<a t-attf-href="/calendar/meeting/decline?token={{object.access_token}}&id={{object.event_id.id}}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Decline</a>
|
||||||
|
<a t-attf-href="/calendar/meeting/view?token={{object.access_token}}&id={{object.event_id.id}}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px"
|
||||||
|
>View</a>
|
||||||
|
</div>
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||||
|
<td width="130px;" style="min-width: 130px;">
|
||||||
|
<div style="border-top-start-radius: 3px; border-top-end-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format='EEEE', lang_code=object.env.lang) or ''">Tuesday</t>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 48px; min-height: auto; font-weight: bold; text-align: center; color: #5F5F5F; background-color: #F8F8F8; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format='d', lang_code=object.env.lang) or ''">4</t>
|
||||||
|
</div>
|
||||||
|
<div style='font-size: 12px; text-align: center; font-weight: bold; color: #ffffff; background-color: #875A7B;'>
|
||||||
|
<t t-out="format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format='MMMM y', lang_code=object.env.lang) or ''">May 2021</t>
|
||||||
|
</div>
|
||||||
|
<div style="border-collapse: separate; color: #5F5F5F; text-align: center; font-size: 12px; border-bottom-end-radius: 3px; font-weight: bold ; border: 1px solid #875A7B; border-bottom-start-radius: 3px;">
|
||||||
|
<t t-if="not object.event_id.allday">
|
||||||
|
<div>
|
||||||
|
<t t-out="format_time(time=object.event_id.start, tz=object.mail_tz, time_format='short', lang_code=object.env.lang) or ''">11:00 AM</t>
|
||||||
|
</div>
|
||||||
|
<t t-if="object.mail_tz">
|
||||||
|
<div style="font-size: 10px; font-weight: normal">
|
||||||
|
(<t t-out="object.mail_tz or ''">Europe/Brussels</t>)
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="20px;"/>
|
||||||
|
<td style="padding-top: 5px;">
|
||||||
|
<p><strong>Details of the event</strong></p>
|
||||||
|
<ul>
|
||||||
|
<t t-if="object.event_id.location">
|
||||||
|
<li>Location: <t t-out="object.event_id.location or ''">Bruxelles</t>
|
||||||
|
(<a target="_blank" t-attf-href="http://maps.google.com/maps?oi=map&q={{object.event_id.location}}">View Map</a>)
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="recurrent">
|
||||||
|
<li>When: <t t-out="object.recurrence_id.get_recurrence_name()">Every 1 Weeks, for 3 events</t></li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not object.event_id.allday and object.event_id.duration">
|
||||||
|
<li>Duration: <t t-out="('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60)) or ''">0H30</t></li>
|
||||||
|
</t>
|
||||||
|
<li>Attendees
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="object.event_id.attendee_ids" t-as="attendee">
|
||||||
|
<div t-attf-style="display: inline-block; border-radius: 50%; width: 10px; height: 10px; background:{{ colors.get(attendee.state) or 'white' }};"> </div>
|
||||||
|
<t t-if="attendee.common_name != object.common_name">
|
||||||
|
<span style="margin-left:5px" t-out="attendee.common_name or ''">Mitchell Admin</span>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<span style="margin-left:5px">You</span>
|
||||||
|
</t>
|
||||||
|
</li>
|
||||||
|
</ul></li>
|
||||||
|
<t t-if="object.event_id.videocall_location">
|
||||||
|
<li>
|
||||||
|
How to Join:
|
||||||
|
<t t-if="object.get_base_url() in object.event_id.videocall_location"> Join with Odoo Discuss</t>
|
||||||
|
<t t-else=""> Join at</t><br/>
|
||||||
|
<a t-att-href="object.event_id.videocall_location" target="_blank" t-out="object.event_id.videocall_location or ''">www.mycompany.com/calendar/join_videocall/xyz</a>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not is_html_empty(object.event_id.description)">
|
||||||
|
<li>Description of the event:
|
||||||
|
<t t-out="object.event_id.description">Internal meeting for discussion for new pricing for product and services.</t></li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr></table>
|
||||||
|
<br/>
|
||||||
|
Thank you,
|
||||||
|
<t t-if="object.event_id.user_id.signature">
|
||||||
|
<br />
|
||||||
|
<t t-out="object.event_id.user_id.signature or ''">--<br/>Mitchell Admin</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_template_meeting_changedate" model="mail.template">
|
||||||
|
<field name="name">Calendar: Date Updated</field>
|
||||||
|
<field name="model_id" ref="calendar.model_calendar_attendee"/>
|
||||||
|
<field name="subject">{{ object.event_id.name }}: Date updated</field>
|
||||||
|
<field name="email_from">{{ (object.event_id.user_id.email_formatted or user.email_formatted or '') }}</field>
|
||||||
|
<field name="email_to">{{ ('' if object.partner_id.email and object.partner_id.email == object.email else object.email) }}</field>
|
||||||
|
<field name="partner_to">{{ object.partner_id.id if object.partner_id.email and object.partner_id.email == object.email else False }}</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="description">Sent to all attendees if the schedule change</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<t t-set="colors" t-value="{'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}"/>
|
||||||
|
<t t-set="is_online" t-value="'appointment_type_id' in object.event_id and object.event_id.appointment_type_id"/>
|
||||||
|
<t t-set="customer" t-value="object.event_id.find_partner_customer()"/>
|
||||||
|
<t t-set="target_responsible" t-value="object.partner_id == object.event_id.partner_id"/>
|
||||||
|
<t t-set="target_customer" t-value="object.partner_id == customer"/>
|
||||||
|
<t t-set="recurrent" t-value="object.recurrence_id and not ctx.get('calendar_template_ignore_recurrence')"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello <t t-out="object.common_name or ''">Ready Mat</t>,<br/><br/>
|
||||||
|
<t t-if="is_online and target_responsible">
|
||||||
|
<t t-if="customer">
|
||||||
|
The date of your appointment with <t t-out="customer.name or ''">Jesse Brown</t> has been updated.
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
Your appointment has been updated.
|
||||||
|
</t>
|
||||||
|
The appointment <strong t-out="object.event_id.appointment_type_id.name or ''">Schedule a Demo</strong> is now scheduled for
|
||||||
|
<t t-out="object.event_id.get_display_time_tz(tz=object.partner_id.tz) or ''">05/04/2021 at (11:00:00 To 11:30:00) (Europe/Brussels)</t>
|
||||||
|
</t>
|
||||||
|
<t t-elif="is_online and target_customer">
|
||||||
|
The date of your appointment with <t t-out="object.event_id.user_id.partner_id.name or ''">Colleen Diaz</t> has been updated.
|
||||||
|
The appointment <strong t-out="object.event_id.appointment_type_id.name or ''"></strong> is now scheduled for
|
||||||
|
<t t-out="object.event_id.get_display_time_tz(tz=object.partner_id.tz) or ''">05/04/2021 at (11:00:00 To 11:30:00) (Europe/Brussels)</t>.
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
The date of the meeting has been updated.
|
||||||
|
The meeting <strong t-out="object.event_id.name or ''">Follow-up for Project proposal</strong> created by <t t-out="object.event_id.user_id.partner_id.name or ''">Colleen Diaz</t> is now scheduled for
|
||||||
|
<t t-out="object.event_id.get_display_time_tz(tz=object.partner_id.tz) or ''">05/04/2021 at (11:00:00 To 11:30:00) (Europe/Brussels)</t>.
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<div style="text-align: center; padding: 16px 0px 16px 0px;">
|
||||||
|
<a t-attf-href="/calendar/meeting/accept?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Accept</a>
|
||||||
|
<a t-attf-href="/calendar/meeting/decline?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Decline</a>
|
||||||
|
<a t-attf-href="/calendar/meeting/view?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
View</a>
|
||||||
|
</div>
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||||
|
<td width="130px;" style="min-width: 130px;">
|
||||||
|
<div style="border-top-start-radius: 3px; border-top-end-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||||
|
<t t-out='format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format="EEEE", lang_code=object.env.lang) or ""'>Tuesday</t>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 48px; min-height: auto; font-weight: bold; text-align: center; color: #5F5F5F; background-color: #F8F8F8; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format='d', lang_code=object.env.lang) or ''">4</t>
|
||||||
|
</div>
|
||||||
|
<div style='font-size: 12px; text-align: center; font-weight: bold; color: #ffffff; background-color: #875A7B;'>
|
||||||
|
<t t-out='format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format="MMMM y", lang_code=object.env.lang) or ""'>May 2021</t>
|
||||||
|
</div>
|
||||||
|
<div style="border-collapse: separate; color: #5F5F5F; text-align: center; font-size: 12px; border-bottom-end-radius: 3px; font-weight: bold; border: 1px solid #875A7B; border-bottom-start-radius: 3px;">
|
||||||
|
<t t-if="not object.event_id.allday">
|
||||||
|
<div>
|
||||||
|
<t t-out='format_time(time=object.event_id.start, tz=object.mail_tz, time_format="short", lang_code=object.env.lang) or ""'>11:00 AM</t>
|
||||||
|
</div>
|
||||||
|
<t t-if="object.mail_tz">
|
||||||
|
<div style="font-size: 10px; font-weight: normal">
|
||||||
|
(<t t-out="object.mail_tz or ''">Europe/Brussels</t>)
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="20px;"/>
|
||||||
|
<td style="padding-top: 5px;">
|
||||||
|
<p><strong>Details of the event</strong></p>
|
||||||
|
<ul>
|
||||||
|
<t t-if="object.event_id.location">
|
||||||
|
<li>Location: <t t-out="object.event_id.location or ''">Bruxelles</t>
|
||||||
|
(<a target="_blank" t-attf-href="http://maps.google.com/maps?oi=map&q={{ object.event_id.location }}">View Map</a>)
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="recurrent">
|
||||||
|
<li>When: <t t-out="object.recurrence_id.get_recurrence_name()">Every 1 Weeks, for 3 events</t></li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not object.event_id.allday and object.event_id.duration">
|
||||||
|
<li>Duration: <t t-out="('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60)) or ''">0H30</t></li>
|
||||||
|
</t>
|
||||||
|
<li>Attendees
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="object.event_id.attendee_ids" t-as="attendee">
|
||||||
|
<div t-attf-style="display: inline-block; border-radius: 50%; width: 10px; height: 10px; background: {{ colors.get(attendee.state) or 'white' }};"> </div>
|
||||||
|
<t t-if="attendee.common_name != object.common_name">
|
||||||
|
<span style="margin-left:5px" t-out="attendee.common_name or ''">Mitchell Admin</span>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<span style="margin-left:5px">You</span>
|
||||||
|
</t>
|
||||||
|
</li>
|
||||||
|
</ul></li>
|
||||||
|
<t t-if="object.event_id.videocall_location">
|
||||||
|
<li>
|
||||||
|
How to Join:
|
||||||
|
<t t-if="object.get_base_url() in object.event_id.videocall_location"> Join with Odoo Discuss</t>
|
||||||
|
<t t-else=""> Join at</t><br/>
|
||||||
|
<a t-att-href="object.event_id.videocall_location" target="_blank" t-out="object.event_id.videocall_location or ''">www.mycompany.com/calendar/join_videocall/xyz</a>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not is_html_empty(object.event_id.description)">
|
||||||
|
<li>Description of the event:
|
||||||
|
<t t-out="object.event_id.description">Internal meeting for discussion for new pricing for product and services.</t></li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr></table>
|
||||||
|
<br/>
|
||||||
|
Thank you,
|
||||||
|
<t t-if="object.event_id.user_id.signature">
|
||||||
|
<br />
|
||||||
|
<t t-out="object.event_id.user_id.signature or ''">--<br/>Mitchell Admin</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_template_meeting_reminder" model="mail.template">
|
||||||
|
<field name="name">Calendar: Reminder</field>
|
||||||
|
<field name="model_id" ref="calendar.model_calendar_attendee"/>
|
||||||
|
<field name="subject">{{ object.event_id.name }} - Reminder</field>
|
||||||
|
<field name="email_from">{{ (object.event_id.user_id.email_formatted or user.email_formatted or '') }}</field>
|
||||||
|
<field name="email_to">{{ ('' if object.partner_id.email and object.partner_id.email == object.email else object.email) }}</field>
|
||||||
|
<field name="partner_to">{{ object.partner_id.id if object.partner_id.email and object.partner_id.email == object.email else False }}</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="description">Sent to all attendees if a reminder is set</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<t t-set="colors" t-value="{'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}" />
|
||||||
|
<t t-set="is_online" t-value="'appointment_type_id' in object.event_id and object.event_id.appointment_type_id" />
|
||||||
|
<t t-set="recurrent" t-value="object.recurrence_id and not ctx.get('calendar_template_ignore_recurrence')" />
|
||||||
|
<p>
|
||||||
|
Hello <t t-out="object.common_name or ''">Gemini Furniture</t>,<br/><br/>
|
||||||
|
This is a reminder for the below event:
|
||||||
|
</p>
|
||||||
|
<div style="text-align: center; padding: 16px 0px 16px 0px;">
|
||||||
|
<a t-attf-href="/calendar/{{ 'recurrence' if recurrent else 'meeting' }}/accept?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Accept</a>
|
||||||
|
<a t-attf-href="/calendar/{{ 'recurrence' if recurrent else 'meeting' }}/decline?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
Decline</a>
|
||||||
|
<a t-attf-href="/calendar/meeting/view?token={{ object.access_token }}&id={{ object.event_id.id }}"
|
||||||
|
style="padding: 5px 10px; color: #FFFFFF; text-decoration: none; background-color: #875A7B; border: 1px solid #875A7B; border-radius: 3px">
|
||||||
|
View</a>
|
||||||
|
</div>
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0"><tr>
|
||||||
|
<td width="130px;" style="min-width: 130px;">
|
||||||
|
<div style="border-top-start-radius: 3px; border-top-end-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||||
|
<t t-out='format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format="EEEE", lang_code=object.env.lang) or ""'>Tuesday</t>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 48px; min-height: auto; font-weight: bold; text-align: center; color: #5F5F5F; background-color: #F8F8F8; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format='d', lang_code=object.env.lang) or ''">4</t>
|
||||||
|
</div>
|
||||||
|
<div style='font-size: 12px; text-align: center; font-weight: bold; color: #ffffff; background-color: #875A7B;'>
|
||||||
|
<t t-out='format_datetime(dt=object.event_id.start, tz=object.mail_tz if not object.event_id.allday else None, dt_format="MMMM y", lang_code=object.env.lang) or ""'>May 2021</t>
|
||||||
|
</div>
|
||||||
|
<div style="border-collapse: separate; color: #5F5F5F; text-align: center; font-size: 12px; border-bottom-end-radius: 3px; font-weight: bold; border: 1px solid #875A7B; border-bottom-start-radius: 3px;">
|
||||||
|
<t t-if="not object.event_id.allday">
|
||||||
|
<div>
|
||||||
|
<t t-out='format_time(time=object.event_id.start, tz=object.mail_tz, time_format="short", lang_code=object.env.lang) or ""'>11:00 AM</t>
|
||||||
|
</div>
|
||||||
|
<t t-if="object.mail_tz">
|
||||||
|
<div style="font-size: 10px; font-weight: normal">
|
||||||
|
(<t t-out="object.mail_tz or ''">Europe/Brussels</t>)
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="20px;"/>
|
||||||
|
<td style="padding-top: 5px;">
|
||||||
|
<p><strong>Details of the event</strong></p>
|
||||||
|
<ul>
|
||||||
|
<t t-if="object.event_id.location">
|
||||||
|
<li>Location: <t t-out="object.event_id.location or ''">Bruxelles</t>
|
||||||
|
(<a target="_blank" t-attf-href="http://maps.google.com/maps?oi=map&q={{ object.event_id.location }}">View Map</a>)
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="recurrent">
|
||||||
|
<li>When: <t t-out="object.recurrence_id.get_recurrence_name()">Every 1 Weeks, for 3 events</t></li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not object.event_id.allday and object.event_id.duration">
|
||||||
|
<li>Duration: <t t-out="('%dH%02d' % (object.event_id.duration,round(object.event_id.duration*60)%60)) or ''">0H30</t></li>
|
||||||
|
</t>
|
||||||
|
<li>Attendees
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="object.event_id.attendee_ids" t-as="attendee">
|
||||||
|
<div t-attf-style="display: inline-block; border-radius: 50%; width: 10px; height: 10px; background:{{ colors.get(attendee.state) or 'white' }};"> </div>
|
||||||
|
<t t-if="attendee.common_name != object.common_name">
|
||||||
|
<span style="margin-left:5px" t-out="attendee.common_name or ''">Mitchell Admin</span>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<span style="margin-left:5px">You</span>
|
||||||
|
</t>
|
||||||
|
</li>
|
||||||
|
</ul></li>
|
||||||
|
<t t-if="object.event_id.videocall_location">
|
||||||
|
<li>
|
||||||
|
How to Join:
|
||||||
|
<t t-if="object.get_base_url() in object.event_id.videocall_location"> Join with Odoo Discuss</t>
|
||||||
|
<t t-else=""> Join at</t><br/>
|
||||||
|
<a t-att-href="object.event_id.videocall_location" target="_blank" t-out="object.event_id.videocall_location or ''">www.mycompany.com/calendar/join_videocall/xyz</a>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not is_html_empty(object.event_id.description)">
|
||||||
|
<li>Description of the event:
|
||||||
|
<t t-out="object.event_id.description">Internal meeting for discussion for new pricing for product and services.</t></li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr></table>
|
||||||
|
<br/>
|
||||||
|
Thank you,
|
||||||
|
<t t-if="object.event_id.user_id.signature">
|
||||||
|
<br />
|
||||||
|
<t t-out="object.event_id.user_id.signature or ''">--<br/>Mitchell Admin</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="calendar_template_meeting_update" model="mail.template">
|
||||||
|
<field name="name">Calendar: Event Update</field>
|
||||||
|
<field name="model_id" ref="calendar.model_calendar_event"/>
|
||||||
|
<field name="subject">{{object.name}}: Event update</field>
|
||||||
|
<field name="email_from">{{ (object.user_id.email_formatted or user.email_formatted or '') }}</field>
|
||||||
|
<field name="email_to">{{ object._get_attendee_emails() }}</field>
|
||||||
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||||
|
<field name="description">Used to manually notifiy attendees</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<t t-set="colors" t-value="{'needsAction': 'grey', 'accepted': 'green', 'tentative': '#FFFF00', 'declined': 'red'}" />
|
||||||
|
<t t-set="is_online" t-value="'appointment_type_id' in object and object.appointment_type_id" />
|
||||||
|
<t t-set="target_responsible" t-value="object.partner_id == object.partner_id" />
|
||||||
|
<t t-set="target_customer" t-value="object.partner_id == customer" />
|
||||||
|
<t t-set="recurrent" t-value="object.recurrence_id and not ctx.get('calendar_template_ignore_recurrence')" />
|
||||||
|
<t t-set="mail_tz" t-value="object._get_mail_tz() or ctx.get('mail_tz')" />
|
||||||
|
<div>
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<td width="130px;" style="min-width: 130px;">
|
||||||
|
<div style="border-top-start-radius: 3px; border-top-end-radius: 3px; font-size: 12px; border-collapse: separate; text-align: center; font-weight: bold; color: #ffffff; min-height: 18px; background-color: #875A7B; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.start, tz=mail_tz if not object.allday else None, dt_format='EEEE', lang_code=object.env.lang) ">Tuesday</t>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 48px; min-height: auto; font-weight: bold; text-align: center; color: #5F5F5F; background-color: #F8F8F8; border: 1px solid #875A7B;">
|
||||||
|
<t t-out="format_datetime(dt=object.start, tz=mail_tz if not object.allday else None, dt_format='d', lang_code=object.env.lang)">4</t>
|
||||||
|
</div>
|
||||||
|
<div style='font-size: 12px; text-align: center; font-weight: bold; color: #ffffff; background-color: #875A7B;'>
|
||||||
|
<t t-out="format_datetime(dt=object.start, tz=mail_tz if not object.allday else None, dt_format='MMMM y', lang_code=object.env.lang)">May 2021</t>
|
||||||
|
</div>
|
||||||
|
<div style="border-collapse: separate; color: #5F5F5F; text-align: center; font-size: 12px; border-bottom-end-radius: 3px; font-weight: bold; border: 1px solid #875A7B; border-bottom-start-radius: 3px;">
|
||||||
|
<t t-if="not object.allday">
|
||||||
|
<div>
|
||||||
|
<t t-out="format_time(time=object.start, tz=mail_tz, time_format='short', lang_code=object.env.lang)">11:00 AM</t>
|
||||||
|
</div>
|
||||||
|
<t t-if="mail_tz">
|
||||||
|
<div style="font-size: 10px; font-weight: normal">
|
||||||
|
(<t t-out="mail_tz"> Europe/Brussels</t>)
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="20px;"/>
|
||||||
|
<td style="padding-top: 5px;">
|
||||||
|
<p>
|
||||||
|
<strong>Details of the event</strong>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<t t-if="not is_html_empty(object.description)">
|
||||||
|
<li>Description:
|
||||||
|
<t t-out="object.description">Internal meeting for discussion for new pricing for product and services.</t></li>
|
||||||
|
</t>
|
||||||
|
<t t-if="object.videocall_location">
|
||||||
|
<li>
|
||||||
|
How to Join:
|
||||||
|
<t t-if="object.get_base_url() in object.videocall_location"> Join with Odoo Discuss</t>
|
||||||
|
<t t-else=""> Join at</t><br/>
|
||||||
|
<a t-att-href="object.videocall_location" target="_blank" t-out="object.videocall_location or ''">www.mycompany.com/calendar/join_videocall/xyz</a>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="object.location">
|
||||||
|
<li>Location: <t t-out="object.location or ''">Bruxelles</t>
|
||||||
|
(<a target="_blank"
|
||||||
|
t-attf-href="http://maps.google.com/maps?oi=map&q={{object.location}}">View Map</a>)
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-if="recurrent">
|
||||||
|
<li>When: <t t-out="object.recurrence_id.get_recurrence_name()">Every 1 Weeks, for 3 events</t></li>
|
||||||
|
</t>
|
||||||
|
<t t-if="not object.allday and object.duration">
|
||||||
|
<li>Duration:
|
||||||
|
<t t-out="('%dH%02d' % (object.duration,round(object.duration*60)%60))">0H30</t>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="user_input">
|
||||||
|
<hr/>
|
||||||
|
<p placeholder="Enter your message here"><br/></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<t t-if="object.user_id.signature">
|
||||||
|
<br />
|
||||||
|
<t t-out="object.user_id.signature or ''">--<br/>Mitchell Admin</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
2367
i18n/af.po
Normal file
2367
i18n/af.po
Normal file
File diff suppressed because it is too large
Load Diff
2363
i18n/am.po
Normal file
2363
i18n/am.po
Normal file
File diff suppressed because it is too large
Load Diff
3045
i18n/ar.po
Normal file
3045
i18n/ar.po
Normal file
File diff suppressed because it is too large
Load Diff
2371
i18n/az.po
Normal file
2371
i18n/az.po
Normal file
File diff suppressed because it is too large
Load Diff
2621
i18n/bg.po
Normal file
2621
i18n/bg.po
Normal file
File diff suppressed because it is too large
Load Diff
2365
i18n/bn.po
Normal file
2365
i18n/bn.po
Normal file
File diff suppressed because it is too large
Load Diff
2368
i18n/bs.po
Normal file
2368
i18n/bs.po
Normal file
File diff suppressed because it is too large
Load Diff
2656
i18n/ca.po
Normal file
2656
i18n/ca.po
Normal file
File diff suppressed because it is too large
Load Diff
2599
i18n/calendar.pot
Normal file
2599
i18n/calendar.pot
Normal file
File diff suppressed because it is too large
Load Diff
2631
i18n/cs.po
Normal file
2631
i18n/cs.po
Normal file
File diff suppressed because it is too large
Load Diff
3045
i18n/da.po
Normal file
3045
i18n/da.po
Normal file
File diff suppressed because it is too large
Load Diff
3059
i18n/de.po
Normal file
3059
i18n/de.po
Normal file
File diff suppressed because it is too large
Load Diff
2372
i18n/el.po
Normal file
2372
i18n/el.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/en_GB.po
Normal file
2366
i18n/en_GB.po
Normal file
File diff suppressed because it is too large
Load Diff
3062
i18n/es.po
Normal file
3062
i18n/es.po
Normal file
File diff suppressed because it is too large
Load Diff
3066
i18n/es_419.po
Normal file
3066
i18n/es_419.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_BO.po
Normal file
2366
i18n/es_BO.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_CL.po
Normal file
2366
i18n/es_CL.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_CO.po
Normal file
2366
i18n/es_CO.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_CR.po
Normal file
2366
i18n/es_CR.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_DO.po
Normal file
2366
i18n/es_DO.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_EC.po
Normal file
2366
i18n/es_EC.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_PE.po
Normal file
2366
i18n/es_PE.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_PY.po
Normal file
2366
i18n/es_PY.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/es_VE.po
Normal file
2366
i18n/es_VE.po
Normal file
File diff suppressed because it is too large
Load Diff
2637
i18n/et.po
Normal file
2637
i18n/et.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/eu.po
Normal file
2366
i18n/eu.po
Normal file
File diff suppressed because it is too large
Load Diff
2629
i18n/fa.po
Normal file
2629
i18n/fa.po
Normal file
File diff suppressed because it is too large
Load Diff
3066
i18n/fi.po
Normal file
3066
i18n/fi.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/fo.po
Normal file
2366
i18n/fo.po
Normal file
File diff suppressed because it is too large
Load Diff
3063
i18n/fr.po
Normal file
3063
i18n/fr.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/fr_BE.po
Normal file
2366
i18n/fr_BE.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/fr_CA.po
Normal file
2366
i18n/fr_CA.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/gl.po
Normal file
2366
i18n/gl.po
Normal file
File diff suppressed because it is too large
Load Diff
2367
i18n/gu.po
Normal file
2367
i18n/gu.po
Normal file
File diff suppressed because it is too large
Load Diff
2634
i18n/he.po
Normal file
2634
i18n/he.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/hi.po
Normal file
2366
i18n/hi.po
Normal file
File diff suppressed because it is too large
Load Diff
2384
i18n/hr.po
Normal file
2384
i18n/hr.po
Normal file
File diff suppressed because it is too large
Load Diff
2624
i18n/hu.po
Normal file
2624
i18n/hu.po
Normal file
File diff suppressed because it is too large
Load Diff
2599
i18n/hy.po
Normal file
2599
i18n/hy.po
Normal file
File diff suppressed because it is too large
Load Diff
3051
i18n/id.po
Normal file
3051
i18n/id.po
Normal file
File diff suppressed because it is too large
Load Diff
2604
i18n/is.po
Normal file
2604
i18n/is.po
Normal file
File diff suppressed because it is too large
Load Diff
3055
i18n/it.po
Normal file
3055
i18n/it.po
Normal file
File diff suppressed because it is too large
Load Diff
3036
i18n/ja.po
Normal file
3036
i18n/ja.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/ka.po
Normal file
2366
i18n/ka.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/kab.po
Normal file
2366
i18n/kab.po
Normal file
File diff suppressed because it is too large
Load Diff
2368
i18n/km.po
Normal file
2368
i18n/km.po
Normal file
File diff suppressed because it is too large
Load Diff
3035
i18n/ko.po
Normal file
3035
i18n/ko.po
Normal file
File diff suppressed because it is too large
Load Diff
2363
i18n/lb.po
Normal file
2363
i18n/lb.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/lo.po
Normal file
2366
i18n/lo.po
Normal file
File diff suppressed because it is too large
Load Diff
2628
i18n/lt.po
Normal file
2628
i18n/lt.po
Normal file
File diff suppressed because it is too large
Load Diff
2630
i18n/lv.po
Normal file
2630
i18n/lv.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/mk.po
Normal file
2366
i18n/mk.po
Normal file
File diff suppressed because it is too large
Load Diff
2383
i18n/mn.po
Normal file
2383
i18n/mn.po
Normal file
File diff suppressed because it is too large
Load Diff
2374
i18n/nb.po
Normal file
2374
i18n/nb.po
Normal file
File diff suppressed because it is too large
Load Diff
2363
i18n/ne.po
Normal file
2363
i18n/ne.po
Normal file
File diff suppressed because it is too large
Load Diff
3061
i18n/nl.po
Normal file
3061
i18n/nl.po
Normal file
File diff suppressed because it is too large
Load Diff
2636
i18n/pl.po
Normal file
2636
i18n/pl.po
Normal file
File diff suppressed because it is too large
Load Diff
2623
i18n/pt.po
Normal file
2623
i18n/pt.po
Normal file
File diff suppressed because it is too large
Load Diff
3053
i18n/pt_BR.po
Normal file
3053
i18n/pt_BR.po
Normal file
File diff suppressed because it is too large
Load Diff
2376
i18n/ro.po
Normal file
2376
i18n/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
3065
i18n/ru.po
Normal file
3065
i18n/ru.po
Normal file
File diff suppressed because it is too large
Load Diff
2622
i18n/sk.po
Normal file
2622
i18n/sk.po
Normal file
File diff suppressed because it is too large
Load Diff
2623
i18n/sl.po
Normal file
2623
i18n/sl.po
Normal file
File diff suppressed because it is too large
Load Diff
2366
i18n/sq.po
Normal file
2366
i18n/sq.po
Normal file
File diff suppressed because it is too large
Load Diff
2640
i18n/sr.po
Normal file
2640
i18n/sr.po
Normal file
File diff suppressed because it is too large
Load Diff
2369
i18n/sr@latin.po
Normal file
2369
i18n/sr@latin.po
Normal file
File diff suppressed because it is too large
Load Diff
3066
i18n/sv.po
Normal file
3066
i18n/sv.po
Normal file
File diff suppressed because it is too large
Load Diff
2627
i18n/th.po
Normal file
2627
i18n/th.po
Normal file
File diff suppressed because it is too large
Load Diff
2649
i18n/tr.po
Normal file
2649
i18n/tr.po
Normal file
File diff suppressed because it is too large
Load Diff
3052
i18n/uk.po
Normal file
3052
i18n/uk.po
Normal file
File diff suppressed because it is too large
Load Diff
3047
i18n/vi.po
Normal file
3047
i18n/vi.po
Normal file
File diff suppressed because it is too large
Load Diff
3033
i18n/zh_CN.po
Normal file
3033
i18n/zh_CN.po
Normal file
File diff suppressed because it is too large
Load Diff
3033
i18n/zh_TW.po
Normal file
3033
i18n/zh_TW.po
Normal file
File diff suppressed because it is too large
Load Diff
18
models/__init__.py
Normal file
18
models/__init__.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import ir_http
|
||||||
|
from . import res_partner
|
||||||
|
from . import calendar_event
|
||||||
|
from . import calendar_alarm
|
||||||
|
from . import calendar_alarm_manager
|
||||||
|
from . import calendar_attendee
|
||||||
|
from . import calendar_filter
|
||||||
|
from . import calendar_event_type
|
||||||
|
from . import calendar_recurrence
|
||||||
|
from . import mail_activity
|
||||||
|
from . import mail_activity_mixin
|
||||||
|
from . import mail_activity_type
|
||||||
|
from . import res_users
|
||||||
|
from . import onboarding_onboarding
|
||||||
|
from . import onboarding_onboarding_step
|
BIN
models/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_alarm.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_alarm.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_alarm_manager.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_alarm_manager.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_attendee.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_attendee.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_event.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_event.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_event_type.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_event_type.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_filter.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_filter.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/calendar_recurrence.cpython-311.pyc
Normal file
BIN
models/__pycache__/calendar_recurrence.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/ir_http.cpython-311.pyc
Normal file
BIN
models/__pycache__/ir_http.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/mail_activity.cpython-311.pyc
Normal file
BIN
models/__pycache__/mail_activity.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/mail_activity_mixin.cpython-311.pyc
Normal file
BIN
models/__pycache__/mail_activity_mixin.cpython-311.pyc
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user