@ -0,0 +1,49 @@ |
|||
.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg |
|||
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html |
|||
:alt: License: LGPL-3 |
|||
|
|||
Odoo ICalender |
|||
============== |
|||
* This module provides iCalendar support. Users can send event invitations with attached .ics files to attendees. |
|||
|
|||
Configuration |
|||
============= |
|||
- www.odoo.com/documentation/16.0/setup/install.html |
|||
- Install our custom addon |
|||
|
|||
License |
|||
------- |
|||
General Public License, Version 3 (LGPL v3). |
|||
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
Developer: (V16) Anusha C , |
|||
(V18) Akhil Ashok, |
|||
Contact : odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit https://www.cybrosys.com |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Akhil (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import models |
@ -0,0 +1,42 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Akhil (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
{ |
|||
"name": "Odoo ICalender", |
|||
"version": "18.0.1.0.0", |
|||
"category": 'Productivity', |
|||
"summary": """Generates ICalendar file & sends to the recipients""", |
|||
"description": """This module provides iCalendar support.Users can send |
|||
event invitations with attached .ics files to attendees.""", |
|||
"author": "Cybrosys Techno Solutions", |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
"depends": ["calendar_sms"], |
|||
"data": ["data/mail_template.xml", |
|||
"data/ir_action_servers_data.xml", |
|||
"views/calendar_event_views.xml"], |
|||
'images': ['static/description/banner.png'], |
|||
'license': 'LGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Adding button in action menu in tree view --> |
|||
<record id="calendar_event_action" model="ir.actions.server"> |
|||
<field name="name">Send ICS File</field> |
|||
<field name="model_id" ref="odoo_icalendar.model_calendar_event"/> |
|||
<field name="binding_model_id" |
|||
ref="odoo_icalendar.model_calendar_event"/> |
|||
<field name="binding_view_types">list</field> |
|||
<field name="state">code</field> |
|||
<field name="code"> |
|||
action = records.action_send_attendee_ics_file() |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,74 @@ |
|||
<odoo> |
|||
<!-- Email template for sending attached ics files having respective event details of each attendee --> |
|||
<record id="odoo_icalendar_email_template" model="mail.template"> |
|||
<field name="name">odoo icalendar: Send by email</field> |
|||
<field name="model_id" ref="odoo_icalendar.model_calendar_event"/> |
|||
<field name="email_from">{{user.email}}</field> |
|||
<field name="subject">Scheduled Meetings</field> |
|||
<field name="body_html" type="html"> |
|||
<div style="font-family: Arial, sans-serif; font-size: 14px;"> |
|||
<p style="margin: 0; padding: 0;"> |
|||
<strong>Hello,</strong> |
|||
</p> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;">You have meetings scheduled. |
|||
Please find the attached ICS file for details. |
|||
</p> |
|||
<br/> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;">Thank you.</p> |
|||
<br/> |
|||
</div> |
|||
</field> |
|||
</record> |
|||
<!-- Email template for sending ics files to attendees of each event--> |
|||
<record id="event_ics_email_template" model="mail.template"> |
|||
<field name="name">Event ICS</field> |
|||
<field name="model_id" ref="odoo_icalendar.model_calendar_event"/> |
|||
<field name="email_from">{{user.email}}</field> |
|||
<field name="subject">{{object.name}}: Event details</field> |
|||
<field name="body_html" type="html"> |
|||
<div style="font-family: Arial, sans-serif; font-size: 14px;"> |
|||
<p style="margin: 0; padding: 0;"> |
|||
<strong>Hello,</strong> |
|||
</p> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;">You are invited to the |
|||
following event: |
|||
</p> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;"> |
|||
<strong>Event Details:</strong> |
|||
</p> |
|||
<ul> |
|||
<li> |
|||
<strong>Summary:</strong> |
|||
<t t-out="object.name"/> |
|||
</li> |
|||
<li> |
|||
<strong>Date and Time:</strong> |
|||
<t t-out="object.start"/> |
|||
to |
|||
<t t-out="object.stop"/> |
|||
</li> |
|||
<li> |
|||
<strong>Location:</strong> |
|||
<t t-out="object.location"/> |
|||
</li> |
|||
<li> |
|||
<strong>Description:</strong> |
|||
<t t-out="object.description"/> |
|||
</li> |
|||
</ul> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;">Please find the attached ICS |
|||
file for more information. |
|||
</p> |
|||
<br/> |
|||
<br/> |
|||
<p style="margin: 0; padding: 0;">Thank you.</p> |
|||
<br/> |
|||
</div> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,5 @@ |
|||
## Module <odoo_icalendar> |
|||
#### 15.03.2025 |
|||
#### Version 18.0.1.0.0 |
|||
#### ADD |
|||
- Initial commit for Odoo ICalender |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Akhil (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import calendar_event |
@ -0,0 +1,161 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Akhil (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import base64 |
|||
import logging |
|||
import pytz |
|||
from datetime import timedelta |
|||
from odoo import fields, models, _ |
|||
from odoo.exceptions import UserError |
|||
from odoo.tools import is_html_empty, html2plaintext |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
try: |
|||
import vobject |
|||
except ImportError: |
|||
_logger.warning( |
|||
"`vobject` Python module not found, iCal file generation disabled. " |
|||
"Consider installing this module if you want to generate iCal files") |
|||
vobject = None |
|||
|
|||
|
|||
class Meeting(models.Model): |
|||
"""This class is to inherit calendar event model redefine mail button |
|||
function and adding an extra button action.""" |
|||
_inherit = 'calendar.event' |
|||
|
|||
def action_send_ics(self): |
|||
"""This function is for sending mail invitations to attendees with |
|||
attached ics file of that event.""" |
|||
attachment_values = {'name': 'Event.ics', |
|||
'type': 'binary', |
|||
'datas': base64.b64encode( |
|||
self._get_ics_file().get(self.id)), |
|||
'mimetype': 'text/calendar', |
|||
'res_model': 'calendar.event', |
|||
'res_id': self.id} |
|||
attachment = self.env['ir.attachment'].sudo().create(attachment_values) |
|||
email_template = self.env.ref('odoo_icalendar.event_ics_email_template') |
|||
email_values = {'email_to': ', '.join( |
|||
attendee.email for attendee in self.partner_ids), |
|||
'attachment_ids': [(4, attachment.id)]} |
|||
email_template.send_mail( |
|||
self.id, email_values=email_values, force_send=True) |
|||
email_template.attachment_ids = [(5, 0, 0)] |
|||
|
|||
def action_send_attendee_ics_file(self): |
|||
"""Button action to send an ics file attached to mail of the |
|||
attendees.""" |
|||
result = {} |
|||
|
|||
def ics_datetime(idate, allday=False): |
|||
"""Format a date and time as an iCalendar-compatible string. |
|||
:param idate: The input date and time. |
|||
:type idate: datetime.datetime |
|||
:param allday: Flag indicating if the event is an all-day event |
|||
(default is False). |
|||
:type allday: bool |
|||
:return: The formatted date and time as a string in the iCalendar |
|||
format. |
|||
:rtype: str or False if idate is None.""" |
|||
if idate: |
|||
if allday: |
|||
return idate |
|||
return idate.replace(tzinfo=pytz.timezone('UTC')) |
|||
return False |
|||
|
|||
if not vobject: |
|||
return result |
|||
attendee_events = {} |
|||
meeting_obj = [] |
|||
for meeting in self: |
|||
meeting_obj = meeting |
|||
for attendee in meeting.partner_ids: |
|||
if attendee.id not in attendee_events: |
|||
attendee_events[attendee.id] = vobject.iCalendar() |
|||
cal = attendee_events[attendee.id] |
|||
event = cal.add('vevent') |
|||
if not meeting.start or not meeting.stop: |
|||
raise UserError( |
|||
_("First you have to specify the date of the " |
|||
"invitation.")) |
|||
event.add('created').value = ics_datetime(fields.Datetime.now()) |
|||
event.add('dtstart').value = ics_datetime(meeting.start, |
|||
meeting.allday) |
|||
event.add('dtend').value = ics_datetime(meeting.stop, |
|||
meeting.allday) |
|||
event.add('summary').value = meeting.name |
|||
if not is_html_empty(meeting.description): |
|||
if 'appointment_type_id' in meeting._fields and \ |
|||
self.appointment_type_id: |
|||
event.add( |
|||
'description').value = self. \ |
|||
convert_online_event_desc_to_text( |
|||
meeting.description) |
|||
else: |
|||
event.add('description').value = html2plaintext( |
|||
meeting.description) |
|||
if meeting.location: |
|||
event.add('location').value = meeting.location |
|||
if meeting.rrule: |
|||
event.add('rrule').value = meeting.rrule |
|||
if meeting.alarm_ids: |
|||
for alarm in meeting.alarm_ids: |
|||
valarm = event.add('valarm') |
|||
interval = alarm.interval |
|||
duration = alarm.duration |
|||
trigger = valarm.add('TRIGGER') |
|||
trigger.params['related'] = ["START"] |
|||
delta = '' |
|||
if interval == 'days': |
|||
delta = timedelta(days=duration) |
|||
elif interval == 'hours': |
|||
delta = timedelta(hours=duration) |
|||
elif interval == 'minutes': |
|||
delta = timedelta(minutes=duration) |
|||
trigger.value = delta |
|||
valarm.add('DESCRIPTION').value = alarm.name or 'Odoo' |
|||
attendee_add = event.add('attendee') |
|||
attendee_add.value = 'MAILTO:' + (attendee.email or '') |
|||
for attendee_id, cal in attendee_events.items(): |
|||
attendee = self.env['res.partner'].browse(attendee_id) |
|||
attachment_values = {'name': 'All_Events.ics', |
|||
'type': 'binary', |
|||
'datas': base64.b64encode( |
|||
cal.serialize().encode('utf-8')), |
|||
'mimetype': 'text/calendar', |
|||
'res_model': 'calendar.event', |
|||
'res_id': attendee.id} |
|||
attachment = self.env['ir.attachment'].sudo().create( |
|||
attachment_values) |
|||
email_template = self.env.ref( |
|||
'odoo_icalendar.odoo_icalendar_email_template') |
|||
email_values = {'email_to': attendee.email, |
|||
'email_cc': False, |
|||
'scheduled_date': False, |
|||
'recipient_ids': [], |
|||
'partner_ids': [], |
|||
'auto_delete': True, |
|||
'attachment_ids': [(4, attachment.id)]} |
|||
email_template.send_mail(meeting_obj[0].id, |
|||
email_values=email_values, |
|||
force_send=True) |
|||
email_template.attachment_ids = [(5, 0, 0)] |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 225 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 912 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 880 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 8.7 KiB |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Form view of the inherited model--> |
|||
<record id="view_calendar_event_form" model="ir.ui.view"> |
|||
<field name="name">calendar.event.form.inherit.automated.odoo.icalendar</field> |
|||
<field name="model">calendar.event</field> |
|||
<field name="inherit_id" ref="calendar.view_calendar_event_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//button[@name='action_send_sms']" position="after"> |
|||
<button name="action_send_ics" type="object" |
|||
string="Send ICS" icon="fa-envelope"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |