diff --git a/calendar_monthly_multi/README.rst b/calendar_monthly_multi/README.rst new file mode 100644 index 00000000..38929e87 --- /dev/null +++ b/calendar_monthly_multi/README.rst @@ -0,0 +1,35 @@ +**This file is going to be generated by oca-gen-addon-readme.** + +*Manual changes will be overwritten.* + +Please provide content in the ``readme`` directory: + +* **DESCRIPTION.rst** (required) +* INSTALL.rst (optional) +* CONFIGURE.rst (optional) +* **USAGE.rst** (optional, highly recommended) +* DEVELOP.rst (optional) +* ROADMAP.rst (optional) +* HISTORY.rst (optional, recommended) +* **CONTRIBUTORS.rst** (optional, highly recommended) +* CREDITS.rst (optional) + +Content of this README will also be drawn from the addon manifest, +from keys such as name, authors, maintainers, development_status, +and license. + +A good, one sentence summary in the manifest is also highly recommended. + + +Automatic changelog generation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`HISTORY.rst` can be auto generated using `towncrier `_. + +Just put towncrier compatible changelog fragments into `readme/newsfragments` +and the changelog file will be automatically generated and updated when a new fragment is added. + +Please refer to `towncrier` documentation to know more. + +NOTE: the changelog will be automatically generated when using `/ocabot merge $option`. +If you need to run it manually, refer to `OCA/maintainer-tools README `_. diff --git a/calendar_monthly_multi/__init__.py b/calendar_monthly_multi/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/calendar_monthly_multi/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/calendar_monthly_multi/__manifest__.py b/calendar_monthly_multi/__manifest__.py new file mode 100644 index 00000000..87827177 --- /dev/null +++ b/calendar_monthly_multi/__manifest__.py @@ -0,0 +1,18 @@ +{ + "name": "Calendar Monthly Extension", + "version": "16.0.1.0.0", + "category": "Productivity/Calendar", + "license": "AGPL-3", + "author": "Onestein,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/calendar", + "depends": ["calendar"], + "data": [ + "security/ir_model_access.xml", + "data/calendar_recurrence_day_data.xml", + "data/calendar_recurrence_weekday_data.xml", + "views/calendar_event_view.xml", + ], + "assets": { + "web.assets_backend": ["calendar_monthly_multi/static/src/scss/backend.scss"] + }, +} diff --git a/calendar_monthly_multi/data/calendar_recurrence_day_data.xml b/calendar_monthly_multi/data/calendar_recurrence_day_data.xml new file mode 100644 index 00000000..8d7f276b --- /dev/null +++ b/calendar_monthly_multi/data/calendar_recurrence_day_data.xml @@ -0,0 +1,96 @@ + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + 10 + + + 11 + + + 12 + + + 13 + + + 14 + + + 15 + + + 16 + + + 17 + + + 18 + + + 19 + + + 20 + + + 21 + + + 22 + + + 23 + + + 24 + + + 25 + + + 26 + + + 27 + + + 28 + + + 29 + + + 30 + + + 31 + + diff --git a/calendar_monthly_multi/data/calendar_recurrence_weekday_data.xml b/calendar_monthly_multi/data/calendar_recurrence_weekday_data.xml new file mode 100644 index 00000000..9b955ee5 --- /dev/null +++ b/calendar_monthly_multi/data/calendar_recurrence_weekday_data.xml @@ -0,0 +1,40 @@ + + + + 0 + MO + Monday + + + 1 + TU + Tuesday + + + 2 + WE + Wednesday + + + 3 + TH + Thursday + + + 4 + FR + Friday + + + 5 + SA + Saturday + True + + + 6 + SU + Sunday + True + + diff --git a/calendar_monthly_multi/models/__init__.py b/calendar_monthly_multi/models/__init__.py new file mode 100644 index 00000000..99599bc4 --- /dev/null +++ b/calendar_monthly_multi/models/__init__.py @@ -0,0 +1,4 @@ +from . import calendar_event +from . import calendar_recurrence +from . import calendar_recurrence_day +from . import calendar_recurrence_weekday diff --git a/calendar_monthly_multi/models/calendar_event.py b/calendar_monthly_multi/models/calendar_event.py new file mode 100644 index 00000000..0fb5b321 --- /dev/null +++ b/calendar_monthly_multi/models/calendar_event.py @@ -0,0 +1,47 @@ +from odoo import api, fields, models + + +class CalendarEvent(models.Model): + _inherit = "calendar.event" + + month_by = fields.Selection(selection_add=[("dates", "Dates of month")]) + weekday = fields.Selection( + selection_add=[ + ("weekday", "Weekday"), + ("weekend_day", "Weekend Day"), + ("day", "Day"), + ("custom", "Custom"), + ] + ) + day_ids = fields.Many2many( + comodel_name="calendar.recurrence.day", + compute="_compute_recurrence", + readonly=False, + ) + weekday_ids = fields.Many2many( + comodel_name="calendar.recurrence.weekday", + compute="_compute_recurrence", + readonly=False, + ) + + @api.model + def _get_recurrent_fields(self): + fields = super()._get_recurrent_fields() + fields.add("day_ids") + fields.add("weekday_ids") + return fields + + def _get_recurrence_params(self): + params = super()._get_recurrence_params() + event_date = self._get_start_date() + params.update( + day_ids=[ + self.env["calendar.recurrence.day"].get_id_from_day(event_date.day) + ], + weekday_ids=[ + self.env["calendar.recurrence.weekday"].get_id_by_sequence( + event_date.weekday() + ) + ], + ) + return params diff --git a/calendar_monthly_multi/models/calendar_recurrence.py b/calendar_monthly_multi/models/calendar_recurrence.py new file mode 100644 index 00000000..72ec4c64 --- /dev/null +++ b/calendar_monthly_multi/models/calendar_recurrence.py @@ -0,0 +1,163 @@ +from datetime import datetime, time + +from dateutil import rrule + +from odoo import Command, _, api, fields, models + +from odoo.addons.calendar.models.calendar_recurrence import ( + MAX_RECURRENT_EVENT, + RRULE_WEEKDAY_TO_FIELD, + RRULE_WEEKDAYS, +) + + +class CalendarRecurrence(models.Model): + _inherit = "calendar.recurrence" + + month_by = fields.Selection(selection_add=[("dates", "Dates of month")]) + weekday = fields.Selection( + selection_add=[ + ("weekday", "Weekday"), + ("weekend_day", "Weekend Day"), + ("day", "Day"), + ("custom", "Custom"), + ] + ) + weekday_ids = fields.Many2many( + comodel_name="calendar.recurrence.weekday", + compute="_compute_weekday_ids", + store=True, + ) + day_ids = fields.Many2many(comodel_name="calendar.recurrence.day") + + @api.depends("weekday", "rrule_type", "month_by", "rrule") + def _compute_weekday_ids(self): + for recurrence in self.filtered( + lambda r: r.weekday != "custom" + and r.rrule_type == "monthly" + and r.month_by == "day" + ): + if recurrence.weekday == "day": + recurrence.weekday_ids = self.env[ + "calendar.recurrence.weekday" + ].get_ids_of_days() + elif recurrence.weekday == "weekday": + recurrence.weekday_ids = self.env[ + "calendar.recurrence.weekday" + ].get_ids_of_weekdays() + elif recurrence.weekday == "weekend_day": + recurrence.weekday_ids = self.env[ + "calendar.recurrence.weekday" + ].get_ids_of_weekend_days() + else: + recurrence.weekday_ids = self.env.ref( + "calendar_monthly_multi.%s" % RRULE_WEEKDAYS[recurrence.weekday] + ).ids + + @api.depends("day_ids", "weekday_ids") + def _compute_rrule(self): + return super()._compute_rrule() + + @api.model + def _rrule_parse(self, rule_str, date_start): + values = super()._rrule_parse(rule_str, date_start) + rule = rrule.rrulestr(rule_str, dtstart=date_start) + if rule._freq != rrule.MONTHLY: + return values + if rule._bymonthday and len(rule._bymonthday) > 1: + values["day_ids"] = [ + Command.set( + [ + self.env["calendar.recurrence.day"].get_id_from_day(d) + for d in rule._bymonthday + ] + ) + ] + values["month_by"] = "dates" + values["rrule_type"] = "monthly" + elif rule._byweekday: # (0, 1, 2, 3, 4) + weekday_ids = [] + if len(rule._byweekday) == 7: + weekday = "day" + elif len(rule._byweekday) == 1: + weekday = RRULE_WEEKDAY_TO_FIELD[rule._byweekday[0]].upper() + else: + weekday_ids = [ + self.env["calendar.recurrence.weekday"].get_id_by_sequence(d) + for d in rule._byweekday + ] + weekday_ids_set = set(weekday_ids) + weekend_days_ids = set( + self.env["calendar.recurrence.weekday"].get_ids_of_weekend_days() + ) + week_days_ids = set( + self.env["calendar.recurrence.weekday"].get_ids_of_weekdays() + ) + if weekday_ids_set == weekend_days_ids: + weekday = "weekend_day" + elif weekday_ids_set == week_days_ids: + weekday = "weekday" + else: + weekday = "custom" + + values["weekday_ids"] = weekday_ids + values["month_by"] = "day" + values["byday"] = str(rule._bysetpos[0]) + values["weekday"] = weekday + values["rrule_type"] = "monthly" + + return values + + def _compute_name(self): + monthly_multi = self.filtered( + lambda r: r.rrule_type == "monthly" + and ( + r.month_by == "dates" + or r.month_by == "day" + and r.weekday in ("day", "weekday", "weekend_day", "custom") + ) + ) + for recurrence in monthly_multi: + if recurrence.month_by == "dates": + recurrence.name = _( + "days %(days)s", + days=", ".join( + [str(day) for day in recurrence.day_ids.mapped("day")] + ), + ) + else: + recurrence.name = _( + "on the %(byday)s %(weekdays)s", + byday=dict(self._fields["byday"].selection)[recurrence.byday], + weekdays=", ".join(recurrence.weekday_ids.mapped("name")), + ) + return super(CalendarRecurrence, self - monthly_multi)._compute_name() + + def _get_rrule(self, dtstart=None): + self.ensure_one() + + if self.rrule_type == "monthly" and ( + self.month_by == "dates" + or self.month_by == "day" + and self.weekday in ("weekday", "weekend_day", "day", "custom") + ): # If weekday is just one day than just let the calendar module handle it, + # we can handle it with weekday_ids but still + rrule_params = { + "dtstart": dtstart, + "interval": self.interval, + } + if self.month_by == "dates": + rrule_params["bymonthday"] = self.day_ids.mapped("day") + else: + rrule_params["bysetpos"] = int(self.byday) + rrule_params["byweekday"] = [ + getattr(rrule, w.key) for w in self.weekday_ids + ] + if self.end_type == "count": + rrule_params["count"] = min(self.count, MAX_RECURRENT_EVENT) + elif self.end_type == "forever": + rrule_params["count"] = MAX_RECURRENT_EVENT + elif self.end_type == "end_date": + rrule_params["until"] = datetime.combine(self.until, time.max) + return rrule.rrule(rrule.MONTHLY, **rrule_params) + return super()._get_rrule(dtstart) diff --git a/calendar_monthly_multi/models/calendar_recurrence_day.py b/calendar_monthly_multi/models/calendar_recurrence_day.py new file mode 100644 index 00000000..eca3c2f3 --- /dev/null +++ b/calendar_monthly_multi/models/calendar_recurrence_day.py @@ -0,0 +1,25 @@ +from odoo import fields, models, tools + + +class CalendarRecurrenceDay(models.Model): + _name = "calendar.recurrence.day" + _description = "Recurrence Day" + _order = "day" + + day = fields.Integer() + + _sql_constraints = [("day_uniq", "unique (day)", "Already exists")] + + def name_get(self): + res = [] + for record in self: + res.append((record.id, str(record.day))) + return res + + @tools.ormcache("day") + def get_id_from_day(self, day): + return self.search([("day", "=", day)], limit=1).id + + @tools.ormcache("day_id") + def get_day_from_id(self, day_id): + return self.browse(day_id).day diff --git a/calendar_monthly_multi/models/calendar_recurrence_weekday.py b/calendar_monthly_multi/models/calendar_recurrence_weekday.py new file mode 100644 index 00000000..04d631e7 --- /dev/null +++ b/calendar_monthly_multi/models/calendar_recurrence_weekday.py @@ -0,0 +1,32 @@ +from odoo import api, fields, models, tools + + +class CalendarRecurrenceWeekday(models.Model): + _name = "calendar.recurrence.weekday" + _description = "Recurrence Weekday" + _order = "sequence" + + sequence = fields.Integer() + key = fields.Char(required=True) + name = fields.Char(required=True) + weekend_day = fields.Boolean() + + @api.model + @tools.ormcache("sequence") + def get_id_by_sequence(self, sequence): + return self.search([("sequence", "=", sequence)], limit=1).id + + @api.model + @tools.ormcache() + def get_ids_of_days(self): + return self.search([]).ids + + @api.model + @tools.ormcache() + def get_ids_of_weekend_days(self): + return self.search([("weekend_day", "=", True)]).ids + + @api.model + @tools.ormcache() + def get_ids_of_weekdays(self): + return self.search([("weekend_day", "=", False)]).ids diff --git a/calendar_monthly_multi/readme/CONTRIBUTORS.md b/calendar_monthly_multi/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..8a94e600 --- /dev/null +++ b/calendar_monthly_multi/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Dennis Sluijk (https://onestein.nl) diff --git a/calendar_monthly_multi/readme/DESCRIPTION.md b/calendar_monthly_multi/readme/DESCRIPTION.md new file mode 100644 index 00000000..d8ddf4b0 --- /dev/null +++ b/calendar_monthly_multi/readme/DESCRIPTION.md @@ -0,0 +1,5 @@ +This module extends the functionality of monthly recurring events in the calendar: + +1. **Multiple dates**: For example every 5th and 15th of the month +2. **All days, Weekday (monday to friday), weekend days (saturday and sunday) or + custom**: For example The first weekday of the month diff --git a/calendar_monthly_multi/readme/USAGE.md b/calendar_monthly_multi/readme/USAGE.md new file mode 100644 index 00000000..f6f43334 --- /dev/null +++ b/calendar_monthly_multi/readme/USAGE.md @@ -0,0 +1,9 @@ +To use this module, you need to: + +1. Go to the calendar app; +2. create a new event; +3. on the form of the event check "Recurrent" and select "Monthly". +4. Select "Dates of month": + ![Select Multiple Dates](../static/description/multiple-dates.png) or select "Day of + month" and "Weekday", "Weekend Day", "Day" or "Custom": + ![Weekday and weekend day](../static/description/weekday-weekendday.png) diff --git a/calendar_monthly_multi/security/ir_model_access.xml b/calendar_monthly_multi/security/ir_model_access.xml new file mode 100644 index 00000000..b417d22e --- /dev/null +++ b/calendar_monthly_multi/security/ir_model_access.xml @@ -0,0 +1,28 @@ + + + + calendar_recurrence_day_access + + + + + + + + + + calendar_recurrence_weekday_access + + + + + + + + diff --git a/calendar_monthly_multi/static/description/multiple-dates.png b/calendar_monthly_multi/static/description/multiple-dates.png new file mode 100644 index 00000000..f6566afa Binary files /dev/null and b/calendar_monthly_multi/static/description/multiple-dates.png differ diff --git a/calendar_monthly_multi/static/description/weekday-weekendday.png b/calendar_monthly_multi/static/description/weekday-weekendday.png new file mode 100644 index 00000000..68dbd1d0 Binary files /dev/null and b/calendar_monthly_multi/static/description/weekday-weekendday.png differ diff --git a/calendar_monthly_multi/static/src/scss/backend.scss b/calendar_monthly_multi/static/src/scss/backend.scss new file mode 100644 index 00000000..1dae5339 --- /dev/null +++ b/calendar_monthly_multi/static/src/scss/backend.scss @@ -0,0 +1,8 @@ +.calendar_monthly_multi_day_ids > div > div { + display: inline-block; + width: 40px; +} +.calendar_monthly_multi_weekday_ids > div > div { + display: inline-block; + width: 100px; +} diff --git a/calendar_monthly_multi/tests/__init__.py b/calendar_monthly_multi/tests/__init__.py new file mode 100644 index 00000000..ffbcb6a9 --- /dev/null +++ b/calendar_monthly_multi/tests/__init__.py @@ -0,0 +1 @@ +from . import test_recurrence diff --git a/calendar_monthly_multi/tests/test_recurrence.py b/calendar_monthly_multi/tests/test_recurrence.py new file mode 100644 index 00000000..6106b05c --- /dev/null +++ b/calendar_monthly_multi/tests/test_recurrence.py @@ -0,0 +1,349 @@ +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestRecurrence(TransactionCase): + def test_weekend_days(self): + self.env["calendar.event"].create( + { + "name": "Last weekend day", + "start": fields.Datetime.to_datetime("2023-09-01 12:00:00"), + "stop": fields.Datetime.to_datetime("2023-09-01 13:00:00"), + "recurrency": True, + "rrule_type": "monthly", + "end_type": "count", + "count": 10, + "month_by": "day", + "byday": "-1", + "weekday": "weekend_day", + "event_tz": "UTC", + } + ) + # You probably wonder why we get the recurrence this way, + # it's because of this commit: + # https://github.com/odoo/odoo/commit/43a774d68574e72fa4aabad65db42a03fac6e666 + # I had to change it to this, because the created event is + # not the base event anymore. The same goes for the other ones + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + self.assertEqual(len(recurrence.calendar_event_ids), 10) + + first_recurrence = recurrence.calendar_event_ids.filtered( + lambda e: e.start == fields.Datetime.to_datetime("2023-09-30 12:00:00") + and e.stop == fields.Datetime.to_datetime("2023-09-30 13:00:00") + ) + self.assertEqual( + len(first_recurrence), + 1, + "First recurrence should be on 2023-09-30 12:00:00 to 2023-09-30 13:00:00", + ) + + some_other_recurrence = recurrence.calendar_event_ids.filtered( + lambda e: e.start == fields.Datetime.to_datetime("2024-01-28 12:00:00") + and e.stop == fields.Datetime.to_datetime("2024-01-28 13:00:00") + ) + self.assertEqual( + len(some_other_recurrence), + 1, + "A recurrence should be on 2024-01-28 12:00:00 to 2024-01-28 13:00:00", + ) + + def test_day(self): + self.env["calendar.event"].create( + { + "name": "Fourth day", + "start_date": fields.Date.to_date("2023-09-01"), + "stop_date": fields.Date.to_date("2023-09-01"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "count", + "count": 20, + "month_by": "day", + "byday": "4", + "weekday": "day", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + self.assertEqual(len(recurrence.calendar_event_ids), 20) + some_recurrence = recurrence.calendar_event_ids.filtered( + lambda e: e.start_date == fields.Date.to_date("2024-02-04") + or e.start_date == fields.Date.to_date("2025-04-04") + ) + self.assertEqual( + len(some_recurrence), 2, "Recurrence should be on 2024-02-04 and 2025-04-04" + ) + + def test_weekdays(self): + self.env["calendar.event"].create( + { + "name": "First workday (mo to fr)", + "start_date": fields.Date.to_date("2023-09-10"), # Skip for 2023-09 + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-01"), # Including + "month_by": "day", + "byday": "1", + "weekday": "weekday", + "event_tz": "UTC", + "interval": 2, # Test interval + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + self.assertEqual( + len(recurrence.calendar_event_ids), 12 + ) # For 2023-09 it shouldn't be there but for 2025-09-01 there should + some_recurrence = recurrence.calendar_event_ids.filtered( + lambda e: e.start_date == fields.Date.to_date("2024-09-02") + or e.start_date == fields.Date.to_date("2025-09-01") + or e.start_date == fields.Date.to_date("2024-10-02") + or e.start_date == fields.Date.to_date("2023-09-01") # Should not + ) + self.assertEqual( + len(some_recurrence), 2, "Recurrence should be on 2024-09-02 and 2025-09-01" + ) + + def test_multi_dates(self): + self.env["calendar.event"].create( + { + "name": "Multi dates on 5th and 20th (interval 2)", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "dates", + "day_ids": [ + self.ref("calendar_monthly_multi.day_5"), + self.ref("calendar_monthly_multi.day_20"), + ], + "byday": "1", + "weekday": "weekday", + "event_tz": "UTC", + "interval": 2, # Test interval + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + self.assertEqual(len(recurrence.calendar_event_ids), 24) + some_recurrence = recurrence.calendar_event_ids.filtered( + lambda e: e.start_date == fields.Date.to_date("2023-11-05") + or e.start_date == fields.Date.to_date("2023-11-20") + or e.start_date == fields.Date.to_date("2024-09-05") + or e.start_date == fields.Date.to_date("2023-09-20") + or e.start_date == fields.Date.to_date("2025-09-05") + or e.start_date == fields.Date.to_date("2025-09-20") + or e.start_date == fields.Date.to_date("2023-09-05") # Should not + or e.start_date == fields.Date.to_date("2023-09-01") # Should not + or e.start_date == fields.Date.to_date("2023-12-20") # Should not + ) + self.assertEqual( + len(some_recurrence), + 5, + "Recurrence should be on 2023-09-20, 2023-11-05, " + "2023-11-20, 2024-09-05, and 2025-09-05", + ) + + def test_inverse_rrule_multi_date(self): + day_5 = self.ref("calendar_monthly_multi.day_5") + day_20 = self.ref("calendar_monthly_multi.day_20") + self.env["calendar.event"].create( + { + "name": "Multi dates on 5th and 20th (interval 2)", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "dates", + "day_ids": [day_5, day_20], + "byday": "1", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + multi_date_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(multi_date_test.month_by, "dates") + self.assertEqual(multi_date_test.rrule_type, "monthly") + self.assertIn(day_5, multi_date_test.day_ids.ids) + self.assertIn(day_20, multi_date_test.day_ids.ids) + self.assertEqual(len(multi_date_test.day_ids), 2) + + def test_inverse_rrule_weekdays(self): + monday = self.ref("calendar_monthly_multi.MO") + wednesday = self.ref("calendar_monthly_multi.WE") + saturday = self.ref("calendar_monthly_multi.SA") + sunday = self.ref("calendar_monthly_multi.SU") + + self.env["calendar.event"].create( + { + "name": "Weekend Day Test", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "day", + "weekday": "weekend_day", + "byday": "1", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + weekend_day_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(weekend_day_test.month_by, "day") + self.assertEqual(weekend_day_test.rrule_type, "monthly") + self.assertIn(saturday, weekend_day_test.weekday_ids.ids) + self.assertIn(sunday, weekend_day_test.weekday_ids.ids) + self.assertEqual(weekend_day_test.weekday, "weekend_day") + + self.env["calendar.event"].create( + { + "name": "Weekday (any day) test", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "day", + "weekday": "day", + "byday": "1", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + all_days_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(all_days_test.month_by, "day") + self.assertEqual(all_days_test.rrule_type, "monthly") + self.assertIn(monday, all_days_test.weekday_ids.ids) + self.assertIn(saturday, all_days_test.weekday_ids.ids) + self.assertIn(sunday, all_days_test.weekday_ids.ids) + self.assertIn(wednesday, all_days_test.weekday_ids.ids) + self.assertEqual(all_days_test.weekday, "day") + + self.env["calendar.event"].create( + { + "name": "Workday test", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "day", + "weekday": "weekday", + "byday": "1", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + workday_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(workday_test.month_by, "day") + self.assertEqual(workday_test.rrule_type, "monthly") + self.assertIn(monday, workday_test.weekday_ids.ids) + self.assertIn(wednesday, workday_test.weekday_ids.ids) + self.assertNotIn(sunday, workday_test.weekday_ids.ids) + self.assertNotIn(saturday, workday_test.weekday_ids.ids) + self.assertEqual(workday_test.weekday, "weekday") + + self.env["calendar.event"].create( + { + "name": "Custom test", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "day", + "weekday": "custom", + "weekday_ids": [monday, saturday], + "byday": "2", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + custom_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(custom_test.month_by, "day") + self.assertEqual(custom_test.rrule_type, "monthly") + self.assertIn(monday, custom_test.weekday_ids.ids) + self.assertIn(saturday, custom_test.weekday_ids.ids) + self.assertNotIn(wednesday, custom_test.weekday_ids.ids) + self.assertNotIn(sunday, custom_test.weekday_ids.ids) + self.assertEqual(custom_test.weekday, "custom") + + self.env["calendar.event"].create( + { + "name": "Normal test", + "start_date": fields.Date.to_date("2023-09-10"), + "stop_date": fields.Date.to_date("2023-09-10"), + "allday": True, + "recurrency": True, + "rrule_type": "monthly", + "end_type": "end_date", + "until": fields.Date.to_date("2025-09-06"), + "month_by": "day", + "weekday": "WED", + "byday": "1", + "event_tz": "UTC", + } + ) + recurrence = self.env["calendar.recurrence"].search( + [], limit=1, order="id desc" + ) + + normal_test = self.env["calendar.recurrence"].create( + {"rrule": recurrence.rrule} + ) + self.assertEqual(normal_test.month_by, "day") + self.assertEqual(normal_test.rrule_type, "monthly") + self.assertIn(wednesday, normal_test.weekday_ids.ids) + self.assertNotIn(sunday, normal_test.weekday_ids.ids) + self.assertNotIn(monday, normal_test.weekday_ids.ids) + self.assertNotIn(saturday, normal_test.weekday_ids.ids) + self.assertEqual(normal_test.weekday, "WED") diff --git a/calendar_monthly_multi/views/calendar_event_view.xml b/calendar_monthly_multi/views/calendar_event_view.xml new file mode 100644 index 00000000..aada77b3 --- /dev/null +++ b/calendar_monthly_multi/views/calendar_event_view.xml @@ -0,0 +1,25 @@ + + + + calendar.event + + + + + + + + + + + + diff --git a/setup/calendar_monthly_multi/odoo/addons/calendar_monthly_multi b/setup/calendar_monthly_multi/odoo/addons/calendar_monthly_multi new file mode 120000 index 00000000..5ea8c782 --- /dev/null +++ b/setup/calendar_monthly_multi/odoo/addons/calendar_monthly_multi @@ -0,0 +1 @@ +../../../../calendar_monthly_multi \ No newline at end of file diff --git a/setup/calendar_monthly_multi/setup.py b/setup/calendar_monthly_multi/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/calendar_monthly_multi/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)