Browse Source

[ADD] Initial Commit

pull/72/head
Sreejith P 7 years ago
parent
commit
dfa5df6eba
  1. 24
      hr_vacation_mngmt/__init__.py
  2. 49
      hr_vacation_mngmt/__manifest__.py
  3. 31
      hr_vacation_mngmt/data/hr_payslip_data.xml
  4. 31
      hr_vacation_mngmt/data/hr_vacation_data.xml
  5. 6
      hr_vacation_mngmt/doc/RELEASE_NOTES.md
  6. 6
      hr_vacation_mngmt/doc/RELEASE_NOTES.md~
  7. 5
      hr_vacation_mngmt/models/__init__.py
  8. 120
      hr_vacation_mngmt/models/hr_employee_ticket.py
  9. 183
      hr_vacation_mngmt/models/hr_payslip.py
  10. 171
      hr_vacation_mngmt/models/hr_vacation.py
  11. 11
      hr_vacation_mngmt/security/hr_vacation_security.xml
  12. 8
      hr_vacation_mngmt/security/ir.model.access.csv
  13. BIN
      hr_vacation_mngmt/static/description/HRMS-BUTTON.png
  14. BIN
      hr_vacation_mngmt/static/description/banner.jpg
  15. BIN
      hr_vacation_mngmt/static/description/cybro-service.png
  16. BIN
      hr_vacation_mngmt/static/description/cybro_logo.png
  17. BIN
      hr_vacation_mngmt/static/description/icon.png
  18. 216
      hr_vacation_mngmt/static/description/index.html
  19. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_01.png
  20. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_02.png
  21. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_03.png
  22. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_04.png
  23. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_05.png
  24. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_06.png
  25. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_07.png
  26. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_08.png
  27. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_09.png
  28. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_10.png
  29. BIN
      hr_vacation_mngmt/static/description/ohrms_vacation_11.png
  30. 121
      hr_vacation_mngmt/views/hr_employee_ticket.xml
  31. 39
      hr_vacation_mngmt/views/hr_payslip.xml
  32. 20
      hr_vacation_mngmt/views/hr_reminder.xml
  33. 114
      hr_vacation_mngmt/views/hr_vacation.xml
  34. 3
      hr_vacation_mngmt/wizard/__init__.py
  35. 59
      hr_vacation_mngmt/wizard/reassign_task.py
  36. 31
      hr_vacation_mngmt/wizard/reassign_task.xml

24
hr_vacation_mngmt/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
###################################################################################
# A part of OpenHrms Project <https://www.openhrms.co.uk>
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies (<https://www.cybrosys.com>).
# Author: Aswani PC (<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# 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 for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
###################################################################################
from . import models
from . import wizard

49
hr_vacation_mngmt/__manifest__.py

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
###################################################################################
# A part of Open Hrms Project <https://www.openhrms.co.uk>
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies (<https://www.cybrosys.com>).
# Author: Aswani PC (<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# 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 for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
###################################################################################
{
'name': "Open HRMS Vacation Management",
'version': '11.0.1.0.0',
'summary': """Manage Employee Vacation""",
'description': """HR Vacation management""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'website': 'https://www.openhrms.com',
'category': 'Generic Modules/Human Resources',
'depends': ['hr_leave_request_aliasing','project', 'hr_payroll', 'account'],
'data': [
'security/hr_vacation_security.xml',
'security/ir.model.access.csv',
'data/hr_payslip_data.xml',
'views/hr_reminder.xml',
'data/hr_vacation_data.xml',
'wizard/reassign_task.xml',
'views/hr_employee_ticket.xml',
'views/hr_vacation.xml',
'views/hr_payslip.xml',
],
'images': ['static/description/banner.jpg'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

31
hr_vacation_mngmt/data/hr_payslip_data.xml

@ -0,0 +1,31 @@
<odoo>
<data>
<record id="hr_leave_salary_register" model="hr.contribution.register">
<field name="name">Leave Salary</field>
<field name="partner_id" eval="False"/>
</record>
<!-- Salary Rules -->
<record id="hr_salary_rule_leave_salary_basic" model="hr.salary.rule">
<field name="name">Leave Salary</field>
<field name="code">LS</field>
<field name="sequence" eval="90"/>
<field name="category_id" ref="hr_payroll.ALW"/>
<field name="register_id" ref="hr_leave_salary_register"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = categories.BASIC</field>
</record>
<record id="hr_salary_rule_leave_salary_gross" model="hr.salary.rule">
<field name="name">Leave Salary</field>
<field name="code">LS</field>
<field name="sequence" eval="90"/>
<field name="category_id" ref="hr_payroll.ALW"/>
<field name="register_id" ref="hr_leave_salary_register"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = categories.BASIC + categories.ALW</field>
</record>
</data>
</odoo>

31
hr_vacation_mngmt/data/hr_vacation_data.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="ir_cron_ticket_status_update" model="ir.cron">
<field name="name">Flight ticket status update</field>
<field name="model_id" ref="model_hr_flight_ticket"/>
<field name="state">code</field>
<field name="code">model.run_update_ticket_status()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
<record id="hr_email_leave_reminder" model="ir.cron">
<field name="name">HR Leave Reminder</field>
<field name="model_id" ref="hr_holidays.model_hr_holidays"/>
<field name="state">code</field>
<field name="code">model.send_leave_reminder()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
<record id="air_lines_partner" model="res.partner">
<field name="name">Airlines</field>
<field name="supplier">True</field>
</record>
</data>
</odoo>

6
hr_vacation_mngmt/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <ohrms_core>
#### 25.04.2018
#### Version 11.0.1.0.0
##### ADD
- Initial commit for OpenHrms Project

6
hr_vacation_mngmt/doc/RELEASE_NOTES.md~

@ -0,0 +1,6 @@
## Module <ohrms_core>
#### 30.03.2018
#### Version 10.0.1.0.0
##### ADD
- Initial commit for OpenHrms Project

5
hr_vacation_mngmt/models/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import hr_vacation
from . import hr_payslip
from . import hr_employee_ticket

120
hr_vacation_mngmt/models/hr_employee_ticket.py

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
class HrFlightTicket(models.Model):
_name = 'hr.flight.ticket'
name = fields.Char()
employee_id = fields.Many2one('hr.employee', string='Employee', required=True)
ticket_type = fields.Selection([('one', 'One Way'), ('round', 'Round Trip')], string='Ticket Type', default='round')
depart_from = fields.Char(string='Departure', required=True)
destination = fields.Char(string='Destination', required=True)
date_start = fields.Date(string='Start Date', required=True)
date_return = fields.Date(string='Return Date')
ticket_class = fields.Selection([('economy', 'Economy'),
('premium_economy', 'Premium Economy'),
('business', 'Business'),
('first_class', 'First Class')], string='Class')
ticket_fare = fields.Float(string='Ticket Fare')
flight_details = fields.Text(string='Flight Details')
return_flight_details = fields.Text(string='Return Flight Details')
state = fields.Selection([('booked', 'Booked'), ('confirmed', 'Confirmed'), ('started', 'Started'),
('completed', 'Completed'), ('canceled', 'Canceled')], string='Status', default='booked')
invoice_id = fields.Many2one('account.invoice', string='Invoice')
leave_id = fields.Many2one('hr.holidays', string='Leave')
company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.user.company_id)
@api.multi
def name_get(self):
res = []
for ticket in self:
res.append((ticket.id, _("Flight ticket for %s on %s to %s") % (
ticket.employee_id.name, ticket.date_start, ticket.destination)))
return res
@api.constrains('date_start', 'date_return')
def check_valid_date(self):
if self.filtered(lambda c: c.date_return and c.date_start > c.date_return):
raise ValidationError(_('Flight travelling start date must be less than flight return date.'))
def book_ticket(self):
return {'type': 'ir.actions.act_window_close'}
def confirm_ticket(self):
if self.ticket_fare <= 0:
raise UserError(_('Please add ticket fare.'))
inv_obj = self.env['account.invoice'].sudo()
expense_account = self.env['ir.config_parameter'].sudo().get_param('travel_expense_account')
if not expense_account:
raise UserError(_('Please select expense account for the flight tickets.'))
domain = [
('type', '=', 'purchase'),
('company_id', '=', self.company_id.id),
]
journal_id = self.env['account.journal'].search(domain, limit=1)
partner = self.env.ref('hr_vacation_mngmt.air_lines_partner')
if not partner.property_payment_term_id:
date_due = fields.Date.context_today(self)
else:
pterm = partner.property_payment_term_id
pterm_list = \
pterm.with_context(currency_id=self.env.user.company_id.id).compute(
value=1, date_ref=fields.Date.context_today(self))[0]
date_due = max(line[0] for line in pterm_list)
inv_data = {
'name': '',
'origin': 'Flight Ticket',
'type': 'in_invoice',
'journal_id': journal_id.id,
'payment_term_id': partner.property_payment_term_id.id,
'date_due': date_due,
'reference': False,
'partner_id': partner.id,
'account_id': partner.property_account_payable_id.id,
'invoice_line_ids': [(0, 0, {
'name': 'Flight Ticket',
'price_unit': self.ticket_fare,
'quantity': 1.0,
'account_id': expense_account,
})],
}
inv_id = inv_obj.create(inv_data)
inv_id.action_invoice_open()
self.write({'state': 'confirmed', 'invoice_id': inv_id.id})
def cancel_ticket(self):
if self.state == 'booked':
self.write({'state': 'canceled'})
elif self.state == 'confirmed':
if self.invoice_id and self.invoice_id.state == 'paid':
self.write({'state': 'canceled'})
if self.invoice_id and self.invoice_id.state == 'open':
self.invoice_id.action_invoice_cancel()
self.write({'state': 'canceled'})
@api.model
def run_update_ticket_status(self):
run_out_tickets = self.search([('state', 'in', ['confirmed', 'started']),
('date_return', '<=', datetime.now())])
confirmed_tickets = self.search([('state', '=', 'confirmed'), ('date_start', '<=', datetime.now()),
('date_return', '>', datetime.now())])
for ticket in run_out_tickets:
ticket.write({'state': 'completed'})
for ticket in confirmed_tickets:
ticket.write({'state': 'started'})
@api.multi
def action_view_invoice(self):
return {
'name': _('Flight Ticket Invoice'),
'view_mode': 'form',
'view_id': self.env.ref('account.invoice_supplier_form').id,
'res_model': 'account.invoice',
'context': "{'type':'in_invoice'}",
'type': 'ir.actions.act_window',
'res_id': self.invoice_id.id,
}

183
hr_vacation_mngmt/models/hr_payslip.py

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class HrPayslip(models.Model):
_inherit = 'hr.payslip'
leave_salary = fields.Boolean(string='Leave Salary')
@api.model
def _get_payslip_lines(self, contract_ids, payslip_id):
def _sum_salary_rule_category(localdict, category, amount):
if category.parent_id:
localdict = _sum_salary_rule_category(localdict, category.parent_id, amount)
localdict['categories'].dict[category.code] = category.code in localdict['categories'].dict and localdict['categories'].dict[category.code] + amount or amount
return localdict
class BrowsableObject(object):
def __init__(self, employee_id, dict, env):
self.employee_id = employee_id
self.dict = dict
self.env = env
def __getattr__(self, attr):
return attr in self.dict and self.dict.__getitem__(attr) or 0.0
class InputLine(BrowsableObject):
"""a class that will be used into the python code, mainly for usability purposes"""
def sum(self, code, from_date, to_date=None):
if to_date is None:
to_date = fields.Date.today()
self.env.cr.execute("""
SELECT sum(amount) as sum
FROM hr_payslip as hp, hr_payslip_input as pi
WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""",
(self.employee_id, from_date, to_date, code))
return self.env.cr.fetchone()[0] or 0.0
class WorkedDays(BrowsableObject):
"""a class that will be used into the python code, mainly for usability purposes"""
def _sum(self, code, from_date, to_date=None):
if to_date is None:
to_date = fields.Date.today()
self.env.cr.execute("""
SELECT sum(number_of_days) as number_of_days, sum(number_of_hours) as number_of_hours
FROM hr_payslip as hp, hr_payslip_worked_days as pi
WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""",
(self.employee_id, from_date, to_date, code))
return self.env.cr.fetchone()
def sum(self, code, from_date, to_date=None):
res = self._sum(code, from_date, to_date)
return res and res[0] or 0.0
def sum_hours(self, code, from_date, to_date=None):
res = self._sum(code, from_date, to_date)
return res and res[1] or 0.0
class Payslips(BrowsableObject):
"""a class that will be used into the python code, mainly for usability purposes"""
def sum(self, code, from_date, to_date=None):
if to_date is None:
to_date = fields.Date.today()
self.env.cr.execute("""SELECT sum(case when hp.credit_note = False then (pl.total) else (-pl.total) end)
FROM hr_payslip as hp, hr_payslip_line as pl
WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""",
(self.employee_id, from_date, to_date, code))
res = self.env.cr.fetchone()
return res and res[0] or 0.0
#we keep a dict with the result because a value can be overwritten by another rule with the same code
result_dict = {}
rules_dict = {}
worked_days_dict = {}
inputs_dict = {}
blacklist = []
payslip = self.env['hr.payslip'].browse(payslip_id)
for worked_days_line in payslip.worked_days_line_ids:
worked_days_dict[worked_days_line.code] = worked_days_line
for input_line in payslip.input_line_ids:
inputs_dict[input_line.code] = input_line
categories = BrowsableObject(payslip.employee_id.id, {}, self.env)
inputs = InputLine(payslip.employee_id.id, inputs_dict, self.env)
worked_days = WorkedDays(payslip.employee_id.id, worked_days_dict, self.env)
payslips = Payslips(payslip.employee_id.id, payslip, self.env)
rules = BrowsableObject(payslip.employee_id.id, rules_dict, self.env)
baselocaldict = {'categories': categories, 'rules': rules, 'payslip': payslips, 'worked_days': worked_days,
'inputs': inputs}
# get the ids of the structures on the contracts and their parent id as well
contracts = self.env['hr.contract'].browse(contract_ids)
structure_ids = contracts.get_all_structures()
# get the rules of the structure and thier children
rule_ids = self.env['hr.payroll.structure'].browse(structure_ids).get_all_rules()
# leave salary computation
if payslip.leave_salary:
leave_sal_basic = self.env.ref('hr_vacation_mngmt.hr_salary_rule_leave_salary_basic')
leave_sal_gross = self.env.ref('hr_vacation_mngmt.hr_salary_rule_leave_salary_gross')
default_leave_salary = self.env['ir.config_parameter'].sudo().get_param('default_leave_salary')
if default_leave_salary == '0':
leave_salary = leave_sal_basic
elif default_leave_salary == '1':
leave_salary = leave_sal_gross
else:
leave_salary = leave_sal_basic
rule_ids.append((leave_salary.id, leave_salary.sequence))
# run the rules by sequence
sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x:x[1])]
sorted_rules = self.env['hr.salary.rule'].browse(sorted_rule_ids)
for contract in contracts:
employee = contract.employee_id
localdict = dict(baselocaldict, employee=employee, contract=contract)
for rule in sorted_rules:
key = rule.code + '-' + str(contract.id)
localdict['result'] = None
localdict['result_qty'] = 1.0
localdict['result_rate'] = 100
#check if the rule can be applied
if rule._satisfy_condition(localdict) and rule.id not in blacklist:
#compute the amount of the rule
amount, qty, rate = rule._compute_rule(localdict)
#check if there is already a rule computed with that code
previous_amount = rule.code in localdict and localdict[rule.code] or 0.0
#set/overwrite the amount computed for this rule in the localdict
tot_rule = amount * qty * rate / 100.0
localdict[rule.code] = tot_rule
rules_dict[rule.code] = rule
#sum the amount for its salary category
localdict = _sum_salary_rule_category(localdict, rule.category_id, tot_rule - previous_amount)
#create/overwrite the rule in the temporary results
result_dict[key] = {
'salary_rule_id': rule.id,
'contract_id': contract.id,
'name': rule.name,
'code': rule.code,
'category_id': rule.category_id.id,
'sequence': rule.sequence,
'appears_on_payslip': rule.appears_on_payslip,
'condition_select': rule.condition_select,
'condition_python': rule.condition_python,
'condition_range': rule.condition_range,
'condition_range_min': rule.condition_range_min,
'condition_range_max': rule.condition_range_max,
'amount_select': rule.amount_select,
'amount_fix': rule.amount_fix,
'amount_python_compute': rule.amount_python_compute,
'amount_percentage': rule.amount_percentage,
'amount_percentage_base': rule.amount_percentage_base,
'register_id': rule.register_id.id,
'amount': amount,
'employee_id': contract.employee_id.id,
'quantity': qty,
'rate': rate,
}
else:
#blacklist this rule and its children
blacklist += [id for id, seq in rule._recursive_search_of_rules()]
return list(result_dict.values())
class HrPayrollConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
default_leave_salary = fields.Selection([('0', 'Basic'), ('1', 'Gross')], string='Leave Salary')
def get_values(self):
res = super(HrPayrollConfigSettings, self).get_values()
res.update(
default_leave_salary=self.env['ir.config_parameter'].sudo().get_param('default_leave_salary')
)
return res
def set_values(self):
super(HrPayrollConfigSettings, self).set_values()
self.env['ir.config_parameter'].sudo().set_param('default_leave_salary', self.default_leave_salary)

171
hr_vacation_mngmt/models/hr_vacation.py

@ -0,0 +1,171 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta, date
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class HrLeaveRequest(models.Model):
_inherit = 'hr.holidays'
remaining_leaves = fields.Float(string='Remaining Legal Leaves', related='employee_id.remaining_leaves')
overlapping_leaves = fields.Many2many('hr.holidays', compute='get_overlapping_leaves', string='Overlapping Leaves')
pending_tasks = fields.One2many('pending.task', 'leave_id', string='Pending Tasks')
holiday_managers = fields.Many2many('res.users', compute='get_hr_holiday_managers')
flight_ticket = fields.One2many('hr.flight.ticket', 'leave_id', string='Flight Ticket')
@api.one
def get_overlapping_leaves(self):
if self.type == 'remove' and self.date_from and self.date_to:
overlap_leaves = []
from_date = datetime.strptime(self.date_from, '%Y-%m-%d %H:%M:%S').date()
to_date = datetime.strptime(self.date_to, '%Y-%m-%d %H:%M:%S').date()
r = (to_date + timedelta(days=1) - from_date).days
leave_dates = [str(from_date + timedelta(days=i)) for i in range(r)]
leaves = self.env['hr.holidays'].search([('state', '=', 'validate'), ('type', '=', 'remove'),
('department_id', '=', self.department_id.id)])
other_leaves = leaves - self
for leave in other_leaves:
frm_dte = datetime.strptime(leave.date_from, '%Y-%m-%d %H:%M:%S').date()
to_dte = datetime.strptime(leave.date_to, '%Y-%m-%d %H:%M:%S').date()
r = (to_dte + timedelta(days=1) - frm_dte).days
leave_dtes = [str(frm_dte + timedelta(days=i)) for i in range(r)]
if set(leave_dtes).intersection(set(leave_dates)):
overlap_leaves.append(leave.id)
self.update({'overlapping_leaves': [(6, 0, overlap_leaves)]})
@api.multi
def action_approve(self):
# if double_validation: this method is the first approval approval
# if not double_validation: this method calls action_validate() below
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
raise UserError(_('Only an HR Officer or Manager can approve leave requests.'))
manager = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
for holiday in self:
if holiday.state != 'confirm':
raise UserError(_('Leave request must be confirmed ("To Approve") in order to approve it.'))
if holiday.pending_tasks:
if holiday.user_id:
ctx = dict(self.env.context or {})
ctx.update({
'default_leave_req_id': self.id,
})
return {
'name': _('Re-Assign Task'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'task.reassign',
'target': 'new',
'context': ctx,
}
else:
raise UserError(_('Please configure user for the employee %s') % (holiday.employee_id.name,))
else:
if holiday.double_validation:
return holiday.write({'state': 'validate1', 'manager_id': manager.id if manager else False})
else:
holiday.action_validate()
def book_ticket(self):
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
raise UserError(_('Only an HR Officer or Manager can book flight tickets.'))
ctx = dict(self.env.context or {})
ctx.update({
'default_employee_id': self.employee_id.id,
'default_leave_id': self.id,
})
return {
'name': _('Book Flight Ticket'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'view_id': self.env.ref('hr_vacation_mngmt.view_hr_book_flight_ticket_form').id,
'res_model': 'hr.flight.ticket',
'target': 'new',
'context': ctx,
}
@api.one
def get_hr_holiday_managers(self):
self.holiday_managers = self.env.ref('hr_holidays.group_hr_holidays_manager').users
def view_flight_ticket(self):
return {
'name': _('Flight Ticket'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'hr.flight.ticket',
'target': 'current',
'res_id': self.flight_ticket[0].id,
}
@api.model
def send_leave_reminder(self):
leave_request = self.env['hr.holidays'].search([('type', '=', 'remove'), ('state', '=', 'validate')])
leave_reminder = self.env['ir.config_parameter'].sudo().get_param('leave_reminder')
reminder_day_before = int(self.env['ir.config_parameter'].sudo().get_param('reminder_day_before'))
mail_template = self.env.ref('hr_vacation_mngmt.email_template_hr_leave_reminder_mail')
holiday_managers = self.env.ref('hr_holidays.group_hr_holidays_manager').users
today = date.today()
if leave_reminder:
for request in leave_request:
if request.date_from:
from_date = datetime.strptime(request.date_from, '%Y-%m-%d %H:%M:%S').date()
if reminder_day_before == 0:
prev_reminder_day = request.date_from
else:
prev_reminder_day = from_date - timedelta(days=reminder_day_before)
if prev_reminder_day == today:
for manager in holiday_managers:
template = mail_template.sudo().with_context(
email_to=manager.email,
)
template.send_mail(request.id, force_send=True)
class PendingTask(models.Model):
_name = 'pending.task'
name = fields.Char(string='Task', required=True)
leave_id = fields.Many2one('hr.holidays', string='Leave Request')
dept_id = fields.Many2one('hr.department', string='Department', related='leave_id.department_id')
project_id = fields.Many2one('project.project', string='Project', required=True)
description = fields.Text(string='Description')
assigned_to = fields.Many2one('hr.employee', string='Assigned to',
domain="[('department_id', '=', dept_id)]")
unavailable_employee = fields.Many2many('hr.employee', string='Unavailable Employees',
compute='get_unavailable_employee')
@api.one
def get_unavailable_employee(self):
unavail_emp = []
for leave in self.leave_id.overlapping_leaves:
unavail_emp.append(leave.employee_id.id)
self.update({'unavailable_employee': unavail_emp})
class HrVacationConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
leave_reminder = fields.Boolean(string='Leave Reminder Email', help="Send leave remainder emails to hr managers")
reminder_day_before = fields.Integer(string='Reminder Day Before')
default_expense_account = fields.Many2one('account.account', string='Travel Expense Account')
def get_values(self):
res = super(HrVacationConfigSettings, self).get_values()
res.update(
leave_reminder=self.env['ir.config_parameter'].sudo().get_param('leave_reminder'),
reminder_day_before=int(self.env['ir.config_parameter'].sudo().get_param('reminder_day_before')),
default_expense_account=int(self.env['ir.config_parameter'].sudo().get_param('travel_expense_account'))
)
return res
def set_values(self):
super(HrVacationConfigSettings, self).set_values()
self.env['ir.config_parameter'].sudo().set_param('leave_reminder', self.leave_reminder)
self.env['ir.config_parameter'].sudo().set_param('reminder_day_before', self.reminder_day_before)
self.env['ir.config_parameter'].sudo().set_param('travel_expense_account', self.default_expense_account.id)

11
hr_vacation_mngmt/security/hr_vacation_security.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="property_rule_hr_flight_ticket" model="ir.rule">
<field name="name">Hr Flight Ticket Multi Company</field>
<field name="model_id" ref="model_hr_flight_ticket"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
</data>
</odoo>

8
hr_vacation_mngmt/security/ir.model.access.csv

@ -0,0 +1,8 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_flight_ticket_user,hr.flight.ticket.user,model_hr_flight_ticket,hr_holidays.group_hr_holidays_user,1,1,1,1
access_hr_flight_ticket_employee,hr.flight.ticket.employee,model_hr_flight_ticket,base.group_user,1,1,1,1
access_pending_task_user,pending.task.user,model_pending_task,hr_holidays.group_hr_holidays_user,1,1,1,1
access_pending_task_employee,pending.task.employee,model_pending_task,base.group_user,1,1,1,1
access_account_invoice,account.invoice.hr_manager,account.model_account_invoice,hr_holidays.group_hr_holidays_manager,1,0,0,0
access_account_invoice_tax,account.invoice.tax.hr_manager,account.model_account_invoice_tax,hr_holidays.group_hr_holidays_manager,1,0,0,0
access_account_move_line,account.move.line.hr_manager,account.model_account_move_line,hr_holidays.group_hr_holidays_manager,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_hr_flight_ticket_user hr.flight.ticket.user model_hr_flight_ticket hr_holidays.group_hr_holidays_user 1 1 1 1
3 access_hr_flight_ticket_employee hr.flight.ticket.employee model_hr_flight_ticket base.group_user 1 1 1 1
4 access_pending_task_user pending.task.user model_pending_task hr_holidays.group_hr_holidays_user 1 1 1 1
5 access_pending_task_employee pending.task.employee model_pending_task base.group_user 1 1 1 1
6 access_account_invoice account.invoice.hr_manager account.model_account_invoice hr_holidays.group_hr_holidays_manager 1 0 0 0
7 access_account_invoice_tax account.invoice.tax.hr_manager account.model_account_invoice_tax hr_holidays.group_hr_holidays_manager 1 0 0 0
8 access_account_move_line account.move.line.hr_manager account.model_account_move_line hr_holidays.group_hr_holidays_manager 1 0 0 0

BIN
hr_vacation_mngmt/static/description/HRMS-BUTTON.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
hr_vacation_mngmt/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
hr_vacation_mngmt/static/description/cybro-service.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

BIN
hr_vacation_mngmt/static/description/cybro_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
hr_vacation_mngmt/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

216
hr_vacation_mngmt/static/description/index.html

@ -0,0 +1,216 @@
<section class="oe_container ">
<div class="oe_row">
<h2 class="oe_slogan">Open HRMS</h2>
<h3 class="oe_slogan">Most advanced open source HR management software</h3>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced oe_mt32">
<div class="oe_span">
<div class="oe_demo oe_picture oe_screenshot">
<a href="https://www.openhrms.com/#request-demo">
<img src="HRMS-BUTTON.png">
</a>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Open HRMS Vacation Management</h2>
<h3 class="oe_slogan">Manage Employee Vacation</h3>
<h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a></h4>
</div>
<div class="oe_row oe_spaced" style="padding-left:65px;">
<h4>Features:</h4>
<div>
<span style="color:green;"> &#9745; </span>Remaining legal leaves in leave request to approval.<br/>
<span style="color:green;"> &#9745; </span>Overlapping leaves.<br/>
<span style="color:green;"> &#9745; </span>Leave notification.<br/>
<span style="color:green;"> &#9745; </span>Leave salary.<br/>
<span style="color:green;"> &#9745; </span>Pending task update and re-assign task.<br/>
<span style="color:green;"> &#9745; </span>Flight ticket booking.<br/>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="" style="text-align: center;">
<div class="oe_picture">
<h3 class="oe_slogan">Overview</h3>
<p class="oe_mt32">
This module extend Odoo default HR Holiday Management with extra features adaptable for managing employees vacation..
</p>
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div style="text-align: center">
<p><h4 class="oe_slogan">Remaining & Overlapping Leaves</h4><p>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_01.png">
</div>
</a>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div style="text-align: center">
<p><h4 class="oe_slogan">Pending Tasks Update & Task Re-assign</h4><p>
</div>
<div style="text-align: center">
<p class="oe_mt32">
Employees can able to update their pending tasks on leave request
</p>
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_02.png">
</div>
</a>
</div>
<div style="text-align: center">
<p class="oe_mt32">
On leave request approval it opens a wizard to re-assign tasks to available employees.
</p>
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_03.png">
</div>
</a>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div style="text-align: center">
<p><h4 class="oe_slogan">Flight Ticket Booking</h4><p>
</div>
<div style="text-align: center">
<p class="oe_mt32">
HR managers can able to book the flight ticket for the employee.
</p>
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_04.png">
</div>
</a>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_05.png">
</div>
</a>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_06.png">
</div>
</a>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_07.png">
</div>
</a>
</div>
<div style="text-align: center">
<p class="oe_mt32">
On confirming the flight ticket generate corresponding supplier invoice.
</p>
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_08.png">
</div>
</a>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div style="text-align: center">
<p><h4 class="oe_slogan">Leave Salary</h4><p>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_09.png">
</div>
</a>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div style="text-align: center">
<p><h4 class="oe_slogan">Configurations</h4><p>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_10.png">
</div>
</a>
</div>
<div style="text-align: center">
<a href="https://www.cybrosys.com">
<div class="oe_demo oe_picture oe_screenshot">
<img style="border:10px solid white;" src="ohrms_vacation_11.png">
</div>
</a>
</div>
</div>
</section>
<div class="row section-content">
<div class="col-md-6 img-content">
<h3>Our Odoo Services</h3>
</div>
<div class="bc-span col-md-12"><div class="inner-span">
<a target="_blank" href="https://www.openhrms.com"><img class="img-border img-responsive thumbnail" src="cybro-service.png"></a>
</div></div>
</div>
<section class="oe_container">
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2>
<div class="oe_slogan" style="margin-top:10px !important;">
<div>
<a
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;"
href="https://www.cybrosys.com/contact/" target="_blank"><i
class="fa fa-phone"></i> Contact Us </a>
<a
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;"
href="https://www.odoo.com/apps/modules/browse?search=open+hrms" target="_blank"><i
class="fa fa-suitcase"></i> Other Open HRMS Addons </a>
<a
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;"
href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"><i
class="fa fa-wrench"></i> Request Customization </a>
</div>
<br>
<a href="https://www.cybrosys.com/" target="_blank">
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block">
</a>
</div>
</section>

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_02.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_03.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_04.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_05.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_06.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_07.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_08.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_09.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
hr_vacation_mngmt/static/description/ohrms_vacation_11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

121
hr_vacation_mngmt/views/hr_employee_ticket.xml

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_hr_flight_ticket_form" model="ir.ui.view">
<field name="name">hr.flight.ticket.form</field>
<field name="model">hr.flight.ticket</field>
<field name="priority" eval="0"/>
<field name="arch" type="xml">
<form string="Flight Ticket" create="0">
<header>
<button name="confirm_ticket" states="booked" string="Confirm" type="object" class="oe_highlight"/>
<button name="cancel_ticket" string="Cancel" type="object" states="booked,confirmed"/>
<field name="state" widget="statusbar"
statusbar_visible="booked,confirmed,started,completed"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_view_invoice"
string="Invoice"
type="object"
class="oe_stat_button"
icon="fa-pencil-square-o"
attrs="{'invisible':[('invoice_id','=', False)]}">
</button>
<field name="invoice_id" invisible="1"/>
</div>
<div class="oe_title">
<h1><field name="display_name"/></h1>
</div>
<group>
<group>
<field name="employee_id" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="depart_from" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="date_start" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="ticket_class" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="flight_details" attrs="{'readonly': [('state','=','completed')]}"/>
<field name="company_id" invisible="1"/>
</group>
<group>
<field name="ticket_type" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="destination" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="date_return" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="ticket_fare" attrs="{'readonly': [('state','in',('confirmed','started','completed'))]}"/>
<field name="leave_id" invisible="1"/>
<field name="return_flight_details"
attrs="{'readonly': [('state','=','completed')],
'invisible':[('ticket_type', '=', 'one')]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_hr_flight_ticket_tree" model="ir.ui.view">
<field name="name">hr.flight.ticket.form</field>
<field name="model">hr.flight.ticket</field>
<field name="priority" eval="1"/>
<field name="arch" type="xml">
<tree string="Flight Ticket" create="0">
<field name="employee_id"/>
<field name="date_start"/>
<field name="date_return"/>
<field name="ticket_type"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_hr_book_flight_ticket_form" model="ir.ui.view">
<field name="name">hr.flight.ticket.form</field>
<field name="model">hr.flight.ticket</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<form string="Flight Ticket" create="0">
<div class="oe_title">
<h1><field name="name" readonly="1"/></h1>
</div>
<group>
<group>
<field name="employee_id" readonly="1"/>
<field name="depart_from"/>
<field name="date_start"/>
<field name="ticket_class"/>
</group>
<group>
<field name="ticket_type"/>
<field name="destination"/>
<field name="date_return"/>
<field name="leave_id" invisible="1"/>
</group>
</group>
<footer>
<button name="book_ticket" type="object" string="Book Ticket" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_hr_flight_tickets" model="ir.actions.act_window">
<field name="name">Flight Tickets</field>
<field name="res_model">hr.flight.ticket</field>
<field name="view_mode">tree,form</field>
<field name="view_type">form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
There is no previously booked flight ticket details available.
</p>
</field>
</record>
<menuitem
id="menu_hr_flight_tickets"
name="Flight Tickets"
parent="hr_holidays.menu_hr_holidays_root"
action="action_hr_flight_tickets"
groups="hr_holidays.group_hr_holidays_manager"
sequence="5"/>
</data>
</odoo>

39
hr_vacation_mngmt/views/hr_payslip.xml

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="view_hr_payslip_leave_salary_form">
<field name="name">hr.payslip.form</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="hr_payroll.view_hr_payslip_form"/>
<field name="arch" type="xml">
<field name="credit_note" position="after">
<field name="leave_salary" attrs="{'readonly': [('state','=', 'done')]}"/>
</field>
</field>
</record>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">Configure Payroll</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="hr_payroll.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='hr_payroll_localization']" position="after">
<h2>Leaves</h2>
<div class="row mt16 o_settings_container" id="hr_leave_salary">
<div class="col-md-6 col-xs-12 o_setting_box">
<div class="o_setting_right_pane">
<label string="Leave Salary"/>
<div class="text-muted">
Leave salary calculation
</div>
<div class="mt16">
<field name="default_leave_salary" widget="radio"/>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

20
hr_vacation_mngmt/views/hr_reminder.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="email_template_hr_leave_reminder_mail" model="mail.template">
<field name="name">Leave : Reminder</field>
<field name="model_id" ref="hr_holidays.model_hr_holidays"/>
<field name="auto_delete" eval="True"/>
<field name="email_from">${object.employee_id.company_id.email}</field>
<field name="subject">Reminder: ${object.display_name}</field>
<field name="body_html"><![CDATA[
<p>Hello ,</p>
<p>The employee <strong>${object.employee_id.name}</strong> has taken <strong>${object.no_of_days_temp}</strong> days leave starting from <strong>${object.date_from}</strong> to <strong>${object.date_to}</strong>.</p>
<p>Kindly do the needful.</p>
</p><p>Thank you!</p>
]]></field>
</record>
</data>
</odoo>

114
hr_vacation_mngmt/views/hr_vacation.xml

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="hr_vacation_form_view" model="ir.ui.view">
<field name="name">Leave Request</field>
<field name="model">hr.holidays</field>
<field name="inherit_id" ref="hr_holidays.edit_holiday_new"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_title')]" position="before">
<div class="oe_button_box" name="button_box">
<button type="object" icon="fa-pencil-square-o" name="view_flight_ticket"
string="Flight Ticket" class="oe_stat_button"
attrs="{'invisible': [('flight_ticket','=', [])]}"
groups="hr_holidays.group_hr_holidays_manager">
</button>
</div>
</xpath>
<button name="action_draft" position="after">
<button string="Book Flight Ticket" name="book_ticket" type="object"
groups="hr_holidays.group_hr_holidays_manager" class="oe_highlight"
attrs="{'invisible': ['|', '|', ('type','=','add'),('state','!=','validate'), ('flight_ticket','!=',[])]}"/>
</button>
<field name="employee_id" position="after">
<field name="remaining_leaves" attrs="{'invisible': [('state','in',('validate', 'refuse'))]}"
readonly="1" groups="hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_manager"/>
<field name="flight_ticket" invisible="1"/>
</field>
<xpath expr="//sheet" position="inside">
<notebook attrs="{'invisible': [('type','=','add')], 'readonly': [('state','in',('validate', 'refuse'))]}">
<page string="Pending Works">
<field name="pending_tasks" widget="one2many_list" attrs="{'readonly': [('state','in',('validate', 'validate1','refuse'))]}">
<tree editable="bottom">
<field name="name"/>
<field name="project_id"/>
<field name="description"/>
<field name="leave_id" invisible="1"/>
<field name="dept_id" invisible="1"/>
</tree>
</field>
</page>
<page string="Overlapping Leaves"
attrs="{'invisible': ['|',('state','in',('validate', 'refuse')),('overlapping_leaves','=',[])]}"
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user">
<field name="overlapping_leaves"/>
</page>
</notebook>
</xpath>
</field>
</record>
<record id="view_pending_task" model="ir.ui.view">
<field name="name">pending.task.form</field>
<field name="model">pending.task</field>
<field name="arch" type="xml">
<form string="Pending Tasks">
<group>
<group>
<field name="name"/>
<field name="leave_id"/>
<field name="project_id"/>
</group>
<group>
<field name="dept_id"/>
<field name="assigned_to" groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"/>
<field name="unavailable_employee" widget="many2many_tags"
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"/>
</group>
<group colspan="4">
<field name="description"/>
</group>
</group>
</form>
</field>
</record>
<record id="view_hr_leave_configuration" model="ir.ui.view">
<field name="name">Configure Leave</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="hr_leave_request_aliasing.view_hr_leave_configuration"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='config_leave']" position="inside">
<div class="col-xs-12 col-md-6 o_setting_box" name="config_leave_reminder">
<div class="o_setting_left_pane">
<field name="leave_reminder"/>
</div>
<div class="o_setting_right_pane">
<label string="Leaves Reminder"/>
<div class="text-muted">
Send leave remainder emails to holiday managers
</div>
<div class="content-group">
<div class="row mt16" attrs="{'invisible': [('leave_reminder', '=', False)]}">
<label string="Days Before" class="col-md-3 o_light_label"/>
<field name="reminder_day_before"/>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" name="config_leave_flight_ticket">
<div class="o_setting_right_pane">
<label string="Flight Ticket"/>
<div class="content-group">
<div class="row mt16">
<label string="Expense Account" class="col-md-3 o_light_label"/>
<field name="default_expense_account"/>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

3
hr_vacation_mngmt/wizard/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import reassign_task

59
hr_vacation_mngmt/wizard/reassign_task.py

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class ReAssignTask(models.TransientModel):
_name = 'task.reassign'
pending_tasks = fields.One2many('pending.task', related='leave_req_id.pending_tasks', string='Pending Tasks')
leave_req_id = fields.Many2one('hr.holidays', string='Leave Request')
@api.multi
def action_approve(self):
task_pending = False
e_unavail = False
emp_unavail = []
for task in self.pending_tasks:
if not task.assigned_to:
task_pending = True
if task_pending:
raise UserError(_('Please assign pending task to employees.'))
else:
for task in self.pending_tasks:
if task.assigned_to in task.unavailable_employee:
emp_unavail.append(task.assigned_to.name)
e_unavail = True
emp_unavail = set(emp_unavail)
emp_unavail_count = len(emp_unavail)
if e_unavail:
if emp_unavail_count == 1:
raise UserError(_('Selected employee %s is not available') % (', '.join(emp_unavail),))
else:
raise UserError(_('Selected employees %s are not available') % (', '.join(emp_unavail),))
else:
manager = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
holiday = self.leave_req_id
tasks = self.env['project.task']
for task in self.pending_tasks:
if not task.assigned_to.user_id:
raise UserError(_('Please configure user for the employee %s') % (task.assigned_to.name,))
vals = {
'name': task.name,
'user_id': task.assigned_to.user_id.id,
'project_id': task.project_id.id,
'description': task.description,
}
tasks.sudo().create(vals)
if holiday.double_validation:
return holiday.write({'state': 'validate1', 'manager_id': manager.id if manager else False})
else:
holiday.action_validate()
@api.multi
def cancel(self):
for task in self.pending_tasks:
task.update({'assigned_to': False})
return {'type': 'ir.actions.act_window_close'}

31
hr_vacation_mngmt/wizard/reassign_task.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="reassign_task_form" model="ir.ui.view">
<field name="name">Re-Assign Task</field>
<field name="model">task.reassign</field>
<field name="arch" type="xml">
<form>
<h3>Confirm leave request and reassign pending works of the employee.</h3>
<group>
<field name="leave_req_id" invisible="1"/>
<field name="pending_tasks" widget="one2many_list">
<tree create="0" delete="0" editable="bottom">
<field name="name" readonly="1"/>
<field name="project_id" readonly="1"/>
<field name="assigned_to"/>
<field name="leave_id" invisible="1"/>
<field name="dept_id" invisible="1"/>
<field name="unavailable_employee" invisible="1"/>
</tree>
</field>
</group>
<footer>
<button string="Confirm" name="action_approve" type="object" class="btn-primary"/>
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
</data>
</odoo>
Loading…
Cancel
Save