You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
14 KiB
271 lines
14 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Vishnu KP (odoo@cybrosys.com)
|
|
#
|
|
# You can modify it under the terms of the GNU AFFERO
|
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
# (AGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
###############################################################################
|
|
from datetime import timedelta, date
|
|
from dateutil.relativedelta import relativedelta
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class RecurringActivity(models.Model):
|
|
"""It handles the activity scheduled in recurring mode."""
|
|
_name = 'recurring.activity'
|
|
_description = 'Recurring Activity'
|
|
|
|
name = fields.Char(string='Name', help='Enter the name of the recurring '
|
|
'activity', required=True)
|
|
activity_type_id = fields.Many2one('mail.activity.type',
|
|
string='Activity',
|
|
help='Which activity you want to '
|
|
'schedule the recurring',
|
|
required=True)
|
|
user_id = fields.Many2one('res.users', string='Assigned to',
|
|
help='Who are the responsible person to assign'
|
|
' the activity')
|
|
summary = fields.Char(string='Summary',help='Discussion proposal',
|
|
required=True)
|
|
note = fields.Text(string='Note', help='Any kind of notes if you want to '
|
|
'share with the activity')
|
|
period = fields.Selection([('day', 'Days'), ('week', 'Weeks'),
|
|
('month', 'Months'), ('year', 'Years')],
|
|
string='Repeat Every',
|
|
help='Number of period to be recurring the '
|
|
'activity', default="day", required=True)
|
|
create_date = fields.Date(string='Activity Create Date',
|
|
help='Create date of the activity',
|
|
default=fields.Date.today)
|
|
next_activity_date = fields.Date(string='Next Activity Date',
|
|
help='Remaining the next activity day',
|
|
copy=False)
|
|
archive_date = fields.Date(string='Recurring Deadline',
|
|
help='The date after which this rule will be'
|
|
' archived and no more recurrent activity '
|
|
'will be created', required=True)
|
|
monday = fields.Boolean(string='Monday',
|
|
help='You will choose this day it'
|
|
' repeat every monday in a week ')
|
|
tues = fields.Boolean(string='Tuesday',
|
|
help='You will choose this day it'
|
|
' repeat every Tuesday in a week ')
|
|
wed = fields.Boolean(string='Wednesday',
|
|
help='You will choose this day it'
|
|
' repeat every Wednesday in a week ')
|
|
thus = fields.Boolean(string='Thursday',
|
|
help='You will choose this day it'
|
|
' repeat every Thursday in a week ')
|
|
fri = fields.Boolean(string='Friday',
|
|
help='You will choose this day it'
|
|
' repeat every Friday in a week ')
|
|
sat = fields.Boolean(string='Saturday',
|
|
help='You will choose this day it'
|
|
' repeat every Saturday in a week ')
|
|
sun = fields.Boolean(string='Sunday',
|
|
help='You will choose this day it'
|
|
' repeat every Sunday in a week ')
|
|
action = fields.Reference(selection=[('sale.order', 'Sale Orders'),
|
|
('purchase.order', 'Purchase Orders'),
|
|
('res.partner', 'Contact'),
|
|
('account.journal', 'Journal'),
|
|
('res.partner', 'Employees'),
|
|
('crm.lead', 'Lead/Opportunity'),
|
|
('product.template', 'Product'),
|
|
('product.product', 'Product Variant'),
|
|
('project.task', 'Task'),
|
|
],
|
|
string='Action',
|
|
help='Choose the reference document you want to '
|
|
'set a recurring activity.')
|
|
year_date = fields.Integer(string='Date',
|
|
help='Periodicity of the recurring activity '
|
|
'in year')
|
|
year_months = fields.Selection([('1', 'January'), ('2', 'February'),
|
|
('3', 'March'), ('4', 'April'),
|
|
('5', 'May'),
|
|
('6', 'June'), ('7', 'July'),
|
|
('8', 'August'), ('9', 'September'),
|
|
('10', 'October'), ('11', 'November'),
|
|
('12', 'December')], string='Month',
|
|
help='You can choose e month.It repeat every'
|
|
' the chose month')
|
|
month_by = fields.Selection([('first', 'The First Day'),
|
|
('last', 'The Last Day'),
|
|
('date', 'Date of Month'),
|
|
],
|
|
string='Day of Month',
|
|
help='Choose the month base recurring activity',
|
|
defualt='date')
|
|
date_of_month = fields.Integer(string='Date of Month',
|
|
help='Repeat the activity every date of the'
|
|
' chose month', default=1)
|
|
|
|
def _get_weekdays(self):
|
|
"""Get a list of selected weekdays based on user input."""
|
|
weekdays = []
|
|
if self.monday:
|
|
weekdays.append('Mon')
|
|
if self.tues:
|
|
weekdays.append('Tue')
|
|
if self.wed:
|
|
weekdays.append('Wed')
|
|
if self.thus:
|
|
weekdays.append('Thu')
|
|
if self.fri:
|
|
weekdays.append('Fri')
|
|
if self.sat:
|
|
weekdays.append('Sat')
|
|
if self.sun:
|
|
weekdays.append('Sun')
|
|
return weekdays
|
|
|
|
def _get_next_recurring_dates(self):
|
|
"""Calculate the next recurring activity dates based on defined
|
|
rules."""
|
|
next_dates = []
|
|
# Calculate the next date based on the selected options
|
|
current_date = date.today()
|
|
if current_date < self.archive_date:
|
|
if self.period == 'day':
|
|
next_dates.append(current_date)
|
|
elif self.period == 'week':
|
|
weekdays = self._get_weekdays()
|
|
if not weekdays:
|
|
raise ValidationError('Please choose a specific day for '
|
|
'the recurring activity.')
|
|
while current_date <= self.archive_date:
|
|
if current_date.strftime('%a') in weekdays:
|
|
next_dates.append(current_date.strftime("%Y-%m-%d"))
|
|
current_date += timedelta(days=1)
|
|
elif self.period == 'month':
|
|
if self.month_by == 'first':
|
|
next_month_date = (current_date + relativedelta(months=1)
|
|
).replace(day=1)
|
|
next_dates.append(next_month_date)
|
|
elif self.month_by == 'last':
|
|
# Calculate the last day of the current month
|
|
last_day_date_current_month = current_date.replace(
|
|
day=1) + relativedelta(months=1, days=-1)
|
|
# If the current date is before the last day, its start the
|
|
# current month
|
|
if current_date <= last_day_date_current_month:
|
|
next_dates.append(last_day_date_current_month)
|
|
else:
|
|
# Otherwise, set recurrence start last day of the
|
|
# next month
|
|
next_month_date = (current_date + relativedelta(
|
|
day=31)).replace(day=1)
|
|
last_day_date_next_month = (next_month_date +
|
|
relativedelta(
|
|
months=1, days=-1))
|
|
next_dates.append(last_day_date_next_month)
|
|
elif self.month_by == 'date':
|
|
try:
|
|
next_month_date = (current_date + relativedelta())
|
|
selected_date = next_month_date.replace(
|
|
day=self.date_of_month)
|
|
next_dates.append(selected_date)
|
|
except Exception as e:
|
|
raise ValidationError(_(f"Error: {e}. Invalid date of"
|
|
f" the month specified."))
|
|
else:
|
|
raise ValidationError(_('Please select a recurring activity'
|
|
'type for the month.'))
|
|
elif self.period == 'year':
|
|
if not self.year_date or not self.year_months:
|
|
raise ValidationError(_("Both Date and month are "
|
|
"required for yearly recurrence."))
|
|
month_integer = int(self.year_months)
|
|
# Get the current month
|
|
current_month = self.create_date.month
|
|
# Calculate the next date for yearly recurrence
|
|
if current_month <= month_integer:
|
|
# If the current month is on or before the specified month,
|
|
# set the next_year_date in the same year
|
|
next_year_date = self.create_date.replace(
|
|
month=month_integer)
|
|
else:
|
|
# If the current month is after the specified month,
|
|
# set the next_year_date in the next year
|
|
next_year_date = self.create_date.replace(
|
|
month=month_integer, year=self.create_date.year + 1)
|
|
next_month_date = next_year_date.replace(day=self.year_date)
|
|
next_dates.append(next_month_date)
|
|
else:
|
|
next_dates.append(self.archive_date)
|
|
if next_dates:
|
|
self.next_activity_date = next_dates[
|
|
0] # Set the next activity date
|
|
return next_dates
|
|
|
|
def create_recurring_activities(self):
|
|
"""Create recurring activities based on calculated dates."""
|
|
records = self.env['recurring.activity'].search([])
|
|
for rec in records:
|
|
next_dates = rec._get_next_recurring_dates()
|
|
# Create recurring activities for each next date
|
|
self.env['mail.activity'].create({
|
|
'activity_type_id': rec.activity_type_id.id,
|
|
'user_id': rec.user_id.id,
|
|
'date_deadline': next_dates[0],
|
|
'note': rec.note,
|
|
'summary': rec.summary,
|
|
'res_model_id': rec.env['ir.model']._get_id(rec.action._name),
|
|
'res_id': rec.action.id
|
|
})
|
|
|
|
def create_recurring_activities_record(self):
|
|
"""Create recurring activities based on calculated dates."""
|
|
next_dates = self._get_next_recurring_dates()
|
|
# Create recurring activities for each next date
|
|
self.env['mail.activity'].create({
|
|
'activity_type_id': self.activity_type_id.id,
|
|
'user_id': self.user_id.id,
|
|
'date_deadline': next_dates[0],
|
|
'note': self.note,
|
|
'summary': self.summary,
|
|
'res_model_id': self.env['ir.model']._get_id(self.action._name),
|
|
'res_id': self.action.id
|
|
})
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""
|
|
Create and schedule recurring activities when a new record is created.
|
|
|
|
:param vals_list: List of field values for the new record.
|
|
:return: Created record.
|
|
"""
|
|
res = super().create(vals_list)
|
|
if not vals_list[0]['action']:
|
|
raise ValidationError(_("Please choose the record for the "
|
|
"recurring activity."))
|
|
res.create_recurring_activities_record()
|
|
return res
|
|
|
|
@api.constrains('create_date', 'archive_date')
|
|
def _compute_archive_date(self):
|
|
"""This method is used to check whether the 'archive_date' is greater
|
|
than or equal to the 'create_date' for each record. If 'archive_date'
|
|
is less than 'create_date', it raises a validation error with the
|
|
message "The dealing should be greater than the created date." """
|
|
for record in self:
|
|
if record.archive_date < record.create_date:
|
|
raise ValidationError("The dealing should be grater "
|
|
"than the created date")
|
|
|