mirror of
https://github.com/bringout/oca-mrp.git
synced 2026-04-22 09:12:08 +02:00
Initial commit: OCA Mrp packages (117 packages)
This commit is contained in:
commit
277e84fd7a
4403 changed files with 395154 additions and 0 deletions
|
|
@ -0,0 +1 @@
|
|||
from . import wizard_event_session
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
# Copyright 2017 David Vidal<david.vidal@tecnativa.com>
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2021 Moka Tourisme (https://www.mokatourisme.fr).
|
||||
# @author Iván Todorovich <ivan.todorovich@gmail.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from datetime import datetime, time, timedelta
|
||||
|
||||
import pytz
|
||||
from dateutil import rrule
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
SELECT_FREQ_TO_RRULE = {
|
||||
"daily": rrule.DAILY,
|
||||
"weekly": rrule.WEEKLY,
|
||||
"monthly": rrule.MONTHLY,
|
||||
"yearly": rrule.YEARLY,
|
||||
}
|
||||
|
||||
RRULE_WEEKDAYS = {
|
||||
"SUN": "SU",
|
||||
"MON": "MO",
|
||||
"TUE": "TU",
|
||||
"WED": "WE",
|
||||
"THU": "TH",
|
||||
"FRI": "FR",
|
||||
"SAT": "SA",
|
||||
}
|
||||
|
||||
|
||||
def freq_to_rrule(freq):
|
||||
return SELECT_FREQ_TO_RRULE[freq]
|
||||
|
||||
|
||||
def float_time_to_hours_and_minutes(float_time):
|
||||
# Round to 2 decimals to avoid hours like 1:60
|
||||
# It'd be rounded to 2:00
|
||||
float_time = round(float_time, 2)
|
||||
hours = int(float_time)
|
||||
minutes = round((float_time - hours) * 60)
|
||||
return (hours, minutes)
|
||||
|
||||
|
||||
def float_time_as_timedelta(float_time):
|
||||
hours, minutes = float_time_to_hours_and_minutes(float_time)
|
||||
return timedelta(hours=hours, minutes=minutes)
|
||||
|
||||
|
||||
def float_time_as_time(float_time):
|
||||
hours, minutes = float_time_to_hours_and_minutes(float_time)
|
||||
return time(hour=hours, minute=minutes)
|
||||
|
||||
|
||||
class WizardEventSession(models.TransientModel):
|
||||
_name = "wizard.event.session"
|
||||
_description = "Wizard for ease sessions creation"
|
||||
|
||||
event_id = fields.Many2one(
|
||||
comodel_name="event.event",
|
||||
default=lambda self: self.env.context["active_id"],
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
date_tz = fields.Selection(
|
||||
related="event_id.date_tz",
|
||||
help="Set it up in the event configuration"
|
||||
"Sessions will be generated up to this date",
|
||||
)
|
||||
duration = fields.Float(
|
||||
compute="_compute_duration",
|
||||
readonly=False,
|
||||
store=True,
|
||||
required=True,
|
||||
help="Duration of the sessions in hours",
|
||||
)
|
||||
timeslot_ids = fields.Many2many(
|
||||
comodel_name="event.session.timeslot",
|
||||
string="Time slots",
|
||||
required=True,
|
||||
)
|
||||
# rrule fields
|
||||
interval = fields.Integer(default=1, required=True)
|
||||
rrule_type = fields.Selection(
|
||||
[("weekly", "Weeks"), ("monthly", "Months")],
|
||||
string="Recurrence",
|
||||
default="weekly",
|
||||
required=True,
|
||||
)
|
||||
mon = fields.Boolean()
|
||||
tue = fields.Boolean()
|
||||
wed = fields.Boolean()
|
||||
thu = fields.Boolean()
|
||||
fri = fields.Boolean()
|
||||
sat = fields.Boolean()
|
||||
sun = fields.Boolean()
|
||||
month_by = fields.Selection(
|
||||
[("date", "Date of month"), ("day", "Day of month")],
|
||||
default="date",
|
||||
)
|
||||
day = fields.Integer(default=1)
|
||||
weekday = fields.Selection(
|
||||
[
|
||||
("MON", "Monday"),
|
||||
("TUE", "Tuesday"),
|
||||
("WED", "Wednesday"),
|
||||
("THU", "Thursday"),
|
||||
("FRI", "Friday"),
|
||||
("SAT", "Saturday"),
|
||||
("SUN", "Sunday"),
|
||||
],
|
||||
)
|
||||
byday = fields.Selection(
|
||||
[
|
||||
("1", "First"),
|
||||
("2", "Second"),
|
||||
("3", "Third"),
|
||||
("4", "Fourth"),
|
||||
("-1", "Last"),
|
||||
],
|
||||
string="By day",
|
||||
)
|
||||
start = fields.Date(
|
||||
compute="_compute_start",
|
||||
readonly=False,
|
||||
required=True,
|
||||
store=True,
|
||||
)
|
||||
until = fields.Date(required=True)
|
||||
|
||||
@api.depends("event_id")
|
||||
def _compute_start(self):
|
||||
# Suggest to create sessions from the date of the last session
|
||||
# Usually the user wants to add new ones.
|
||||
for rec in self:
|
||||
rec.start = rec.event_id.date_end.date() + timedelta(days=1)
|
||||
|
||||
@api.depends("event_id")
|
||||
def _compute_duration(self):
|
||||
# Suggest to create sessions with the same duration than the
|
||||
# last existing session
|
||||
for rec in self:
|
||||
if rec.event_id.session_ids:
|
||||
session = rec.event_id.session_ids[-1]
|
||||
delta = session.date_end - session.date_begin
|
||||
rec.duration = round(delta.total_seconds() / 3600, 2)
|
||||
|
||||
@api.constrains("duration")
|
||||
def _check_duration(self):
|
||||
if any(rec.duration <= 0 for rec in self):
|
||||
raise ValidationError(_("Duration is required."))
|
||||
|
||||
@api.constrains("interval")
|
||||
def _check_interval(self):
|
||||
if any(rec.interval <= 0 for rec in self):
|
||||
raise ValidationError(_("The interval cannot be negative."))
|
||||
|
||||
def _get_lang_week_start(self):
|
||||
lang = self.env["res.lang"]._lang_get(self.env.user.lang)
|
||||
week_start = int(lang.week_start)
|
||||
# lang.week_start ranges from '1' to '7'
|
||||
# rrule expects an int from 0 to 6
|
||||
return rrule.weekday(week_start - 1)
|
||||
|
||||
def _get_week_days(self):
|
||||
return tuple(
|
||||
rrule.weekday(weekday_index)
|
||||
for weekday_index, weekday in {
|
||||
rrule.MO.weekday: self.mon,
|
||||
rrule.TU.weekday: self.tue,
|
||||
rrule.WE.weekday: self.wed,
|
||||
rrule.TH.weekday: self.thu,
|
||||
rrule.FR.weekday: self.fri,
|
||||
rrule.SA.weekday: self.sat,
|
||||
rrule.SU.weekday: self.sun,
|
||||
}.items()
|
||||
if weekday
|
||||
)
|
||||
|
||||
def _get_rrule(self, dtstart=None):
|
||||
"""Builds the rrule from fields"""
|
||||
self.ensure_one()
|
||||
freq = self.rrule_type
|
||||
rrule_params = dict(
|
||||
dtstart=dtstart,
|
||||
until=datetime.combine(self.until, datetime.max.time()),
|
||||
interval=self.interval,
|
||||
)
|
||||
if freq == "monthly" and self.month_by == "date":
|
||||
rrule_params["bymonthday"] = self.day
|
||||
elif freq == "monthly" and self.month_by == "day":
|
||||
rrule_params["byweekday"] = getattr(rrule, RRULE_WEEKDAYS[self.weekday])(
|
||||
int(self.byday)
|
||||
)
|
||||
elif freq == "weekly":
|
||||
weekdays = self._get_week_days()
|
||||
if not weekdays: # pragma: no cover
|
||||
raise ValidationError(
|
||||
_("You have to choose at least one day in the week")
|
||||
)
|
||||
rrule_params["byweekday"] = weekdays
|
||||
rrule_params["wkst"] = self._get_lang_week_start()
|
||||
return rrule.rrule(freq_to_rrule(freq), **rrule_params)
|
||||
|
||||
def _get_start_of_period(self):
|
||||
self.ensure_one()
|
||||
dtstart = datetime.combine(self.start, datetime.min.time())
|
||||
if self.rrule_type == "monthly":
|
||||
return dtstart - relativedelta(day=1)
|
||||
return dtstart
|
||||
|
||||
def _get_occurrences(self):
|
||||
self.ensure_one()
|
||||
dtstart = self._get_start_of_period()
|
||||
occurences = self._get_rrule(dtstart=dtstart)
|
||||
return list(occurences)
|
||||
|
||||
def _get_ranges(self):
|
||||
"""Generate ranges from the rrule
|
||||
|
||||
:return: list of tuples (start_dt, end_dt, extra_vals)
|
||||
"""
|
||||
self.ensure_one()
|
||||
res = []
|
||||
ocurrences = self._get_occurrences()
|
||||
duration = float_time_as_timedelta(self.duration)
|
||||
timezone = pytz.timezone(self.date_tz)
|
||||
timeslot_times = [float_time_as_time(t.time) for t in self.timeslot_ids]
|
||||
for dtstart in ocurrences:
|
||||
for tslot, ttime in zip(self.timeslot_ids, timeslot_times):
|
||||
start = datetime.combine(dtstart, ttime)
|
||||
start_utc = (
|
||||
timezone.localize(start, is_dst=False)
|
||||
.astimezone(pytz.utc)
|
||||
.replace(tzinfo=None)
|
||||
)
|
||||
extra_vals = tslot._prepare_session_extra_vals()
|
||||
res.append((start_utc, start_utc + duration, extra_vals))
|
||||
return res
|
||||
|
||||
def _prepare_session_vals(self, date_begin, date_end):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"event_id": self.event_id.id,
|
||||
"date_begin": date_begin,
|
||||
"date_end": date_end,
|
||||
}
|
||||
|
||||
def _create_sessions(self):
|
||||
"""Create sessions"""
|
||||
self.ensure_one()
|
||||
session_vals = []
|
||||
for date_begin, date_end, extra_vals in self._get_ranges():
|
||||
vals = self._prepare_session_vals(date_begin, date_end)
|
||||
vals.update(extra_vals)
|
||||
session_vals.append(vals)
|
||||
return self.env["event.session"].create(session_vals)
|
||||
|
||||
def action_create_sessions(self):
|
||||
self.ensure_one()
|
||||
sessions = self._create_sessions()
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"event_session.act_event_session_event_form"
|
||||
)
|
||||
action["domain"] = [("id", "in", sessions.ids)]
|
||||
action["context"] = {
|
||||
"default_event_id": self.event_id.id,
|
||||
"search_default_event_id": self.event_id.id,
|
||||
}
|
||||
return action
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<record id="act_wizard_event_session" model="ir.actions.act_window">
|
||||
<field name="name">Create Sessions</field>
|
||||
<field name="res_model">wizard.event.session</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
<record id="view_event_form_create_sessions" model="ir.ui.view">
|
||||
<field name="model">event.event</field>
|
||||
<field name="inherit_id" ref="event.view_event_form" />
|
||||
<field name="arch" type="xml">
|
||||
<header position="inside">
|
||||
<button
|
||||
string="Create Sessions"
|
||||
name="%(act_wizard_event_session)d"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('use_sessions', '=', False)]}"
|
||||
type="action"
|
||||
/>
|
||||
</header>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_wizard_event_session_form" model="ir.ui.view">
|
||||
<field name="model">wizard.event.session</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="schedule" string="Schedule">
|
||||
<group name="rrule">
|
||||
<label string="From" for="start" />
|
||||
<div class="o_row">
|
||||
<field
|
||||
name="start"
|
||||
widget="daterange"
|
||||
nolabel="1"
|
||||
class="oe_inline"
|
||||
options="{'related_end_date': 'until'}"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-long-arrow-right mx-2"
|
||||
aria-label="Arrow icon"
|
||||
title="Arrow"
|
||||
/>
|
||||
<field
|
||||
name="until"
|
||||
widget="daterange"
|
||||
nolabel="1"
|
||||
class="oe_inline"
|
||||
options="{'related_start_date': 'start'}"
|
||||
/>
|
||||
</div>
|
||||
<label for="interval" string="Repeat Every" />
|
||||
<div class="o_col">
|
||||
<div class="o_row">
|
||||
<field name="interval" />
|
||||
<field name="rrule_type" />
|
||||
</div>
|
||||
<widget
|
||||
name="week_days"
|
||||
attrs="{'invisible': [('rrule_type', '!=', 'weekly')]}"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
string="Day of Month"
|
||||
for="month_by"
|
||||
attrs="{'invisible': [('rrule_type', '!=', 'monthly')]}"
|
||||
/>
|
||||
<div
|
||||
class="o_row"
|
||||
attrs="{'invisible': [('rrule_type', '!=', 'monthly')]}"
|
||||
>
|
||||
<field name="month_by" />
|
||||
<field
|
||||
name="day"
|
||||
attrs="{'required': [('month_by', '=', 'date'), ('rrule_type', '=', 'monthly')],
|
||||
'invisible': [('month_by', '!=', 'date')]}"
|
||||
/>
|
||||
<field
|
||||
name="byday"
|
||||
string="The"
|
||||
attrs="{'required': [('month_by', '=', 'day'), ('rrule_type', '=', 'monthly')],
|
||||
'invisible': [('month_by', '!=', 'day')]}"
|
||||
/>
|
||||
<field
|
||||
name="weekday"
|
||||
nolabel="1"
|
||||
attrs="{'required': [('month_by', '=', 'day'), ('rrule_type', '=', 'monthly')],
|
||||
'invisible': [('month_by', '!=', 'day')]}"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="time">
|
||||
<field name="event_id" invisible="1" />
|
||||
<field name="date_tz" />
|
||||
<field
|
||||
name="timeslot_ids"
|
||||
string="At"
|
||||
widget="many2many_tags"
|
||||
/>
|
||||
<field name="duration" widget="float_time" />
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="action_create_sessions"
|
||||
type="object"
|
||||
string="Create Sessions"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button special="cancel" string="Cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue