attendance, leaves, weekly timesheets enhancements
This commit is contained in:
parent
3092032fee
commit
b5f643fb18
|
|
@ -0,0 +1 @@
|
||||||
|
from . import models
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
'name': 'Grace period Attendance',
|
||||||
|
'version': '18.0.1.0.0',
|
||||||
|
'category': 'Human Resources',
|
||||||
|
'summary': 'Attendances grace Period',
|
||||||
|
'author': 'Srivyn Platforms',
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
|
||||||
|
'depends': [
|
||||||
|
'hr',
|
||||||
|
'hr_attendance',
|
||||||
|
'hr_holidays',
|
||||||
|
'resource',
|
||||||
|
'hr_attendance_extended',
|
||||||
|
],
|
||||||
|
|
||||||
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'data/resource_calendar_weekday_data.xml',
|
||||||
|
'data/sequence.xml',
|
||||||
|
'views/resource_calendar_period.xml',
|
||||||
|
'views/attendance_data.xml',
|
||||||
|
'views/late_coming_request.xml',
|
||||||
|
'views/hr_employee_inherit.xml',
|
||||||
|
'views/late_coming_mail_template.xml',
|
||||||
|
# 'security/record_rules.xml',
|
||||||
|
],
|
||||||
|
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<odoo noupdate="1">
|
||||||
|
|
||||||
|
<record id="weekday_monday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Monday</field>
|
||||||
|
<field name="code">0</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_tuesday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Tuesday</field>
|
||||||
|
<field name="code">1</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_wednesday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Wednesday</field>
|
||||||
|
<field name="code">2</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_thursday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Thursday</field>
|
||||||
|
<field name="code">3</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_friday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Friday</field>
|
||||||
|
<field name="code">4</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_saturday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Saturday</field>
|
||||||
|
<field name="code">5</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="weekday_sunday"
|
||||||
|
model="resource.calendar.weekday">
|
||||||
|
<field name="name">Sunday</field>
|
||||||
|
<field name="code">6</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="seq_late_coming_request"
|
||||||
|
model="ir.sequence">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="code">
|
||||||
|
late.coming.request
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="prefix">
|
||||||
|
LCR/
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="padding">
|
||||||
|
5
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
from . import resource_calendar_period
|
||||||
|
from . import late_coming_request
|
||||||
|
from . import attendance_data
|
||||||
|
from. import hr_employee_inherit
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,34 @@
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class HREmployee(models.Model):
|
||||||
|
_inherit = 'hr.employee'
|
||||||
|
|
||||||
|
attendance_analytics_count = fields.Integer(
|
||||||
|
string="Attendance Count",
|
||||||
|
compute="_compute_attendance_analytics_count"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compute_attendance_analytics_count(self):
|
||||||
|
|
||||||
|
analytics = self.env['attendance.analytics']
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
rec.attendance_analytics_count = analytics.search_count([
|
||||||
|
('employee_id', '=', rec.id)
|
||||||
|
])
|
||||||
|
|
||||||
|
def action_open_attendance_analytics(self):
|
||||||
|
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'name': 'Attendance Sheet',
|
||||||
|
'res_model': 'attendance.analytics',
|
||||||
|
'view_mode': 'list,pivot,graph',
|
||||||
|
'domain': [('employee_id', '=', self.id)],
|
||||||
|
'context': {
|
||||||
|
'search_default_employee_id': self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
from odoo import fields, models, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
|
class LateComingRequest(models.Model):
|
||||||
|
_name = 'late.coming.request'
|
||||||
|
_description = 'Late Coming Request'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
_rec_name = 'employee_id'
|
||||||
|
|
||||||
|
|
||||||
|
employee_id = fields.Many2one(
|
||||||
|
'hr.employee',
|
||||||
|
string="Employee",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
manager_id = fields.Many2one(
|
||||||
|
'hr.employee',
|
||||||
|
related='employee_id.parent_id',
|
||||||
|
store=True,
|
||||||
|
string="Manager"
|
||||||
|
)
|
||||||
|
|
||||||
|
department_id = fields.Many2one(
|
||||||
|
'hr.department',
|
||||||
|
related='employee_id.department_id',
|
||||||
|
store=True,
|
||||||
|
string="Department"
|
||||||
|
)
|
||||||
|
|
||||||
|
attendance_date = fields.Date(
|
||||||
|
string="Attendance Date"
|
||||||
|
)
|
||||||
|
|
||||||
|
check_in = fields.Datetime(
|
||||||
|
string="Check In"
|
||||||
|
)
|
||||||
|
|
||||||
|
worked_hours = fields.Float(
|
||||||
|
string="Worked Hours"
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_check_in = fields.Float(
|
||||||
|
string="Expected Check In"
|
||||||
|
)
|
||||||
|
|
||||||
|
late_minutes = fields.Float(
|
||||||
|
string="Late Minutes"
|
||||||
|
)
|
||||||
|
|
||||||
|
department_grace_period = fields.Integer(
|
||||||
|
string="Department Grace Period"
|
||||||
|
)
|
||||||
|
|
||||||
|
required_checkout_time = fields.Float(
|
||||||
|
string="Required Checkout Time"
|
||||||
|
)
|
||||||
|
|
||||||
|
compensation_pending = fields.Boolean(
|
||||||
|
string="Compensation Pending"
|
||||||
|
)
|
||||||
|
|
||||||
|
compensation_minutes = fields.Float(
|
||||||
|
string="Compensation Minutes"
|
||||||
|
)
|
||||||
|
|
||||||
|
reason = fields.Text(
|
||||||
|
string="Reason"
|
||||||
|
)
|
||||||
|
|
||||||
|
manager_comment = fields.Text(
|
||||||
|
string="Manager Comment"
|
||||||
|
)
|
||||||
|
|
||||||
|
status_message = fields.Char(
|
||||||
|
string="Status"
|
||||||
|
)
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
|
||||||
|
('draft', 'Draft'),
|
||||||
|
|
||||||
|
('submitted', 'Submitted'),
|
||||||
|
|
||||||
|
('approved', 'Approved'),
|
||||||
|
|
||||||
|
('rejected', 'Rejected')
|
||||||
|
|
||||||
|
],
|
||||||
|
string="Status",
|
||||||
|
default='draft'
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_submit(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if not rec.reason:
|
||||||
|
raise UserError(
|
||||||
|
_("Please enter reason.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not rec.manager_id:
|
||||||
|
raise UserError(
|
||||||
|
_("Manager not configured.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not rec.manager_id.work_email:
|
||||||
|
raise UserError(
|
||||||
|
_("Manager work email not configured.")
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.state = 'submitted'
|
||||||
|
|
||||||
|
template = self.env.ref(
|
||||||
|
'grace_period.email_template_late_coming_request'
|
||||||
|
)
|
||||||
|
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
rec.message_post(
|
||||||
|
body=_("Request Submitted.")
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_approve(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if (
|
||||||
|
rec.manager_id.user_id != self.env.user
|
||||||
|
and not self.env.user.has_group(
|
||||||
|
'hr.group_hr_manager'
|
||||||
|
)
|
||||||
|
):
|
||||||
|
|
||||||
|
raise UserError(
|
||||||
|
_("Only Manager or HR can approve.")
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.state = 'approved'
|
||||||
|
|
||||||
|
def action_reject(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if (
|
||||||
|
rec.manager_id.user_id != self.env.user
|
||||||
|
and not self.env.user.has_group(
|
||||||
|
'hr.group_hr_manager'
|
||||||
|
)
|
||||||
|
):
|
||||||
|
|
||||||
|
raise UserError(
|
||||||
|
_("Only Manager or HR can reject.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not rec.employee_id.work_email:
|
||||||
|
|
||||||
|
raise UserError(
|
||||||
|
_("Employee work email not configured.")
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.state = 'rejected'
|
||||||
|
|
||||||
|
template = self.env.ref(
|
||||||
|
'grace_period.email_template_late_coming_rejected'
|
||||||
|
)
|
||||||
|
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
rec.message_post(
|
||||||
|
body=_("Request Rejected.")
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_reset_to_draft(self):
|
||||||
|
|
||||||
|
self.state = 'draft'
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
from odoo import api, fields, models, tools
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceCalendar(models.Model):
|
||||||
|
_inherit = 'resource.calendar'
|
||||||
|
|
||||||
|
weekday_ids = fields.Many2many(
|
||||||
|
'resource.calendar.weekday',
|
||||||
|
'resource_calendar_weekday_rel',
|
||||||
|
'calendar_id',
|
||||||
|
'weekday_id',
|
||||||
|
string="Weekdays"
|
||||||
|
)
|
||||||
|
|
||||||
|
weekend_ids = fields.Many2many(
|
||||||
|
'resource.calendar.weekday',
|
||||||
|
'resource_calendar_weekend_rel',
|
||||||
|
'calendar_id',
|
||||||
|
'weekday_id',
|
||||||
|
string="Weekends"
|
||||||
|
)
|
||||||
|
|
||||||
|
shift_start_time = fields.Float(string="Start Time")
|
||||||
|
shift_end_time = fields.Float(string="End Time")
|
||||||
|
late_grace_period = fields.Integer(default=15)
|
||||||
|
early_out_grace_period = fields.Integer(default=0)
|
||||||
|
department_grace_ids = fields.One2many(
|
||||||
|
'resource.calendar.department.grace',
|
||||||
|
'calendar_id',
|
||||||
|
string="Department Grace Periods"
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_generate_schedule(self):
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
attendance_commands = [(5, 0, 0)]
|
||||||
|
|
||||||
|
added_days = []
|
||||||
|
|
||||||
|
for day in rec.weekday_ids:
|
||||||
|
|
||||||
|
# Avoid duplicate weekdays
|
||||||
|
if day.code in added_days:
|
||||||
|
continue
|
||||||
|
|
||||||
|
added_days.append(day.code)
|
||||||
|
|
||||||
|
attendance_commands.append((0, 0, {
|
||||||
|
'name': day.name,
|
||||||
|
'dayofweek': day.code,
|
||||||
|
'hour_from': rec.shift_start_time,
|
||||||
|
'hour_to': rec.shift_end_time,
|
||||||
|
}))
|
||||||
|
|
||||||
|
# Single write operation
|
||||||
|
rec.write({
|
||||||
|
'attendance_ids': attendance_commands
|
||||||
|
})
|
||||||
|
|
||||||
|
# ------------------------------------
|
||||||
|
# Department Grace Period Generation
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
department_commands = [(5, 0, 0)]
|
||||||
|
|
||||||
|
departments = self.env['hr.department'].search([])
|
||||||
|
|
||||||
|
for dept in departments:
|
||||||
|
department_commands.append((0, 0, {
|
||||||
|
'department_id': dept.id,
|
||||||
|
'grace_period': 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
rec.write({
|
||||||
|
'department_grace_ids': department_commands
|
||||||
|
})
|
||||||
|
class ResourceCalendarWeekday(models.Model):
|
||||||
|
_name = 'resource.calendar.weekday'
|
||||||
|
_description = 'Weekday Master'
|
||||||
|
|
||||||
|
name = fields.Char(required=True)
|
||||||
|
|
||||||
|
code = fields.Selection([
|
||||||
|
('0', 'Monday'),
|
||||||
|
('1', 'Tuesday'),
|
||||||
|
('2', 'Wednesday'),
|
||||||
|
('3', 'Thursday'),
|
||||||
|
('4', 'Friday'),
|
||||||
|
('5', 'Saturday'),
|
||||||
|
('6', 'Sunday'),
|
||||||
|
], required=True)
|
||||||
|
|
||||||
|
class ResourceCalendarDepartmentGrace(models.Model):
|
||||||
|
_name = 'resource.calendar.department.grace'
|
||||||
|
_description = 'Department Wise Grace Period'
|
||||||
|
|
||||||
|
calendar_id = fields.Many2one(
|
||||||
|
'resource.calendar',
|
||||||
|
string="Working Schedule",
|
||||||
|
ondelete='cascade'
|
||||||
|
)
|
||||||
|
|
||||||
|
department_id = fields.Many2one(
|
||||||
|
'hr.department',
|
||||||
|
string="Department",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
grace_period = fields.Integer(
|
||||||
|
string="Grace Period (Minutes)",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_resource_calendar_weekday, resource_calendar_weekday,model_resource_calendar_weekday,base.group_user,1,1,1,1
|
||||||
|
access_attendance_analytics_user,attendance.analytics.user,model_attendance_analytics,base.group_user,1,0,0,0
|
||||||
|
access_attendance_analytics_manager,attendance.analytics.manager,model_attendance_analytics,hr.group_hr_manager,1,1,1,0
|
||||||
|
access_attendance_analytics_admin,attendance.analytics.admin,model_attendance_analytics,base.group_system,1,1,1,1
|
||||||
|
access_late_coming_request,attendance_late_coming_request,model_late_coming_request,base.group_user,1,1,1,1
|
||||||
|
access_resource_calendar_department_grace,resource_calendar_department_grace,model_resource_calendar_department_grace,base.group_user,1,1,1,1
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
<!-- EMPLOYEE: Can see only own attendance -->
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
|
||||||
|
<record id="attendance_analytics_employee_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Attendance Analytics - Employee Own Records
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_attendance_analytics"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
[('employee_id.user_id', '=', user.id)]
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('base.group_user'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
<!-- MANAGER: Can see subordinate employees -->
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
|
||||||
|
<record id="attendance_analytics_manager_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Attendance Analytics - Manager Records
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_attendance_analytics"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
|
||||||
|
[
|
||||||
|
'|',
|
||||||
|
|
||||||
|
('employee_id.user_id', '=', user.id),
|
||||||
|
|
||||||
|
('employee_id.parent_id.user_id', '=', user.id)
|
||||||
|
]
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('your_module_name.group_attendance_analytics_manager'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
<!-- ADMIN: Full Access -->
|
||||||
|
<!-- ===================================================== -->
|
||||||
|
|
||||||
|
<record id="attendance_analytics_admin_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Attendance Analytics - Admin Full Access
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_attendance_analytics"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
[(1, '=', 1)]
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('hr.group_hr_manager'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ================================================= -->
|
||||||
|
<!-- EMPLOYEE -->
|
||||||
|
<!-- ================================================= -->
|
||||||
|
|
||||||
|
<record id="late_coming_request_employee_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request Employee Rule
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_late_coming_request"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
[('employee_id.user_id', '=', user.id)]
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('base.group_user'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
<record id="late_coming_request_manager_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request Manager Rule
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_late_coming_request"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
|
||||||
|
[
|
||||||
|
'|',
|
||||||
|
('employee_id.user_id', '=', user.id),
|
||||||
|
('employee_id.parent_id.user_id', '=', user.id)
|
||||||
|
]
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('your_module.group_attendance_analytics_manager'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ================================================= -->
|
||||||
|
<!-- HR MANAGER FULL ACCESS -->
|
||||||
|
<!-- ================================================= -->
|
||||||
|
|
||||||
|
<record id="late_coming_request_hr_rule"
|
||||||
|
model="ir.rule">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request HR Rule
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_late_coming_request"/>
|
||||||
|
|
||||||
|
<field name="domain_force">
|
||||||
|
[(1, '=', 1)]
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="groups"
|
||||||
|
eval="[(4, ref('hr.group_hr_manager'))]"/>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- =============================================== -->
|
||||||
|
<!-- TREE VIEW -->
|
||||||
|
<!-- =============================================== -->
|
||||||
|
|
||||||
|
<record id="view_attendance_analytics_list" model="ir.ui.view">
|
||||||
|
<field name="name">attendance.analytics.list</field>
|
||||||
|
<field name="model">attendance.analytics</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Attendance Analytics">
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="department_id"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="min_check_in"/>
|
||||||
|
<field name="max_check_out"/>
|
||||||
|
<field name="worked_hours"/>
|
||||||
|
<field name="department_grace_period"/>
|
||||||
|
<field name="late_time"/>
|
||||||
|
<field name="early_out_time"/>
|
||||||
|
<field name="required_checkout_time" widget="float_time"/>
|
||||||
|
<field name="is_late"/>
|
||||||
|
<field name="is_early_out"/>
|
||||||
|
<field name="is_compensation_pending"/>
|
||||||
|
<field name="late_approved"/>
|
||||||
|
<field name="status_message"/>
|
||||||
|
<button name="action_create_late_request"
|
||||||
|
type="object"
|
||||||
|
string="Request Approval"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="
|
||||||
|
is_holiday == True
|
||||||
|
or is_week_off == True
|
||||||
|
or late_approved == True
|
||||||
|
or (
|
||||||
|
late_minutes == 0
|
||||||
|
and early_out_minutes == 0
|
||||||
|
)
|
||||||
|
"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- =============================================== -->
|
||||||
|
<!-- CALENDAR VIEW -->
|
||||||
|
<!-- =============================================== -->
|
||||||
|
|
||||||
|
<record id="view_attendance_analytics_calendar" model="ir.ui.view">
|
||||||
|
<field name="name">attendance.analytics.calendar</field>
|
||||||
|
<field name="model">attendance.analytics</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<calendar string="Attendance Calendar"
|
||||||
|
date_start="date"
|
||||||
|
date_stop="date_end"
|
||||||
|
color="color"
|
||||||
|
mode="month"
|
||||||
|
quick_create="false"
|
||||||
|
event_open_popup="true">
|
||||||
|
<field name="display_label"/>
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="status_message"/>
|
||||||
|
</calendar>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- =============================================== -->
|
||||||
|
<!-- SEARCH VIEW -->
|
||||||
|
<!-- =============================================== -->
|
||||||
|
|
||||||
|
<record id="view_attendance_analytics_search" model="ir.ui.view">
|
||||||
|
<field name="name">attendance.analytics.search</field>
|
||||||
|
<field name="model">attendance.analytics</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search string="Attendance Analytics">
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="department_id"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<separator/>
|
||||||
|
<filter string="Late"
|
||||||
|
name="late"
|
||||||
|
domain="[('is_late','=',True)]"/>
|
||||||
|
<filter string="Early Out"
|
||||||
|
name="early_out"
|
||||||
|
domain="[('is_early_out','=',True)]"/>
|
||||||
|
<filter string="Compensation Pending"
|
||||||
|
name="compensation_pending"
|
||||||
|
domain="[('is_compensation_pending','=',True)]"/>
|
||||||
|
<filter string="Holiday"
|
||||||
|
name="holiday"
|
||||||
|
domain="[('is_holiday','=',True)]"/>
|
||||||
|
<filter string="Week Off"
|
||||||
|
name="week_off"
|
||||||
|
domain="[('is_week_off','=',True)]"/>
|
||||||
|
<group expand="0"
|
||||||
|
string="Group By">
|
||||||
|
<filter string="Employee"
|
||||||
|
name="group_employee"
|
||||||
|
context="{'group_by':'employee_id'}"/>
|
||||||
|
<filter string="Department"
|
||||||
|
name="group_department"
|
||||||
|
context="{'group_by':'department_id'}"/>
|
||||||
|
<filter string="Date"
|
||||||
|
name="group_date"
|
||||||
|
context="{'group_by':'date'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="action_attendance_analytics" model="ir.actions.act_window">
|
||||||
|
<field name="name">Attendance Analytics</field>
|
||||||
|
<field name="res_model">attendance.analytics</field>
|
||||||
|
<field name="view_mode">list,calendar</field>
|
||||||
|
<field name="domain"> [ '|', ('employee_id.user_id', '=', uid), ('employee_id.parent_id.user_id', '=', uid) ] </field>
|
||||||
|
<field name="search_view_id" ref="view_attendance_analytics_search"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="menu_attendance_analytics"
|
||||||
|
name="Attendance Report"
|
||||||
|
parent="hr_attendance.menu_hr_attendance_root"
|
||||||
|
action="action_attendance_analytics"
|
||||||
|
sequence="50"/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_employee_form_inherit_attendance_analytics"
|
||||||
|
model="ir.ui.view">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
hr.employee.form.attendance.analytics
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model">hr.employee</field>
|
||||||
|
|
||||||
|
<field name="inherit_id"
|
||||||
|
ref="hr.view_employee_form"/>
|
||||||
|
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<xpath expr="//div[@name='button_box']"
|
||||||
|
position="inside">
|
||||||
|
|
||||||
|
<button name="action_open_attendance_analytics"
|
||||||
|
type="object"
|
||||||
|
class="oe_stat_button"
|
||||||
|
icon="fa-calendar">
|
||||||
|
|
||||||
|
<field name="attendance_analytics_count"
|
||||||
|
string="Attendance"
|
||||||
|
widget="statinfo"/>
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,447 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="email_template_late_coming_request"
|
||||||
|
model="mail.template">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request Submitted
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_late_coming_request"/>
|
||||||
|
|
||||||
|
<field name="subject">
|
||||||
|
Late Coming Request - {{ object.employee_id.name }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_from">
|
||||||
|
{{ user.email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_to">
|
||||||
|
{{ object.manager_id.work_email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
|
||||||
|
<div style="font-family: Arial, sans-serif;">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello
|
||||||
|
<strong t-out="object.manager_id.name"/>,
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Employee
|
||||||
|
<strong t-out="object.employee_id.name"/>
|
||||||
|
has submitted a Late Coming / Compensation Request.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table border="1"
|
||||||
|
cellpadding="6"
|
||||||
|
cellspacing="0"
|
||||||
|
style="border-collapse: collapse;">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Employee</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.employee_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Department</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.department_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Date</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.attendance_date"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Check In</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.check_in"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Late Minutes</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.late_minutes"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.department_grace_period">
|
||||||
|
<td>
|
||||||
|
<strong>Department Grace</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.department_grace_period"/>
|
||||||
|
Minutes
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.compensation_pending">
|
||||||
|
<td>
|
||||||
|
<strong>Compensation Required</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Yes
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.compensation_minutes">
|
||||||
|
<td>
|
||||||
|
<strong>Pending Minutes</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.compensation_minutes"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.required_checkout_time">
|
||||||
|
<td>
|
||||||
|
<strong>Required Checkout Time</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.required_checkout_time"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.status_message">
|
||||||
|
<td>
|
||||||
|
<strong>Status</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.status_message"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>Reason:</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p t-if="object.reason">
|
||||||
|
<span t-out="object.reason"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p t-if="not object.reason">
|
||||||
|
No reason provided.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please review and take appropriate action.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank You
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
<record id="email_template_late_coming_rejected"
|
||||||
|
model="mail.template">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Late Coming Request Rejected
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_late_coming_request"/>
|
||||||
|
|
||||||
|
<field name="subject">
|
||||||
|
Your Late Coming Request was Rejected
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_from">
|
||||||
|
{{ user.email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_to">
|
||||||
|
{{ object.employee_id.work_email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
|
||||||
|
<div style="font-family: Arial, sans-serif;">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello
|
||||||
|
<strong t-out="object.employee_id.name"/>,
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your Late Coming / Compensation Request has been
|
||||||
|
<strong style="color: red;">
|
||||||
|
Rejected
|
||||||
|
</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table border="1"
|
||||||
|
cellpadding="6"
|
||||||
|
cellspacing="0"
|
||||||
|
style="border-collapse: collapse;">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Employee</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.employee_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Department</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.department_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Attendance Date</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.attendance_date"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Manager</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.manager_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Late Minutes</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.late_minutes"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.department_grace_period">
|
||||||
|
<td>
|
||||||
|
<strong>Department Grace</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.department_grace_period"/>
|
||||||
|
Minutes
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.compensation_pending">
|
||||||
|
<td>
|
||||||
|
<strong>Compensation Required</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Yes
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.compensation_minutes">
|
||||||
|
<td>
|
||||||
|
<strong>Pending Minutes</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.compensation_minutes"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.required_checkout_time">
|
||||||
|
<td>
|
||||||
|
<strong>Required Checkout Time</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.required_checkout_time"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="object.status_message">
|
||||||
|
<td>
|
||||||
|
<strong>Status</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.status_message"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>Reason Submitted:</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p t-if="object.reason">
|
||||||
|
<span t-out="object.reason"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p t-if="not object.reason">
|
||||||
|
No reason provided.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please contact your manager or HR for further clarification.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank You
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="email_template_absent_alert"
|
||||||
|
model="mail.template">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Attendance Missing Alert
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_attendance_analytics"/>
|
||||||
|
|
||||||
|
<field name="subject">
|
||||||
|
Attendance Punch Missing
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_from">
|
||||||
|
{{ user.email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_to">
|
||||||
|
{{ object.employee_id.work_email }}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
|
||||||
|
<div style="font-family: Arial, sans-serif;">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello
|
||||||
|
<strong t-out="object.employee_id.name"/>,
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your attendance punch has not been recorded.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table border="1"
|
||||||
|
cellpadding="6"
|
||||||
|
cellspacing="0"
|
||||||
|
style="border-collapse: collapse;">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Employee</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.employee_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Department</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.department_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Date</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-out="object.date"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Status</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Absent / No Attendance Recorded
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please login your attendance immediately
|
||||||
|
or contact HR/Admin if already marked.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank You
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="ir_cron_send_absent_alert" model="ir.cron">
|
||||||
|
<field name="name">Send Absent Attendance Alert</field>
|
||||||
|
<field name="model_id" ref="model_attendance_analytics"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model.action_send_absent_mail()</field>
|
||||||
|
<field name="interval_number">1</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="active">True</field>
|
||||||
|
<field name="nextcall"
|
||||||
|
eval="DateTime.now().replace(hour=10, minute=0, second=0)"/>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<odoo>
|
||||||
|
<!-- ============================================= -->
|
||||||
|
<!-- LIST VIEW -->
|
||||||
|
<!-- ============================================= -->
|
||||||
|
<record id="view_late_coming_request_list" model="ir.ui.view">
|
||||||
|
<field name="name">late.coming.request.list</field>
|
||||||
|
<field name="model">late.coming.request</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list>
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="department_id"/>
|
||||||
|
<field name="attendance_date"/>
|
||||||
|
<field name="late_minutes"/>
|
||||||
|
<field name="department_grace_period"/>
|
||||||
|
<field name="compensation_pending"/>
|
||||||
|
<field name="compensation_minutes"/>
|
||||||
|
<field name="state"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<!-- ============================================= -->
|
||||||
|
<!-- FORM VIEW -->
|
||||||
|
<!-- ============================================= -->
|
||||||
|
<record id="view_late_coming_request_form" model="ir.ui.view">
|
||||||
|
<field name="name">late.coming.request.form</field>
|
||||||
|
<field name="model">late.coming.request</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<form string="Permission Request">
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<button name="action_reset_to_draft"
|
||||||
|
string="Reset To Draft"
|
||||||
|
type="object"
|
||||||
|
invisible="state == 'draft' or state == 'approved'"
|
||||||
|
class="btn-secondary"/>
|
||||||
|
|
||||||
|
<button name="action_submit"
|
||||||
|
string="Submit"
|
||||||
|
type="object"
|
||||||
|
invisible="state != 'draft'"
|
||||||
|
class="btn-primary"/>
|
||||||
|
|
||||||
|
<button name="action_approve"
|
||||||
|
string="Approve"
|
||||||
|
type="object"
|
||||||
|
invisible="state != 'submitted'"
|
||||||
|
class="btn-success"/>
|
||||||
|
|
||||||
|
<button name="action_reject"
|
||||||
|
string="Reject"
|
||||||
|
type="object"
|
||||||
|
invisible="state != 'submitted'"
|
||||||
|
class="btn-danger"/>
|
||||||
|
|
||||||
|
<field name="state"
|
||||||
|
widget="statusbar"/>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<sheet>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="employee_id"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="manager_id"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="attendance_date"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="worked_hours"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="late_minutes"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="compensation_minutes"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="department_grace_period"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="required_checkout_time"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="status_message"
|
||||||
|
readonly="1"/>
|
||||||
|
|
||||||
|
<field name="reason"
|
||||||
|
placeholder="Enter reason here..."
|
||||||
|
readonly="state in ('approved','rejected')"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="action_late_coming_request" model="ir.actions.act_window">
|
||||||
|
<field name="name">Permission Requests</field>
|
||||||
|
<field name="res_model">late.coming.request</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="domain">
|
||||||
|
[
|
||||||
|
'|',
|
||||||
|
('employee_id.user_id', '=', uid),
|
||||||
|
('employee_id.parent_id.user_id', '=', uid)
|
||||||
|
]
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<menuitem id="menu_late_coming_request"
|
||||||
|
name="Permission Requests"
|
||||||
|
parent="hr_attendance.menu_hr_attendance_root"
|
||||||
|
action="action_late_coming_request"
|
||||||
|
sequence="30"/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_resource_calendar_form_inherit_grace_period"
|
||||||
|
model="ir.ui.view">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
resource.calendar.form.inherit.grace.period
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model">resource.calendar</field>
|
||||||
|
|
||||||
|
<field name="inherit_id"
|
||||||
|
ref="resource.resource_calendar_form"/>
|
||||||
|
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<xpath expr="//sheet/notebook"
|
||||||
|
position="before">
|
||||||
|
|
||||||
|
<group string="Attendance Configuration">
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="weekday_ids"
|
||||||
|
widget="many2many_tags"/>
|
||||||
|
|
||||||
|
<field name="weekend_ids"
|
||||||
|
widget="many2many_tags"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="shift_start_time"
|
||||||
|
widget="float_time"/>
|
||||||
|
|
||||||
|
<field name="shift_end_time"
|
||||||
|
widget="float_time"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
|
||||||
|
<field name="late_grace_period"/>
|
||||||
|
|
||||||
|
<field name="early_out_grace_period"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group>
|
||||||
|
<button name="action_generate_schedule"
|
||||||
|
type="object"
|
||||||
|
string="Generate Schedule"
|
||||||
|
class="oe_highlight oe_inline"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//sheet/notebook"
|
||||||
|
position="inside">
|
||||||
|
|
||||||
|
<page string="Department Grace Period">
|
||||||
|
|
||||||
|
<field name="department_grace_ids">
|
||||||
|
|
||||||
|
<list editable="bottom">
|
||||||
|
|
||||||
|
<field name="department_id"/>
|
||||||
|
<field name="grace_period"/>
|
||||||
|
|
||||||
|
</list>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
'data': [
|
'data': [
|
||||||
'data/project_task_data.xml',
|
'data/project_task_data.xml',
|
||||||
'views/hr_leave_views.xml',
|
'views/hr_leave_views.xml',
|
||||||
|
'views/hr_leave_type.xml',
|
||||||
|
'views/hr_leave_allocation.xml',
|
||||||
|
'views/hr_leave_allocation_mail_template.xml',
|
||||||
],
|
],
|
||||||
|
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<field name="user_id" ref="base.user_admin"/>
|
<field name="user_id" ref="base.user_admin"/>
|
||||||
|
|
||||||
<field name="allow_timesheets">True</field>
|
<field name="allow_timesheets">True</field>
|
||||||
|
<field name="privacy_visibility">employees</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Default Leave Task -->
|
<!-- Default Leave Task -->
|
||||||
|
|
@ -23,4 +24,5 @@
|
||||||
eval="[(4, ref('base.user_admin'))]"/>
|
eval="[(4, ref('base.user_admin'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
from . import hr_leave
|
from . import hr_leave
|
||||||
|
from . import hr_leave_allocation
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
from odoo import models, fields, api
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
class HrLeave(models.Model):
|
class HrLeave(models.Model):
|
||||||
_inherit = 'hr.leave'
|
_inherit = 'hr.leave'
|
||||||
|
|
||||||
project_id = fields.Many2one(
|
project_id = fields.Many2one(
|
||||||
'project.project',
|
'project.project',related="holiday_status_id.project_id",
|
||||||
string='Project'
|
string='Project'
|
||||||
)
|
)
|
||||||
|
|
||||||
task_id = fields.Many2one(
|
task_id = fields.Many2one(
|
||||||
'project.task',
|
'project.task',related="holiday_status_id.task_id",
|
||||||
string='Task'
|
string='Task'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -19,12 +19,12 @@ class HrLeave(models.Model):
|
||||||
string='Timesheet Entry',
|
string='Timesheet Entry',
|
||||||
readonly=True,
|
readonly=True,
|
||||||
copy=False
|
copy=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# CREATE TIMESHEET ON APPROVAL
|
# CREATE TIMESHEET ON APPROVAL
|
||||||
|
|
||||||
def action_validate(self, check_state=True):
|
def action_draft(self):
|
||||||
res = super().action_validate(check_state=check_state)
|
res = super().action_draft()
|
||||||
|
|
||||||
default_project = self.env.ref(
|
default_project = self.env.ref(
|
||||||
'leaves_timesheets_extended.project_internal_leave'
|
'leaves_timesheets_extended.project_internal_leave'
|
||||||
|
|
@ -40,8 +40,15 @@ class HrLeave(models.Model):
|
||||||
if leave.timesheet_line_id:
|
if leave.timesheet_line_id:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
project = leave.project_id or default_project
|
project = (
|
||||||
task = leave.task_id or default_task
|
leave.project_id
|
||||||
|
or default_project
|
||||||
|
)
|
||||||
|
|
||||||
|
task = (
|
||||||
|
leave.task_id
|
||||||
|
or default_task
|
||||||
|
)
|
||||||
|
|
||||||
# Hours Calculation
|
# Hours Calculation
|
||||||
if leave.request_unit_half:
|
if leave.request_unit_half:
|
||||||
|
|
@ -49,9 +56,7 @@ class HrLeave(models.Model):
|
||||||
else:
|
else:
|
||||||
hours = leave.number_of_days * 8
|
hours = leave.number_of_days * 8
|
||||||
|
|
||||||
analytic_line = self.env[
|
analytic_line = self.env['account.analytic.line'].create({
|
||||||
'account.analytic.line'
|
|
||||||
].create({
|
|
||||||
'name': f"Leave: {leave.holiday_status_id.name}",
|
'name': f"Leave: {leave.holiday_status_id.name}",
|
||||||
'employee_id': leave.employee_id.id,
|
'employee_id': leave.employee_id.id,
|
||||||
'user_id': leave.employee_id.user_id.id,
|
'user_id': leave.employee_id.user_id.id,
|
||||||
|
|
@ -65,7 +70,6 @@ class HrLeave(models.Model):
|
||||||
leave.timesheet_line_id = analytic_line.id
|
leave.timesheet_line_id = analytic_line.id
|
||||||
|
|
||||||
return res
|
return res
|
||||||
# DELETE TIMESHEET ON REFUSE
|
|
||||||
|
|
||||||
def action_refuse(self):
|
def action_refuse(self):
|
||||||
res = super().action_refuse()
|
res = super().action_refuse()
|
||||||
|
|
@ -78,3 +82,42 @@ class HrLeave(models.Model):
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
#ACTION CANCEL
|
||||||
|
def action_cancel(self):
|
||||||
|
res = super().action_cancel()
|
||||||
|
|
||||||
|
for leave in self:
|
||||||
|
|
||||||
|
if leave.timesheet_line_id:
|
||||||
|
leave.timesheet_line_id.unlink()
|
||||||
|
leave.timesheet_line_id = False
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _check_validity(self):
|
||||||
|
|
||||||
|
res = super(HrLeave, self)._check_validity()
|
||||||
|
|
||||||
|
for leave in self:
|
||||||
|
|
||||||
|
# Public holiday / weekoff validation
|
||||||
|
if leave.number_of_days <= 0:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"The selected day is either a Public Holiday or Week Off."
|
||||||
|
))
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class HRLeaveType(models.Model):
|
||||||
|
_inherit='hr.leave.type'
|
||||||
|
|
||||||
|
project_id = fields.Many2one(
|
||||||
|
'project.project',
|
||||||
|
string='Project'
|
||||||
|
)
|
||||||
|
|
||||||
|
task_id = fields.Many2one(
|
||||||
|
'project.task',
|
||||||
|
string='Task'
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
from odoo import api, fields, models, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
|
class HrLeaveAllocation(models.Model):
|
||||||
|
_inherit = 'hr.leave.allocation'
|
||||||
|
|
||||||
|
state = fields.Selection(selection_add=[
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('submitted', 'Submitted'),
|
||||||
|
('refuse', 'Rejected'),
|
||||||
|
])
|
||||||
|
|
||||||
|
def action_submit(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if rec.state != 'draft':
|
||||||
|
raise UserError(
|
||||||
|
_("Only Draft allocations can be submitted.")
|
||||||
|
)
|
||||||
|
|
||||||
|
manager_email = rec.employee_id.parent_id.work_email
|
||||||
|
|
||||||
|
if not manager_email:
|
||||||
|
raise UserError(
|
||||||
|
_("Manager work email not configured.")
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.state = 'submitted'
|
||||||
|
|
||||||
|
# SEND MAIL TO MANAGER
|
||||||
|
template = self.env.ref(
|
||||||
|
'leaves_timesheets_extended.email_template_leave_allocation_submit'
|
||||||
|
)
|
||||||
|
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.message_post(
|
||||||
|
body=_("Leave Allocation Submitted.")
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_approve(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if rec.state != 'submitted':
|
||||||
|
raise UserError(
|
||||||
|
_("Only Submitted allocations can be approved.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert back to Odoo valid approval state
|
||||||
|
rec.state = 'confirm'
|
||||||
|
|
||||||
|
# Odoo internal approval
|
||||||
|
rec.action_validate()
|
||||||
|
|
||||||
|
template = self.env.ref(
|
||||||
|
'leaves_timesheets_extended.email_template_leave_allocation_approved'
|
||||||
|
)
|
||||||
|
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.message_post(
|
||||||
|
body=_("Leave Allocation Approved.")
|
||||||
|
)
|
||||||
|
def action_reject(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
|
||||||
|
if rec.state != 'submitted':
|
||||||
|
raise UserError(
|
||||||
|
_("Only Submitted allocations can be rejected.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not rec.employee_id.work_email:
|
||||||
|
raise UserError(
|
||||||
|
_("Employee work email not configured.")
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.state = 'refuse'
|
||||||
|
|
||||||
|
# SEND MAIL TO EMPLOYEE
|
||||||
|
template = self.env.ref(
|
||||||
|
'leaves_timesheets_extended.email_template_leave_allocation_rejected'
|
||||||
|
)
|
||||||
|
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
|
||||||
|
rec.message_post(
|
||||||
|
body=_("Leave Allocation Rejected.")
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_reset_to_draft(self):
|
||||||
|
|
||||||
|
for rec in self:
|
||||||
|
rec.state = 'draft'
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_hr_leave_allocation_form_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">hr.leave.allocation.form.inherit</field>
|
||||||
|
<field name="model">hr.leave.allocation</field>
|
||||||
|
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<!-- SUBMIT BUTTON -->
|
||||||
|
<xpath expr="//header" position="inside">
|
||||||
|
<button name="action_submit"
|
||||||
|
string="Submit"
|
||||||
|
type="object"
|
||||||
|
class="btn-primary"
|
||||||
|
invisible="state != 'draft'"/>
|
||||||
|
<button name="action_approve"
|
||||||
|
string="Approve"
|
||||||
|
type="object"
|
||||||
|
class="btn-success"
|
||||||
|
invisible="state != 'submitted'"/>
|
||||||
|
<button name="action_reject"
|
||||||
|
string="Reject"
|
||||||
|
type="object"
|
||||||
|
class="btn-danger"
|
||||||
|
invisible="state != 'submitted'"/>
|
||||||
|
<button name="action_reset_to_draft"
|
||||||
|
string="Reset To Draft"
|
||||||
|
type="object"
|
||||||
|
invisible="state == 'draft'"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
<odoo>
|
||||||
|
<record id="email_template_leave_allocation_submit" model="mail.template">
|
||||||
|
<field name="name">Leave Allocation Submitted</field>
|
||||||
|
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||||
|
<field name="subject">Leave Allocation Submitted - {{ object.employee_id.name }}</field>
|
||||||
|
<field name="email_from">{{ user.email }}</field>
|
||||||
|
<field name="email_to">{{ object.employee_id.parent_id.work_email }}</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<p>Hello,</p>
|
||||||
|
<p>
|
||||||
|
Employee
|
||||||
|
<strong t-out="object.employee_id.name"/>
|
||||||
|
submitted a Leave Allocation request.
|
||||||
|
</p>
|
||||||
|
<table border="1" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Time Off Type</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-out="object.holiday_status_id.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong>Days</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-out="'%s Days' % object.number_of_days"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<br/>
|
||||||
|
<p>
|
||||||
|
Please review the request.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="email_template_leave_allocation_approved" model="mail.template">
|
||||||
|
<field name="name">Leave Allocation Approved</field>
|
||||||
|
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||||
|
<field name="subject">Leave Allocation Approved</field>
|
||||||
|
<field name="email_from">{{ user.email }}</field>
|
||||||
|
<field name="email_to">{{ object.employee_id.work_email }}</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<p>Hello
|
||||||
|
<strong t-out="object.employee_id.name"/>,
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Your Leave Allocation request has been
|
||||||
|
<strong style="color:green;">
|
||||||
|
Approved
|
||||||
|
</strong>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Leave Days:
|
||||||
|
<strong>
|
||||||
|
<t t-out="'%s Days' % object.number_of_days"/>
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
<br/>
|
||||||
|
<p>Thank You</p>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="email_template_leave_allocation_rejected" model="mail.template">
|
||||||
|
<field name="name">Leave Allocation Rejected</field>
|
||||||
|
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||||
|
<field name="subject">Leave Allocation Rejected</field>
|
||||||
|
<field name="email_from">{{ user.email }}</field>
|
||||||
|
<field name="email_to">{{ object.employee_id.work_email }}</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
<p>Hello
|
||||||
|
<strong t-out="object.employee_id.name"/>,
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Your Leave Allocation request has been
|
||||||
|
<strong style="color:red;">
|
||||||
|
Rejected
|
||||||
|
</strong>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please contact HR or your manager.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_hr_leave_type_form_inherit_project_task"
|
||||||
|
model="ir.ui.view">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
hr.leave.type.form.project.task
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model">hr.leave.type</field>
|
||||||
|
|
||||||
|
<field name="inherit_id"
|
||||||
|
ref="hr_holidays.edit_holiday_status_form"/>
|
||||||
|
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<xpath expr="//sheet/group"
|
||||||
|
position="inside">
|
||||||
|
|
||||||
|
<group string="Project Details">
|
||||||
|
|
||||||
|
<field name="project_id"/>
|
||||||
|
|
||||||
|
<field name="task_id"
|
||||||
|
domain="[('project_id', '=', project_id)]"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -17,11 +17,10 @@
|
||||||
|
|
||||||
<xpath expr="//group" position="inside">
|
<xpath expr="//group" position="inside">
|
||||||
|
|
||||||
<field name="project_id"/>
|
<field name="project_id" invisible="1"/>
|
||||||
|
|
||||||
<field name="task_id"
|
<field name="task_id"
|
||||||
domain="[('project_id', '=', project_id)]"/>
|
domain="[('project_id', '=', project_id)]" invisible="1"/>
|
||||||
|
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
'views/hr_timesheet_inherit.xml',
|
'views/hr_timesheet_inherit.xml',
|
||||||
'views/weekly_period_timesheets.xml',
|
'views/weekly_period_timesheets.xml',
|
||||||
'views/week_timesheet.xml',
|
'views/week_timesheet.xml',
|
||||||
|
'views/mail_template.xml',
|
||||||
],
|
],
|
||||||
|
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,15 @@ class WeeklyPeriodTimesheets(models.Model):
|
||||||
line.write(vals)
|
line.write(vals)
|
||||||
|
|
||||||
rec.state = 'submitted'
|
rec.state = 'submitted'
|
||||||
|
template = self.env.ref(
|
||||||
|
'weekly_timesheets.email_template_weekly_timesheet_submit'
|
||||||
|
)
|
||||||
|
|
||||||
|
if template:
|
||||||
|
template.send_mail(
|
||||||
|
rec.id,
|
||||||
|
force_send=True
|
||||||
|
)
|
||||||
|
|
||||||
def action_approve(self):
|
def action_approve(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="email_template_weekly_timesheet_submit"
|
||||||
|
model="mail.template">
|
||||||
|
|
||||||
|
<field name="name">
|
||||||
|
Weekly Timesheet Submitted
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="model_id"
|
||||||
|
ref="model_weekly_periodtimesheets"/>
|
||||||
|
|
||||||
|
<field name="subject">
|
||||||
|
Weekly Timesheet Submitted - ${object.employee_id.name}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_from">
|
||||||
|
${user.email | safe}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="email_to">
|
||||||
|
${object.employee_id.parent_id.work_email}
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>Hello,</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Employee
|
||||||
|
<strong>${object.employee_id.name}</strong>
|
||||||
|
has submitted the weekly timesheet.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Week:
|
||||||
|
${object.week_line_id.name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Total Hours:
|
||||||
|
${object.total_hours}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please review and approve.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<p>Thank You</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Loading…
Reference in New Issue