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

# -*- 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")