@ -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> |