From b8f1ca6f280e195d178cdd2a8992cdf1ad906acc Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 3 Oct 2025 18:58:19 +0000 Subject: [PATCH 1/2] [BOT] post-merge updates --- calendar_import_ics/README.rst | 104 ++++ calendar_import_ics/__init__.py | 2 + calendar_import_ics/__manifest__.py | 17 + .../i18n/calendar_import_ics.pot | 115 +++++ calendar_import_ics/i18n/it.po | 120 +++++ calendar_import_ics/models/__init__.py | 1 + calendar_import_ics/models/calendar_event.py | 9 + calendar_import_ics/pyproject.toml | 3 + calendar_import_ics/readme/CONTRIBUTORS.md | 4 + calendar_import_ics/readme/DESCRIPTION.md | 7 + calendar_import_ics/readme/USAGE.md | 11 + .../security/calendar_import_security.xml | 7 + .../security/ir.model.access.csv | 2 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 454 ++++++++++++++++++ calendar_import_ics/tests/__init__.py | 1 + .../tests/sample_files/test_calendar.ics | 45 ++ .../tests/sample_files/test_calendar_2.ics | 45 ++ .../tests/sample_files/test_calendar_3.ics | 36 ++ .../tests/test_calendar_import_ics.py | 80 +++ calendar_import_ics/wizards/__init__.py | 1 + .../wizards/wizard_import_ics.py | 136 ++++++ .../wizards/wizard_import_ics.xml | 39 ++ 23 files changed, 1239 insertions(+) create mode 100644 calendar_import_ics/README.rst create mode 100644 calendar_import_ics/__init__.py create mode 100644 calendar_import_ics/__manifest__.py create mode 100644 calendar_import_ics/i18n/calendar_import_ics.pot create mode 100644 calendar_import_ics/i18n/it.po create mode 100644 calendar_import_ics/models/__init__.py create mode 100644 calendar_import_ics/models/calendar_event.py create mode 100644 calendar_import_ics/pyproject.toml create mode 100644 calendar_import_ics/readme/CONTRIBUTORS.md create mode 100644 calendar_import_ics/readme/DESCRIPTION.md create mode 100644 calendar_import_ics/readme/USAGE.md create mode 100644 calendar_import_ics/security/calendar_import_security.xml create mode 100644 calendar_import_ics/security/ir.model.access.csv create mode 100644 calendar_import_ics/static/description/icon.png create mode 100644 calendar_import_ics/static/description/index.html create mode 100644 calendar_import_ics/tests/__init__.py create mode 100644 calendar_import_ics/tests/sample_files/test_calendar.ics create mode 100644 calendar_import_ics/tests/sample_files/test_calendar_2.ics create mode 100644 calendar_import_ics/tests/sample_files/test_calendar_3.ics create mode 100644 calendar_import_ics/tests/test_calendar_import_ics.py create mode 100644 calendar_import_ics/wizards/__init__.py create mode 100644 calendar_import_ics/wizards/wizard_import_ics.py create mode 100644 calendar_import_ics/wizards/wizard_import_ics.xml diff --git a/calendar_import_ics/README.rst b/calendar_import_ics/README.rst new file mode 100644 index 00000000..e35b2baa --- /dev/null +++ b/calendar_import_ics/README.rst @@ -0,0 +1,104 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +===================== +Calendar - Import ics +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0b76e943a6186b958123d04eef313d6d66e7b9361daf4122b045fbca02b88b23 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcalendar-lightgray.png?logo=github + :target: https://github.com/OCA/calendar/tree/18.0/calendar_import_ics + :alt: OCA/calendar +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/calendar-18-0/calendar-18-0-calendar_import_ics + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/calendar&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a new wizard that allows you to import .ics files into +odoo calendar, importing events and the following attributes: + +- Summary +- Start Date +- End Date +- UID + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, follow these steps: + +1. Navigate to the Calendar App. +2. Go to Configuration. +3. Select Import ICS File. + +When importing, you have two options: + +- Specify start and end dates to import events occurring within that + range. +- Leave the date fields empty to import all events from the entire file. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* ForgeFlow S.L. + +Contributors +------------ + +- Arnau Cruz + +Do not contact contributors directly about support or help with +technical issues. + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/calendar `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/calendar_import_ics/__init__.py b/calendar_import_ics/__init__.py new file mode 100644 index 00000000..976591c9 --- /dev/null +++ b/calendar_import_ics/__init__.py @@ -0,0 +1,2 @@ +from . import wizards +from . import models diff --git a/calendar_import_ics/__manifest__.py b/calendar_import_ics/__manifest__.py new file mode 100644 index 00000000..cc71fbf1 --- /dev/null +++ b/calendar_import_ics/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright (C) 2024 - ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Calendar - Import ics", + "summary": "Allow importing an ics file to our calendar", + "version": "18.0.1.0.1", + "author": "ForgeFlow S.L.,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/calendar", + "license": "AGPL-3", + "depends": ["calendar"], + "data": [ + "security/calendar_import_security.xml", + "security/ir.model.access.csv", + "wizards/wizard_import_ics.xml", + ], +} diff --git a/calendar_import_ics/i18n/calendar_import_ics.pot b/calendar_import_ics/i18n/calendar_import_ics.pot new file mode 100644 index 00000000..7b23c6bd --- /dev/null +++ b/calendar_import_ics/i18n/calendar_import_ics.pot @@ -0,0 +1,115 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * calendar_import_ics +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: calendar_import_ics +#: model:ir.model,name:calendar_import_ics.model_calendar_event +msgid "Calendar Event" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model,name:calendar_import_ics.model_calendar_import_ics +#: model:res.groups,name:calendar_import_ics.group_calendar_import +msgid "Calendar Import Ics" +msgstr "" + +#. module: calendar_import_ics +#: model_terms:ir.ui.view,arch_db:calendar_import_ics.calendar_import_ics_form +msgid "Cancel" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__create_uid +msgid "Created by" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__create_date +msgid "Created on" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__display_name +msgid "Display Name" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_end_date +msgid "End Import Date" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_event__event_identifier +msgid "Event Id" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__id +msgid "ID" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,help:calendar_import_ics.field_calendar_import_ics__do_remove_old_event +msgid "" +"If checked, the previously imported events that are not in this import will " +"be deleted" +msgstr "" + +#. module: calendar_import_ics +#: model_terms:ir.ui.view,arch_db:calendar_import_ics.calendar_import_ics_form +msgid "Import" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.actions.act_window,name:calendar_import_ics.action_import_ics_wizard +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_ics_file +#: model:ir.ui.menu,name:calendar_import_ics.menu_calendar_import_ics +msgid "Import Ics File" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_ics_filename +msgid "Import Ics Filename" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__write_date +msgid "Last Updated on" +msgstr "" + +#. module: calendar_import_ics +#. odoo-python +#: code:addons/calendar_import_ics/wizards/wizard_import_ics.py:0 +msgid "Only ics files are supported" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__partner_id +msgid "Partner" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__do_remove_old_event +msgid "Remove old events?" +msgstr "" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_start_date +msgid "Start Import Date" +msgstr "" diff --git a/calendar_import_ics/i18n/it.po b/calendar_import_ics/i18n/it.po new file mode 100644 index 00000000..aea1ef12 --- /dev/null +++ b/calendar_import_ics/i18n/it.po @@ -0,0 +1,120 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * calendar_import_ics +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-08-08 14:26+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: calendar_import_ics +#: model:ir.model,name:calendar_import_ics.model_calendar_event +msgid "Calendar Event" +msgstr "Evento calendario" + +#. module: calendar_import_ics +#: model:ir.model,name:calendar_import_ics.model_calendar_import_ics +#: model:res.groups,name:calendar_import_ics.group_calendar_import +msgid "Calendar Import Ics" +msgstr "Importa calendario ics" + +#. module: calendar_import_ics +#: model_terms:ir.ui.view,arch_db:calendar_import_ics.calendar_import_ics_form +msgid "Cancel" +msgstr "Annulla" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_end_date +msgid "End Import Date" +msgstr "Data fine importazione" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_event__event_identifier +msgid "Event Id" +msgstr "ID evento" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__id +msgid "ID" +msgstr "ID" + +#. module: calendar_import_ics +#: model:ir.model.fields,help:calendar_import_ics.field_calendar_import_ics__do_remove_old_event +msgid "" +"If checked, the previously imported events that are not in this import will " +"be deleted" +msgstr "" +"Se selezionata, gli eventi precedentemente importati che non sono in questa " +"importazione saranno cancellati" + +#. module: calendar_import_ics +#: model_terms:ir.ui.view,arch_db:calendar_import_ics.calendar_import_ics_form +msgid "Import" +msgstr "Importa" + +#. module: calendar_import_ics +#: model:ir.actions.act_window,name:calendar_import_ics.action_import_ics_wizard +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_ics_file +#: model:ir.ui.menu,name:calendar_import_ics.menu_calendar_import_ics +msgid "Import Ics File" +msgstr "Importa file ics" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_ics_filename +msgid "Import Ics Filename" +msgstr "Nome file importazione ics" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: calendar_import_ics +#. odoo-python +#: code:addons/calendar_import_ics/wizards/wizard_import_ics.py:0 +msgid "Only ics files are supported" +msgstr "Sono supportati solo i file ics" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__partner_id +msgid "Partner" +msgstr "Partner" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__do_remove_old_event +msgid "Remove old events?" +msgstr "Rimuovere i vecchi eventi?" + +#. module: calendar_import_ics +#: model:ir.model.fields,field_description:calendar_import_ics.field_calendar_import_ics__import_start_date +msgid "Start Import Date" +msgstr "Data inizio importazione" diff --git a/calendar_import_ics/models/__init__.py b/calendar_import_ics/models/__init__.py new file mode 100644 index 00000000..ba757cbe --- /dev/null +++ b/calendar_import_ics/models/__init__.py @@ -0,0 +1 @@ +from . import calendar_event diff --git a/calendar_import_ics/models/calendar_event.py b/calendar_import_ics/models/calendar_event.py new file mode 100644 index 00000000..5202f110 --- /dev/null +++ b/calendar_import_ics/models/calendar_event.py @@ -0,0 +1,9 @@ +# Copyright (C) 2024 - ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class CalendarEvent(models.Model): + _inherit = "calendar.event" + event_identifier = fields.Char("Event Id") diff --git a/calendar_import_ics/pyproject.toml b/calendar_import_ics/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/calendar_import_ics/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/calendar_import_ics/readme/CONTRIBUTORS.md b/calendar_import_ics/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..7bd3452d --- /dev/null +++ b/calendar_import_ics/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- Arnau Cruz \ + +Do not contact contributors directly about support or help with +technical issues. diff --git a/calendar_import_ics/readme/DESCRIPTION.md b/calendar_import_ics/readme/DESCRIPTION.md new file mode 100644 index 00000000..b20ce9c3 --- /dev/null +++ b/calendar_import_ics/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +This module adds a new wizard that allows you to import .ics files into +odoo calendar, importing events and the following attributes: + +- Summary +- Start Date +- End Date +- UID diff --git a/calendar_import_ics/readme/USAGE.md b/calendar_import_ics/readme/USAGE.md new file mode 100644 index 00000000..2285010d --- /dev/null +++ b/calendar_import_ics/readme/USAGE.md @@ -0,0 +1,11 @@ +To use this module, follow these steps: + +1. Navigate to the Calendar App. +2. Go to Configuration. +3. Select Import ICS File. + +When importing, you have two options: + +- Specify start and end dates to import events occurring within that + range. +- Leave the date fields empty to import all events from the entire file. diff --git a/calendar_import_ics/security/calendar_import_security.xml b/calendar_import_ics/security/calendar_import_security.xml new file mode 100644 index 00000000..1ad29a88 --- /dev/null +++ b/calendar_import_ics/security/calendar_import_security.xml @@ -0,0 +1,7 @@ + + + + Calendar Import Ics + + + diff --git a/calendar_import_ics/security/ir.model.access.csv b/calendar_import_ics/security/ir.model.access.csv new file mode 100644 index 00000000..cadc4160 --- /dev/null +++ b/calendar_import_ics/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_wizard_calendar_import_ics,access_wizard_calendar_import_ics,model_calendar_import_ics,calendar_import_ics.group_calendar_import,1,1,1,1 diff --git a/calendar_import_ics/static/description/icon.png b/calendar_import_ics/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~! zVpnB`o+K7|Al`Q_U;eD$B zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__ zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_ zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)( z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9 zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz# z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K= z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C zuVl&0duN<;uOsB3%T9Fp8t{ED108<+W(nOZd?gDnfNBC3>M8WE61$So|P zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1 zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_ zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8 zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ> zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD z#z-)AXwSRY?OPefw^iI+ z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$ z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6 zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+ z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC) zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x! zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8 z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n= z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@ zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y< zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6 zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6% z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(| z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6 z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d} z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/calendar_import_ics/static/description/index.html b/calendar_import_ics/static/description/index.html new file mode 100644 index 00000000..2d45f67d --- /dev/null +++ b/calendar_import_ics/static/description/index.html @@ -0,0 +1,454 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Calendar - Import ics

+ +

Beta License: AGPL-3 OCA/calendar Translate me on Weblate Try me on Runboat

+

This module adds a new wizard that allows you to import .ics files into +odoo calendar, importing events and the following attributes:

+
    +
  • Summary
  • +
  • Start Date
  • +
  • End Date
  • +
  • UID
  • +
+

Table of contents

+ +
+

Usage

+

To use this module, follow these steps:

+
    +
  1. Navigate to the Calendar App.
  2. +
  3. Go to Configuration.
  4. +
  5. Select Import ICS File.
  6. +
+

When importing, you have two options:

+
    +
  • Specify start and end dates to import events occurring within that +range.
  • +
  • Leave the date fields empty to import all events from the entire file.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ForgeFlow S.L.
  • +
+
+
+

Contributors

+ +

Do not contact contributors directly about support or help with +technical issues.

+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/calendar project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/calendar_import_ics/tests/__init__.py b/calendar_import_ics/tests/__init__.py new file mode 100644 index 00000000..6bf23ec2 --- /dev/null +++ b/calendar_import_ics/tests/__init__.py @@ -0,0 +1 @@ +from . import test_calendar_import_ics diff --git a/calendar_import_ics/tests/sample_files/test_calendar.ics b/calendar_import_ics/tests/sample_files/test_calendar.ics new file mode 100644 index 00000000..e74ae53b --- /dev/null +++ b/calendar_import_ics/tests/sample_files/test_calendar.ics @@ -0,0 +1,45 @@ +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +PRODID:-//Fastmail/2020.5/EN +X-APPLE-CALENDAR-COLOR:#3A429C +X-WR-CALNAME:_CE +X-WR-TIMEZONE:US/Pacific +BEGIN:VEVENT +DTEND:20061010T210000Z +DTSTAMP:20240221T094129Z +DTSTART:20061010T200000Z +SEQUENCE:0 +SUMMARY:Event 1 Test +TRANSP:OPAQUE +UID:ed27f2b89f945c7692547a2903c20cbe80de6cc6 +END:VEVENT +BEGIN:VEVENT +DTEND;TZID=America/Denver:20061011T190000 +DTSTAMP:20240221T094129Z +DTSTART;TZID=America/Denver:20061011T160000 +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:4b1a0cb2081f6b3243bfdf191c985fe86237344c +END:VEVENT +BEGIN:VEVENT +DTEND:20061012T020000Z +DTSTAMP:20240221T094129Z +DTSTART:20061012T010000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:06b1c17713eca80e7219e8278330a4e9604f12e3 +END:VEVENT +BEGIN:VEVENT +DTEND:20061014T000000Z +DTSTAMP:20240221T094129Z +DTSTART:20061013T150000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:3275dc6275325a10b715008ee2713808de24e516 +END:VEVENT +END:VCALENDAR diff --git a/calendar_import_ics/tests/sample_files/test_calendar_2.ics b/calendar_import_ics/tests/sample_files/test_calendar_2.ics new file mode 100644 index 00000000..cb06394d --- /dev/null +++ b/calendar_import_ics/tests/sample_files/test_calendar_2.ics @@ -0,0 +1,45 @@ +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +PRODID:-//Fastmail/2020.5/EN +X-APPLE-CALENDAR-COLOR:#3A429C +X-WR-CALNAME:_CE +X-WR-TIMEZONE:US/Pacific +BEGIN:VEVENT +DTEND:20061010T220000Z +DTSTAMP:20240221T094129Z +DTSTART:20061010T210000Z +SEQUENCE:0 +SUMMARY:Event 1 Test Renamed +TRANSP:OPAQUE +UID:ed27f2b89f945c7692547a2903c20cbe80de6cc6 +END:VEVENT +BEGIN:VEVENT +DTEND:20061011T190000Z +DTSTAMP:20240221T094129Z +DTSTART:20061011T160000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:4b1a0cb2081f6b3243bfdf191c985fe86237344c +END:VEVENT +BEGIN:VEVENT +DTEND:20061012T020000Z +DTSTAMP:20240221T094129Z +DTSTART:20061012T010000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:06b1c17713eca80e7219e8278330a4e9604f12e3 +END:VEVENT +BEGIN:VEVENT +DTEND:20061014T000000Z +DTSTAMP:20240221T094129Z +DTSTART:20061013T150000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:3275dc6275325a10b715008ee2713808de24e516 +END:VEVENT +END:VCALENDAR diff --git a/calendar_import_ics/tests/sample_files/test_calendar_3.ics b/calendar_import_ics/tests/sample_files/test_calendar_3.ics new file mode 100644 index 00000000..def817d9 --- /dev/null +++ b/calendar_import_ics/tests/sample_files/test_calendar_3.ics @@ -0,0 +1,36 @@ +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +PRODID:-//Fastmail/2020.5/EN +X-APPLE-CALENDAR-COLOR:#3A429C +X-WR-CALNAME:_CE +X-WR-TIMEZONE:US/Pacific +BEGIN:VEVENT +DTEND:20061011T190000Z +DTSTAMP:20240221T094129Z +DTSTART:20061011T160000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:4b1a0cb2081f6b3243bfdf191c985fe86237344c +END:VEVENT +BEGIN:VEVENT +DTEND:20221012T020000Z +DTSTAMP:20240221T094129Z +DTSTART:20221012T010000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:06b1c17713eca80e7219e8278330a4e9604f12e3 +END:VEVENT +BEGIN:VEVENT +DTEND:20221014T000000Z +DTSTAMP:20240221T094129Z +DTSTART:20221013T150000Z +SEQUENCE:0 +SUMMARY:Unavailable +TRANSP:OPAQUE +UID:3275dc6275325a10b715008ee2713808de24e516 +END:VEVENT +END:VCALENDAR diff --git a/calendar_import_ics/tests/test_calendar_import_ics.py b/calendar_import_ics/tests/test_calendar_import_ics.py new file mode 100644 index 00000000..58331d56 --- /dev/null +++ b/calendar_import_ics/tests/test_calendar_import_ics.py @@ -0,0 +1,80 @@ +# Copyright (C) 2024 - ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import base64 +from datetime import datetime + +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase +from odoo.tools.misc import file_path + + +class TestImportIcs(TransactionCase): + def setUp(self): + super().setUp() + self.event_model = self.env["calendar.event"] + self.import_wiz = self.env["calendar.import.ics"] + + @classmethod + def _get_test_file(cls, file_name): + path = file_path(f"calendar_import_ics/tests/sample_files/{file_name}") + with open(path, "rb") as file: + return base64.encodebytes(file.read()) + + def test_import_ics(self): + events_before_imp = self.event_model.search([]) + filename = "test_calendar.ics" + wiz = self.import_wiz.create( + { + "import_ics_file": self._get_test_file(filename), + "import_ics_filename": filename, + } + ) + wiz.button_import() + events_after_imp = self.event_model.search([]) + self.assertEqual(len(events_after_imp) - len(events_before_imp), 4) + uid = "ed27f2b89f945c7692547a2903c20cbe80de6cc6" + start_date = datetime(2006, 10, 10, 20, 00, 00) + end_date = datetime(2006, 10, 10, 21, 00, 00) + name = "Event 1 Test" + event_1 = self.event_model.search([("event_identifier", "=", uid)]) + self.assertEqual(event_1.event_identifier, uid) + self.assertEqual(event_1.start, start_date) + self.assertEqual(event_1.stop, end_date) + self.assertEqual(event_1.name, name) + filename = "test_calendar_2.ics" + wiz = self.import_wiz.create( + { + "import_ics_file": self._get_test_file(filename), + "import_ics_filename": filename, + } + ) + wiz.button_import() + event_1 = self.event_model.search([("event_identifier", "=", uid)]) + start_date = datetime(2006, 10, 10, 21, 00, 00) + end_date = datetime(2006, 10, 10, 22, 00, 00) + name = "Event 1 Test Renamed" + self.assertEqual(event_1.event_identifier, uid) + self.assertEqual(event_1.start, start_date) + self.assertEqual(event_1.stop, end_date) + self.assertEqual(event_1.name, name) + filename = "test_calendar_3.ics" + wiz = self.import_wiz.create( + { + "import_ics_file": self._get_test_file(filename), + "import_ics_filename": filename, + "import_start_date": datetime(2004, 10, 10), + "import_end_date": datetime(2044, 10, 10), + } + ) + wiz.button_import() + event_1 = self.event_model.search([("event_identifier", "=", uid)]) + self.assertFalse(event_1) + wiz = self.import_wiz.create( + { + "import_ics_file": self._get_test_file(filename), + "import_ics_filename": "random_name.xslx", + } + ) + with self.assertRaises(ValidationError): + wiz.button_import() diff --git a/calendar_import_ics/wizards/__init__.py b/calendar_import_ics/wizards/__init__.py new file mode 100644 index 00000000..9f9358b9 --- /dev/null +++ b/calendar_import_ics/wizards/__init__.py @@ -0,0 +1 @@ +from . import wizard_import_ics diff --git a/calendar_import_ics/wizards/wizard_import_ics.py b/calendar_import_ics/wizards/wizard_import_ics.py new file mode 100644 index 00000000..bdd17331 --- /dev/null +++ b/calendar_import_ics/wizards/wizard_import_ics.py @@ -0,0 +1,136 @@ +# Copyright (C) 2024 - ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import base64 +from datetime import datetime + +import pytz +from dateutil import parser + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +class CalendarImportIcs(models.TransientModel): + """ + This wizard is used to import ics files to calendar + """ + + _name = "calendar.import.ics" + _description = "Calendar Import Ics" + + import_ics_file = fields.Binary(required=True) + import_ics_filename = fields.Char() + import_start_date = fields.Date("Start Import Date") + import_end_date = fields.Date("End Import Date") + partner_id = fields.Many2one("res.partner", string="Partner") + do_remove_old_event = fields.Boolean( + string="Remove old events?", + help="If checked, the previously imported events " + "that are not in this import will be deleted", + default=True, + ) + + def button_import(self): + imported_events = [] + self.ensure_one() + assert self.import_ics_file + extension = self.import_ics_filename.split(".")[1] + if extension != "ics": + raise ValidationError(_("Only ics files are supported")) + if self.env.user and not self.partner_id: + self.partner_id = self.env.user.partner_id.id + file_decoded = base64.b64decode(self.import_ics_file) + file_str = file_decoded.decode("utf-8") + lines = file_str.split("\n") + ics_event = {} + for line in lines: + if line.startswith(("DTSTART", "DTEND")) and "TZID=" in line: + line = self.convert_date_to_z(line) + if line.startswith("BEGIN:VEVENT"): + ics_event = {} + elif line.startswith("END:VEVENT"): + self._process_event(ics_event, imported_events) + else: + if ":" in line: + key, value = line.strip().split(":", 1) + ics_event[key] = value + if self.do_remove_old_event: + self._delete_non_imported_events(imported_events) + + def _process_event(self, ics_event, imported_events): + if "DTSTART" in ics_event and "DTEND" in ics_event: + event_start_date = self._parse_date(ics_event["DTSTART"]) + event_end_date = self._parse_date(ics_event["DTEND"]) + if (not self.import_start_date or not self.import_end_date) or ( + self.import_start_date <= event_start_date.date() + and self.import_end_date >= event_end_date.date() + ): + imported_events.append(ics_event["UID"]) + event = self.env["calendar.event"].search( + [("event_identifier", "=", ics_event["UID"])] + ) + if event: + self._update_event( + event, ics_event, event_start_date, event_end_date + ) + else: + self._create_event(ics_event, event_start_date, event_end_date) + + def _parse_date(self, date_str): + return datetime.strptime(date_str, "%Y%m%dT%H%M%SZ") + + def _update_event(self, event, ics_event, event_start_date, event_end_date): + vals = {} + if event.start != event_start_date: + vals["start"] = event_start_date + if event.stop != event_end_date: + vals["stop"] = event_end_date + if event.name != ics_event["SUMMARY"]: + vals["name"] = ics_event["SUMMARY"] + if self.partner_id not in event.partner_ids: + vals["partner_ids"] = [(4, self.partner_id.id, 0)] + event.write(vals) + + def _create_event(self, ics_event, event_start_date, event_end_date): + self.env["calendar.event"].create( + { + "start": event_start_date, + "stop": event_end_date, + "name": ics_event["SUMMARY"], + "event_identifier": ics_event["UID"], + "partner_ids": [(4, self.partner_id.id)], + } + ) + + def _delete_non_imported_events(self, imported_events): + domain = [ + ("event_identifier", "!=", False), + ("event_identifier", "not in", imported_events), + ("partner_ids", "in", self.partner_id.id), + ] + + if self.import_start_date: + domain.append(("start", ">=", self.import_start_date)) + + if self.import_end_date: + domain.append(("stop", "<=", self.import_end_date)) + + non_imported_events = self.env["calendar.event"].search(domain) + for non_imported_event in non_imported_events: + non_imported_event.write({"partner_ids": [(3, self.partner_id.id)]}) + if not non_imported_events.partner_ids: + non_imported_events.unlink() + + def convert_date_to_z(self, line): + split_parts = line.split(":") + event_phase = split_parts[0].split(";TZID=")[0] + tz_id = split_parts[0].split(";TZID=")[1] + date = split_parts[1] + + date_obj = parser.parse(date) + tz = pytz.timezone(tz_id) + + utc_date = tz.localize(date_obj).astimezone(pytz.UTC) + utc_date_string = utc_date.strftime(event_phase + ":%Y%m%dT%H%M%SZ") + return utc_date_string diff --git a/calendar_import_ics/wizards/wizard_import_ics.xml b/calendar_import_ics/wizards/wizard_import_ics.xml new file mode 100644 index 00000000..58747e7c --- /dev/null +++ b/calendar_import_ics/wizards/wizard_import_ics.xml @@ -0,0 +1,39 @@ + + + + calendar.import.ics.form + calendar.import.ics + +
+ + + + + + + +
+
+
+
+
+ + Import Ics File + calendar.import.ics + form + new + + +
From 40c25e854e31f0180db687f23a08c0901ebad276 Mon Sep 17 00:00:00 2001 From: Milan Topuzov Date: Sun, 19 Oct 2025 18:37:46 +0200 Subject: [PATCH 2/2] [MIG] calendar_import_ics: Migration to 19.0 --- calendar_import_ics/README.rst | 10 +++++----- calendar_import_ics/__manifest__.py | 3 ++- .../security/calendar_import_security.xml | 2 +- calendar_import_ics/static/description/index.html | 6 +++--- calendar_import_ics/wizards/wizard_import_ics.py | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/calendar_import_ics/README.rst b/calendar_import_ics/README.rst index e35b2baa..6e0fcaf3 100644 --- a/calendar_import_ics/README.rst +++ b/calendar_import_ics/README.rst @@ -21,13 +21,13 @@ Calendar - Import ics :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcalendar-lightgray.png?logo=github - :target: https://github.com/OCA/calendar/tree/18.0/calendar_import_ics + :target: https://github.com/OCA/calendar/tree/19.0/calendar_import_ics :alt: OCA/calendar .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/calendar-18-0/calendar-18-0-calendar_import_ics + :target: https://translation.odoo-community.org/projects/calendar-19-0/calendar-19-0-calendar_import_ics :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/calendar&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/calendar&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -66,7 +66,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -99,6 +99,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/calendar `_ project on GitHub. +This module is part of the `OCA/calendar `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/calendar_import_ics/__manifest__.py b/calendar_import_ics/__manifest__.py index cc71fbf1..f097135e 100644 --- a/calendar_import_ics/__manifest__.py +++ b/calendar_import_ics/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Calendar - Import ics", "summary": "Allow importing an ics file to our calendar", - "version": "18.0.1.0.1", + "version": "19.0.1.0.0", "author": "ForgeFlow S.L.,Odoo Community Association (OCA)", "website": "https://github.com/OCA/calendar", "license": "AGPL-3", @@ -14,4 +14,5 @@ "security/ir.model.access.csv", "wizards/wizard_import_ics.xml", ], + "installable": True, } diff --git a/calendar_import_ics/security/calendar_import_security.xml b/calendar_import_ics/security/calendar_import_security.xml index 1ad29a88..e9cebd7e 100644 --- a/calendar_import_ics/security/calendar_import_security.xml +++ b/calendar_import_ics/security/calendar_import_security.xml @@ -2,6 +2,6 @@ Calendar Import Ics - + diff --git a/calendar_import_ics/static/description/index.html b/calendar_import_ics/static/description/index.html index 2d45f67d..6c78e2ef 100644 --- a/calendar_import_ics/static/description/index.html +++ b/calendar_import_ics/static/description/index.html @@ -374,7 +374,7 @@

Calendar - Import ics

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:0b76e943a6186b958123d04eef313d6d66e7b9361daf4122b045fbca02b88b23 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/calendar Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/calendar Translate me on Weblate Try me on Runboat

This module adds a new wizard that allows you to import .ics files into odoo calendar, importing events and the following attributes:

    @@ -416,7 +416,7 @@

    Bug Tracker

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

    +feedback.

    Do not contact contributors directly about support or help with technical issues.

    @@ -444,7 +444,7 @@

    Maintainers

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    -

    This module is part of the OCA/calendar project on GitHub.

    +

    This module is part of the OCA/calendar project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    diff --git a/calendar_import_ics/wizards/wizard_import_ics.py b/calendar_import_ics/wizards/wizard_import_ics.py index bdd17331..49fc129d 100644 --- a/calendar_import_ics/wizards/wizard_import_ics.py +++ b/calendar_import_ics/wizards/wizard_import_ics.py @@ -7,7 +7,7 @@ import pytz from dateutil import parser -from odoo import _, fields, models +from odoo import fields, models from odoo.exceptions import ValidationError @@ -37,7 +37,7 @@ def button_import(self): assert self.import_ics_file extension = self.import_ics_filename.split(".")[1] if extension != "ics": - raise ValidationError(_("Only ics files are supported")) + raise ValidationError(self.env._("Only ics files are supported")) if self.env.user and not self.partner_id: self.partner_id = self.env.user.partner_id.id file_decoded = base64.b64decode(self.import_ics_file)