From d448713449e75d5931aeabf2ed74e550b98e9377 Mon Sep 17 00:00:00 2001 From: Bhagya-K Date: Mon, 22 Jun 2026 15:01:12 +0530 Subject: [PATCH] DEV: Probation Tracking --- .../firebase_integration/models/__init__.py | 2 + .../models/mail_activity.py | 74 ++++++++++++++ .../tools/firebase_service.py | 30 ++++++ .../models/recruitment_attachments.py | 24 +++++ .../views/recruitment_attachments.xml | 5 +- .../models/weekly_period_timesheets.py | 63 ++++++++++++ .../weekly_timesheets/views/mail_template.xml | 98 ++++++++++--------- .../views/weekly_period_timesheets.xml | 5 + 8 files changed, 251 insertions(+), 50 deletions(-) create mode 100644 addons_extensions/firebase_integration/models/__init__.py create mode 100644 addons_extensions/firebase_integration/models/mail_activity.py create mode 100644 addons_extensions/firebase_integration/tools/firebase_service.py diff --git a/addons_extensions/firebase_integration/models/__init__.py b/addons_extensions/firebase_integration/models/__init__.py new file mode 100644 index 000000000..53a8d88e7 --- /dev/null +++ b/addons_extensions/firebase_integration/models/__init__.py @@ -0,0 +1,2 @@ +from . import discuss_channel_notify +from . import mail_activity \ No newline at end of file diff --git a/addons_extensions/firebase_integration/models/mail_activity.py b/addons_extensions/firebase_integration/models/mail_activity.py new file mode 100644 index 000000000..1e906cb67 --- /dev/null +++ b/addons_extensions/firebase_integration/models/mail_activity.py @@ -0,0 +1,74 @@ +from odoo import models +import logging +import re + +_logger = logging.getLogger(__name__) + + +class MailTemplate(models.Model): + _inherit = "mail.template" + + def send_mail( + self, + res_id, + force_send=False, + raise_exception=False, + email_values=None, + ): + + record = self.env[self.model].browse(res_id) + + # determine recipient directly from business object + recipient_user = False + + if self.model == "weekly.periodtimesheets": + + if "Submitted" in (self.subject or ""): + recipient_user = ( + record.employee_id.parent_id.user_id + ) + + elif ( + "Approved" in (self.subject or "") + or "Rejected" in (self.subject or "") + ): + recipient_user = ( + record.employee_id.user_id + ) + + mail_id = super().send_mail( + res_id, + force_send=force_send, + raise_exception=raise_exception, + email_values=email_values, + ) + + try: + if ( + recipient_user + and recipient_user.token + ): + self.env["firebase.service"].send_notification([ + { + "token": recipient_user.token, + "title": self.subject or "Notification", + "body": "You have received a new email notification", + "data": { + "mail_id": str(mail_id), + "model": self.model, + "record_id": str(res_id), + }, + } + ]) + + _logger.info( + "Firebase sent to %s", + recipient_user.name, + ) + + except Exception: + _logger.exception( + "Firebase notification failed" + ) + + return mail_id \ No newline at end of file diff --git a/addons_extensions/firebase_integration/tools/firebase_service.py b/addons_extensions/firebase_integration/tools/firebase_service.py new file mode 100644 index 000000000..32361addb --- /dev/null +++ b/addons_extensions/firebase_integration/tools/firebase_service.py @@ -0,0 +1,30 @@ +from odoo import models,fields +from ..tools.firebase import send_firebase_notifications + +class FirebaseService(models.AbstractModel): + _name = "firebase.service" + _description = "Firebase Service" + + def send_notification(self, messages): + return send_firebase_notifications(messages) + + +class ResUsers(models.Model): + _inherit = "res.users" + + token = fields.Char(string="Firebase Token") + + def send_push_notification(self, title, body, data=None): + self.ensure_one() + + if not self.token: + return False + + return self.env['firebase.service'].send_notification([ + { + 'token': self.token, + 'title': title, + 'body': body, + 'data': data or {}, + } + ]) diff --git a/addons_extensions/hr_recruitment_extended/models/recruitment_attachments.py b/addons_extensions/hr_recruitment_extended/models/recruitment_attachments.py index b410b68d0..3ca8395f8 100644 --- a/addons_extensions/hr_recruitment_extended/models/recruitment_attachments.py +++ b/addons_extensions/hr_recruitment_extended/models/recruitment_attachments.py @@ -1,4 +1,7 @@ from odoo import models, fields, api +from odoo.exceptions import ValidationError +import base64 +import os class RecruitmentAttachments(models.Model): _name = 'recruitment.attachments' @@ -22,9 +25,30 @@ class EmployeeRecruitmentAttachments(models.Model): recruitment_attachment_id = fields.Many2one('recruitment.attachments') recruitment_attachment_type = fields.Selection([('personal','Personal Documents'),('education','Education Documents'),('previous_employer','Previous Employer'),('others','Others')],related='recruitment_attachment_id.attachment_type') file = fields.Binary(string='File', required=True) + file_name = fields.Char(string='Filename') review_status = fields.Selection([('draft','Under Review'),('pass','PASS'),('fail','FAIL')], default='draft') review_comments = fields.Char() + @api.constrains('file', 'file_name') + def _check_file_validation(self): + allowed_extensions = ['pdf', 'doc', 'jpg', 'jpeg'] + + for rec in self: + if rec.file and rec.file_name: + extension = os.path.splitext(rec.file_name)[1].lower().replace('.', '') + + if extension not in allowed_extensions: + raise ValidationError( + "Only PDF, DOC and JPG files are allowed." + ) + + file_size = len(base64.b64decode(rec.file)) + + if file_size > 5 * 1024 * 1024: + raise ValidationError( + "File size cannot exceed 5 MB." + ) + def action_preview_file(self): """ Returns a URL to preview the attachment in a popup """ for record in self: diff --git a/addons_extensions/hr_recruitment_extended/views/recruitment_attachments.xml b/addons_extensions/hr_recruitment_extended/views/recruitment_attachments.xml index ef700f955..419d218ab 100644 --- a/addons_extensions/hr_recruitment_extended/views/recruitment_attachments.xml +++ b/addons_extensions/hr_recruitment_extended/views/recruitment_attachments.xml @@ -29,7 +29,7 @@ - + @@ -51,7 +51,8 @@ - + + diff --git a/addons_extensions/weekly_timesheets/models/weekly_period_timesheets.py b/addons_extensions/weekly_timesheets/models/weekly_period_timesheets.py index 5427324a8..e71f9a402 100644 --- a/addons_extensions/weekly_timesheets/models/weekly_period_timesheets.py +++ b/addons_extensions/weekly_timesheets/models/weekly_period_timesheets.py @@ -51,6 +51,7 @@ class WeeklyPeriodTimesheets(models.Model): ('draft', 'Draft'), ('submitted', 'Submitted'), ('approved', 'Approved'), + ('rejected', 'Rejected'), ], string="Status", default='draft') def action_submit(self): @@ -92,6 +93,39 @@ class WeeklyPeriodTimesheets(models.Model): force_send=True ) + def action_reject(self): + + for rec in self: + analytic_lines = self.env[ + 'account.analytic.line' + ].search([ + ('employee_id', '=', rec.employee_id.id), + ('date', '>=', rec.week_line_id.date_from), + ('date', '<=', rec.week_line_id.date_to), + ]) + + for line in analytic_lines: + + vals = { + 'weekly_submitted': True + } + + if not line.pm_approval_required: + vals['approval_state'] = 'rejected' + + line.write(vals) + + rec.state = 'rejected' + + template = self.env.ref( + 'weekly_timesheets.email_template_weekly_timesheet_reject' + ) + + if template: + template.send_mail( + rec.id, + force_send=True + ) def action_approve(self): for rec in self: @@ -133,6 +167,35 @@ class WeeklyPeriodTimesheets(models.Model): ) rec.state = 'approved' + template = self.env.ref( + 'weekly_timesheets.email_template_weekly_timesheet_approve' + ) + + if template: + template.send_mail( + rec.id, + force_send=True + ) + employee_user = rec.employee_id.user_id + + if employee_user and employee_user.token: + self.env['firebase.service'].send_notification([ + { + 'token': employee_user.token, + 'title': 'Timesheet Approved', + 'body': ( + f'Your timesheet for ' + f'{rec.week_line_id.date_from} ' + f'to ' + f'{rec.week_line_id.date_to} ' + f'has been approved.' + ), + 'data': { + 'type': 'timesheet_approved', + 'timesheet_id': str(rec.id), + } + } + ]) def action_reset_to_draft(self): for rec in self: diff --git a/addons_extensions/weekly_timesheets/views/mail_template.xml b/addons_extensions/weekly_timesheets/views/mail_template.xml index f531d328d..e3e210fc6 100644 --- a/addons_extensions/weekly_timesheets/views/mail_template.xml +++ b/addons_extensions/weekly_timesheets/views/mail_template.xml @@ -1,59 +1,61 @@ - - - - Weekly Timesheet Submitted - - - - - - Weekly Timesheet Submitted - ${object.employee_id.name} - - - - ${user.email | safe} - - - - ${object.employee_id.parent_id.work_email} - - + + Weekly Timesheet Submitted + + Weekly Timesheet Submitted - ${object.employee_id.name} + ${user.email | safe} + ${object.employee_id.parent_id.work_email} -

Hello,

- -

- Employee - ${object.employee_id.name} - has submitted the weekly timesheet. -

- -

- Week: - ${object.week_line_id.name} -

- -

- Total Hours: - ${object.total_hours} -

- -

- Please review and approve. -

- +

Employee${object.employee_id.name} has submitted the weekly timesheet.

+

Week: ${object.week_line_id.name}

+

Total Hours: ${object.total_hours}

+

Please review and approve.

+
+

Thank You

+
+
+
+ + Weekly Timesheet Rejected + + Weekly Timesheet Rejected - ${object.employee_id.name} + ${user.email | safe} + ${object.employee_id.work_email} + +
+

Hello,

+

Employee${object.employee_id.name}has rejected the weekly timesheet.

+

Week: ${object.week_line_id.name}

+

Total Hours: ${object.total_hours}

+
+

Thank You

+
+
+
+ + Weekly Timesheet Approved + + Weekly Timesheet Approved - ${object.employee_id.name} + ${user.email | safe} + ${object.employee_id.work_email} + +
+

Hello,

+

+ Employee${object.employee_id.name}has approved the weekly timesheet. +

+

+ Week: ${object.week_line_id.name} +

+

+ Total Hours: ${object.total_hours} +


-

Thank You

-
-
-
\ No newline at end of file diff --git a/addons_extensions/weekly_timesheets/views/weekly_period_timesheets.xml b/addons_extensions/weekly_timesheets/views/weekly_period_timesheets.xml index ebc6a7cff..8759880fa 100644 --- a/addons_extensions/weekly_timesheets/views/weekly_period_timesheets.xml +++ b/addons_extensions/weekly_timesheets/views/weekly_period_timesheets.xml @@ -13,6 +13,11 @@ type="object" class="btn-primary" invisible="state != 'draft'"/> +