25 Commits

Author SHA1 Message Date
f5377a3af3 [ADD]project_timesheet_holidays_type 2024-06-03 18:48:29 +02:00
b406aeb2f1 [ADD]project_timesheet_holidays_type 2024-06-03 15:11:50 +02:00
34abfad364 [ADD]hr_usability_elabore 2024-02-15 16:10:22 +01:00
edc8cffc69 Initial Commit 2023-12-21 12:02:04 +01:00
clementthomas
141ad6bfcd [IMP] hr_expense_specific_journal: set default journal 2023-10-17 12:29:02 +02:00
clementthomas
d59b2df993 [NEW] hr_expense_specific_journal 2023-10-11 09:30:35 +02:00
clementthomas
cf29d356fe [IMP] hr_expense_report_merge_attachment: rename module 2023-07-10 16:37:45 +02:00
clementthomas
b282d2f726 [IMP] hr_expense_analytic_account_preselect_with_project: String and required project field 2023-06-23 11:04:10 +02:00
clementthomas
0e80defb81 [NEW] hr_expense_analytic_account_preselect_with_project: new module 2023-06-22 14:28:18 +02:00
clementthomas
81010e0145 [ADD] hr_expense_report_merge_attachment: Merge expense attachments in report 2023-05-16 09:56:53 +02:00
clementthomas
7694bd5c06 [IMP] hr_luncheon_voucher: add voucher balance field 2023-04-28 14:55:46 +02:00
clementthomas
0538e04997 [IMP] hr_luncheon_voucher: search of Luncheon Voucher
add search by employee and distrib_campaign_name, whatever the company
2023-04-17 15:13:00 +02:00
clementthomas
c7f2d0683b [FIX] hr_effective_attendance_period: DST
daylight saving time (DST) fix when compute UTC time
2023-04-13 08:36:10 +02:00
Stéphan Sainléger
070bdaca52 [FIX] hr_effective_attendance_period: fix timezone consideration 2023-02-27 16:05:46 +01:00
Stéphan Sainléger
b08119cf4e [FIX] hr_luncheon_voucher: only consider employee's meetings 2023-02-06 23:36:39 +01:00
Stéphan Sainléger
dbfa5624a3 [I18N] hr_effective_attendance_period: add french translation 2023-02-01 23:35:55 +01:00
Stéphan Sainléger
06e0793a6c [FIX] hr_luncheon_voucher: fix french translation issues
french translations weren not loaded
2023-02-01 23:34:16 +01:00
Stéphan Sainléger
cc901c2e62 [REF] hr_luncheon_voucher: remove useless code 2023-02-01 23:25:51 +01:00
Stéphan Sainléger
8579e22474 [REF] hr-luncheon-voucher: rename add-on in hr_luncheon_voucher
to respect OCA guidelines
2023-02-01 23:25:51 +01:00
Stéphan Sainléger
68788e3950 [IMP] hr-luncheon-voucher: move resource code to dedicated addon
Moves code in add-on hr_effective_attendance_period
2023-01-24 22:24:57 +01:00
Stéphan Sainléger
c7e1c8de0b [IMP] hr_effective_attendance_period: add resource.calendar code
adds several usability functions in resource.calendar model.
2023-01-24 22:23:28 +01:00
Stéphan Sainléger
4dc8241a5e [I18N] hr-luncheon-voucher: add french translations 2023-01-19 14:52:52 +01:00
Stéphan Sainléger
250b9022cf [IMP] hr-luncheon-voucher: improve allocation form creation process 2023-01-19 10:14:47 +01:00
Stéphan Sainléger
eab094677a [IMP] hr-luncheon-voucher: add effective attendance as criteria
The calculation of eligible attendances now also depends on the
effective attendance period field.
2023-01-18 15:16:05 +01:00
Stéphan Sainléger
2a6fb40a15 [NEW] hr_effective_attendance_period: create add-on 2023-01-18 14:38:51 +01:00
28 changed files with 78 additions and 732 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.*~
*.pyc

View File

@@ -1,79 +0,0 @@
===================
HR Luncheon Voucher
===================
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--analytic-lightgray.png?logo=github
:target: https://github.com/elabore-coop/hr-tools
:alt: elabore/hr-tools
|badge1| |badge2| |badge3|
This module allows the management of Luncheon Vouchers attribution and distribution.
Employees can indicate which days are not concerned by luncheon vouchers.
HR managers can ajust the number of luncheon vouchers to distribute, and follow each employee credit.
Installation
============
Use Odoo normal module installation procedure to install ``hr-luncheon-voucher``.
Configuration
=============
1. Go to ``Configuration > Technical > Calendar > Meeting Types`` and define the meeting categories which cancel the daily luncheon voucher distribution.
2. Go to ``Configuration > General Settings > Employees`` and define if employees need to work the whole day to get a luncheon voucher.
3. Go to ``Employees`` and define for each employee the default number of luncheon vouchers to distribute in each distribution campaign.
Use
===
- when an calendar event makes the luncheon voucher distribution cancelled (Off-site or free lunch for instance), add the corresponding category to the event.
- for each distribution period, the HR manager should:
- go in ``Employees`` tree view
- select all the employees concerned by luncheon vouchers distribution
- click on header button ``Generate luncheon vouchers allocation``
- Fill the wizard form
- a voucher allocation request is created for each employee
- HR manager confirms an allocation request when the figures are confirmed
- HR manager marks the requests as "Distributed" when the vouchers has been effectively distributed
- HR manager can correct the allocation requests with ``Back to draft`` button
- employees' luncheon voucher counters are updated considering the vouchers acquired, dued and distributed at each campaign.
**Attribution rules:**
- a luncheon voucher is acquired for a working day if:
- the employee worked on one or all the attendances of the day (depending if option ``Half working days cancel luncheon vouchers`` is True or not)
- there is no meeting which cancel the voucher during that day (``Site off`` or ``Free lunch`` meeting for instance)
- an attendance is considered as worked as long as there is no leave on the whole attendance time slot
Known issues / Roadmap
======================
None yet.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/elabore-coop/hr-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Contributors
------------
- Stéphan Sainléger <https://github.com/stephansainleger>
Funders
-------
The development of this module has been financially supported by:
- Elabore (https://elabore.coop)
- Amaco (https://amaco.org)
Maintainer
----------
This module is maintained by ELABORE.

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizard

View File

@@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
{
"name": "HR Luncheon Voucher",
"category": "Human Resources",
"version": "14.0.1.0",
"summary": "Manage luncheon vouchers credit and distribution",
"author": "Elabore",
"website": "https://elabore.coop/",
"installable": True,
"application": True,
"auto_install": False,
"depends": [
"base",
"calendar",
"hr",
"hr_holidays",
"resource",
],
"data": [
"security/ir.model.access.csv",
"views/event_type.xml",
"views/hr_employee_views.xml",
"views/hr_lv_allocation_views.xml",
"views/res_config_settings_views.xml",
"views/menus.xml",
"wizard/generate_lv_allocations_wizard.xml",
"data/event_type_data.xml",
],
"qweb": [],
}

View File

@@ -1,16 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="categ_meet_free_lunch" model="calendar.event.type">
<field name="name">Free lunch</field>
<field name="ref">categ_meet_free_lunch</field>
<field name="remove_luncheon_voucher">1</field>
</record>
<record id="categ_meet_offsite" model="calendar.event.type">
<field name="name">Off-site</field>
<field name="ref">categ_meet_offsite</field>
<field name="remove_luncheon_voucher">1</field>
</record>
</data>
</odoo>

View File

@@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
from . import calendar_event_type
from . import hr_employee
from . import hr_lv_allocation
from . import resource
from . import res_company
from . import res_config_settings

View File

@@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import fields, models, _
class MeetingType(models.Model):
_inherit = "calendar.event.type"
ref = fields.Char(
string=_("Reference"),
copy=False,
store=True,
)
remove_luncheon_voucher = fields.Boolean(
string=_("Remove luncheon voucher"),
copy=True,
store=True,
)

View File

@@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
from xml.dom.minicompat import EmptyNodeList
from odoo import fields, models, api, _
class HrEmployeeBase(models.AbstractModel):
_inherit = "hr.employee.base"
lv_allocations_ids = fields.One2many("hr.lv.allocation", "employee_id")
total_acquired_lv = fields.Integer(
string=_("Total allocated luncheon vouchers"), store=True, copy=False
)
distributed_lv = fields.Integer(
string=_("Distributed luncheon vouchers"), store=True, copy=False
)
dued_lv = fields.Integer(
string=_("Remaining luncheon vouchers"), store=True, copy=False
)
default_monthly_lv = fields.Integer(
string=_("Default monthly distribution"), store=True, copy=True
)
def refresh_lv_values(self):
for record in self:
record._compute_total_acquired_lv()
record._compute_distributed_lv()
record._compute_dued_lv()
def _compute_total_acquired_lv(self):
for record in self:
allocations = self.env["hr.lv.allocation"].search(
[("employee_id", "=", record.id), ("state", "=", ["confirmed", "distributed"])]
)
record.total_acquired_lv = sum(allocations.mapped("number_acquired_lv"))
def _compute_distributed_lv(self):
for record in self:
allocations = self.env["hr.lv.allocation"].search(
[("employee_id", "=", record.id), ("state", "=", "distributed")]
)
record.distributed_lv = sum(allocations.mapped("number_distributed_lv"))
def _compute_dued_lv(self):
for record in self:
record.dued_lv = record.total_acquired_lv - record.distributed_lv
def generate_mass_lv_allocation(self, values):
for record in self:
record.generate_lv_allocation(values)
def generate_lv_allocation(self, values):
self.ensure_one()
values["employee_id"] = self.id
values["name"] = values["distrib_campaign_name"] + " - " + self.name
self.env["hr.lv.allocation"].create(values)
def action_lv_allocations(self):
action = self.env["ir.actions.act_window"]._for_xml_id("hr-luncheon-voucher.act_lv_allocations")
action['context'] = {
'search_default_employee_id': self.id,
'default_employee_id': self.id,
}
action['domain'] = [('employee_id', '=', self.id)]
return action
def action_lv_allocations_requests_wizard(self):
action = self.env["ir.actions.act_window"]._for_xml_id(
"hr-luncheon-voucher.lv_allocations_requests_wizard_action"
)
ctx = dict(self.env.context)
ctx["active_ids"] = self.ids
action["context"] = ctx
return action

View File

@@ -1,187 +0,0 @@
# -*- coding: utf-8 -*-
import math
from datetime import datetime, date, timedelta, time
from dateutil.rrule import rrule, DAILY
from pytz import timezone, UTC, utc
from odoo import fields, models, api, _
class LuncheonVouchersAllocation(models.Model):
_name = "hr.lv.allocation"
_description = "Luncheon Vouchers Allocation"
_order = "create_date desc"
_inherit = ["mail.thread", "mail.activity.mixin"]
_mail_post_access = "read"
name = fields.Char('Name')
distrib_campaign_name = fields.Char('Distribution campaign')
state = fields.Selection(
[
("draft", "Draft"),
("confirmed", "Confirmed"),
("distributed", "Distributed"),
],
string="Status",
readonly=True,
tracking=True,
copy=False,
default="draft",
help="The status is set to 'Draft', when an allocation request is created."
+ "\nThe status is 'Confirmed', when an allocation request is confirmed by HR manager."
+ "\nThe status is 'Distributed', when the luncheon vouchers have been distributed.",
)
date_from = fields.Datetime(
string=_("Start Date"),
store=True,
readonly=False,
copy=False,
tracking=True,
states={
"confirmed": [("readonly", True)],
"distributed": [("readonly", True)],
},
)
date_to = fields.Datetime(
string=_("End Date"),
store=True,
readonly=False,
copy=False,
tracking=True,
states={
"confirmed": [("readonly", True)],
"distributed": [("readonly", True)],
},
)
employee_id = fields.Many2one(
"hr.employee",
store=True,
string=_("Employee"),
index=True,
readonly=False,
ondelete="restrict",
tracking=True,
states={
"confirmed": [("readonly", True)],
"distributed": [("readonly", True)],
},
)
number_acquired_lv = fields.Integer(
string=_("Acquired Vouchers"),
store=True,
readonly=False,
tracking=True,
states={
"confirmed": [("readonly", True)],
"distributed": [("readonly", True)],
},
)
number_dued_lv = fields.Integer(
string=_("Dued Vouchers"),
store=True,
readonly=False,
tracking=True,
states={
"confirmed": [("readonly", True)],
"distributed": [("readonly", True)],
},
)
number_distributed_lv = fields.Integer(
string=_("Distributed Vouchers"),
store=True,
readonly=False,
tracking=True,
states={
"confirmed": [("readonly", False)],
"distributed": [("readonly", True)],
},
)
def create(self, values):
res = super(LuncheonVouchersAllocation, self).create(values)
res._calculate_number_acquired_lv()
res._calculate_number_dued_lv()
res._default_number_distributed_lv()
return res
@api.depends("employee_id")
def _default_number_distributed_lv(self):
for record in self:
record.number_distributed_lv = record.employee_id.default_monthly_lv
def _has_cancelling_voucher_event(self, day):
category_no_voucher_ids = self.env["calendar.event.type"].search([("remove_luncheon_voucher", "=", True)])
events = self.env["calendar.event"].search([("categ_ids", "in", category_no_voucher_ids.ids)])
day_start = fields.Datetime.to_datetime(day.date())
day_end = fields.Datetime.to_datetime(day.date()) + timedelta(hours=24)
cancelling_events = events.filtered(lambda x: not((x.start < day_start) and (x.stop <= day_start)) and not((x.start >= day_end) and (x.stop > day_end)) )
if len(cancelling_events) > 0:
return True
else:
return False
def _calculate_number_acquired_lv(self):
nb_eligible_days = 0
dfrom = datetime.combine(fields.Date.from_string(self.date_from), time.min).replace(tzinfo=UTC)
dto = datetime.combine(fields.Date.from_string(self.date_to), time.max).replace(tzinfo=UTC)
period_days = rrule(DAILY, dfrom, until=dto)
calendar_resource = self.employee_id.resource_calendar_id
for day in period_days:
# Check if this days is a working day
if not calendar_resource.is_working_day(day):
continue
# The employee should work this day but...
if self.env.company.hr_half_day_cancels_voucher and not calendar_resource.is_full_working_day(day):
# The luncheon voucher is acquired only if the employee has worked the entire day
continue
# Check leaves
if not calendar_resource.is_worked_day(self.employee_id, day):
continue
# The employee has worked this day but...
if self.env.company.hr_half_day_cancels_voucher and not calendar_resource.all_attendances_worked(self.employee_id.resource_id, day):
# The luncheon voucher is acquired only if the employee has worked the entire day
continue
# Check there is no event cancelling the voucher
if self._has_cancelling_voucher_event(day):
continue
# All checks passed, the days is eligible for a voucher
nb_eligible_days += 1
self.number_acquired_lv = nb_eligible_days
def _calculate_number_dued_lv(self):
for record in self:
if record.state == "distributed":
record.number_dued_lv = record.employee_id.dued_lv
else:
record.number_dued_lv = (
record.employee_id.dued_lv + record.number_acquired_lv
)
def confirm_allocation(self):
for record in self:
if record.state == "draft":
record.state = "confirmed"
record.employee_id._compute_total_acquired_lv()
record.employee_id._compute_dued_lv()
def back_to_draft(self):
for record in self:
if record.state in ["confirmed","distributed"]:
record.state = "draft"
record.employee_id._compute_total_acquired_lv()
record.employee_id._compute_distributed_lv()
record.employee_id._compute_dued_lv()
def distribute_allocation(self):
for record in self:
if record.state == "confirmed":
record.state = "distributed"
record.employee_id._compute_distributed_lv()
record.employee_id._compute_dued_lv()
def adjust_distribution(self):
for record in self:
for record in self:
if record.state == "draft":
record.number_distributed_lv = record.employee_id.dued_lv + record.number_acquired_lv

View File

@@ -1,7 +0,0 @@
from odoo import fields, models
class Company(models.Model):
_inherit = 'res.company'
hr_half_day_cancels_voucher = fields.Boolean(string="Half working days cancel luncheon vouchers")

View File

@@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
hr_half_day_cancels_voucher = fields.Boolean(string="Half working days cancel luncheon vouchers", related="company_id.hr_half_day_cancels_voucher", readonly=False)

View File

@@ -1,59 +0,0 @@
from datetime import timedelta
import math
from odoo import models, fields
class ResourceCalendar(models.Model):
_inherit = "resource.calendar"
def _retrieve_day_matching_attendances(self, day):
domain = [("calendar_id", "=", self.id),("dayofweek", "=", day.weekday())]
if self.two_weeks_calendar:
# Employee has Even/Odd weekly calendar
week_type = 1 if int(math.floor((day.toordinal() - 1) / 7) % 2) else 0
domain.append(("week_type", "=", week_type))
result = self.env["resource.calendar.attendance"].search(domain)
return result
def is_working_day(self, day):
day_attendances = self._retrieve_day_matching_attendances(day)
if len(day_attendances) == 0:
# This day of the week is not supposed to be a working day
return False
else:
# This day of the week is supposed to be a working day
return True
def is_full_working_day(self, day):
day_attendances = self._retrieve_day_matching_attendances(day)
morning_worked = len(day_attendances.filtered(lambda x: x.day_period == "morning")) > 0
afternoon_worked = len(day_attendances.filtered(lambda x: x.day_period == "afternoon")) > 0
return morning_worked and afternoon_worked
def _is_worked_attendance(self, resource, day, attendance):
attendance_start = fields.Datetime.to_datetime(day.date()) + timedelta(hours=attendance.hour_from)
attendance_end = fields.Datetime.to_datetime(day.date()) + timedelta(hours=attendance.hour_to)
resource_leaves = self.env["resource.calendar.leaves"].search([("resource_id", "=", resource.id), ("date_from", "<=", attendance_start), ("date_to", ">=", attendance_end)])
if resource_leaves:
return False
else:
# a part or the whole attendance is worked
return True
def is_worked_day(self, resource, day):
day_attendances = self._retrieve_day_matching_attendances(day)
# If at least one attendance is worked, return True
for attendance in day_attendances:
if self._is_worked_attendance(resource, day, attendance):
return True
return False
def all_attendances_worked(self, resource, day):
day_attendances = self._retrieve_day_matching_attendances(day)
# If at least one attendance is not worked, return False
for attendance in day_attendances:
if not self._is_worked_attendance(resource, day, attendance):
return False
return True

View File

@@ -1,5 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_lv_allocation_user,access_lv_allocation_user,model_hr_lv_allocation,hr.group_hr_user,1,0,0,0
access_lv_allocation_manager,access_lv_allocation_manager,model_hr_lv_allocation,hr.group_hr_manager,1,1,1,1
access_lv_allocation_wizard_user,access_lv_allocation_wizard_user,model_generate_lv_allocation_requests,hr.group_hr_user,1,0,0,0
access_lv_allocation_wizard_manager,access_lv_allocation_wizard_manager,model_generate_lv_allocation_requests,hr.group_hr_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_lv_allocation_user access_lv_allocation_user model_hr_lv_allocation hr.group_hr_user 1 0 0 0
3 access_lv_allocation_manager access_lv_allocation_manager model_hr_lv_allocation hr.group_hr_manager 1 1 1 1
4 access_lv_allocation_wizard_user access_lv_allocation_wizard_user model_generate_lv_allocation_requests hr.group_hr_user 1 0 0 0
5 access_lv_allocation_wizard_manager access_lv_allocation_wizard_manager model_generate_lv_allocation_requests hr.group_hr_manager 1 1 1 1

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_event_type_luncheonvoucher_tree" model="ir.ui.view">
<field name="name">event.type.luncheonvoucher</field>
<field name="model">calendar.event.type</field>
<field name="inherit_id" ref="calendar.view_calendar_event_type_tree" />
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after">
<field name="remove_luncheon_voucher" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_employee_form_lv" model="ir.ui.view">
<field name="name">hr.employee.form.lv</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form" />
<field name="arch" type="xml">
<header position="inside">
<button type="object" name="refresh_lv_values" string="Refresh Luncheon Vouchers" class="btn-secundary" />
</header>
<xpath expr="//div[@name='button_box']" position="inside">
<button type="object" name="action_lv_allocations" class="oe_stat_button" icon="fa-ticket">
<field name="total_acquired_lv" widget="statinfo" string="Acquired" />
</button>
<button type="object" name="action_lv_allocations" class="oe_stat_button" icon="fa-ticket">
<field name="distributed_lv" widget="statinfo" string="Distributed" />
</button>
<button type="object" name="action_lv_allocations" class="oe_stat_button" icon="fa-ticket">
<field name="dued_lv" widget="statinfo" string="Dued" />
</button>
</xpath>
<xpath expr="//page[@name='hr_settings']/group" position="inside">
<group name="luncheon_vouchers" string="Luncheon Vouchers">
<field name="default_monthly_lv" />
<field name="lv_allocations_ids" />
</group>
</xpath>
</field>
</record>
<record id="view_employee_tree_lv" model="ir.ui.view">
<field name="name">view_employee_tree_lv</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_tree" />
<field name="arch" type="xml">
<xpath expr="//tree" position="inside">
<header>
<button type="object" name="action_lv_allocations_requests_wizard" string="Generate Luncheon Vouchers Allocations" class="btn-primary" />
</header>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_lv_allocation_search" model="ir.ui.view">
<field name="name">hr.lv.allocation.search</field>
<field name="model">hr.lv.allocation</field>
<field name="arch" type="xml">
<search string="Luncheon vouchers allocations">
<field name="state" />
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]" />
<filter name="confirmed" string="Confirmed" domain="[('state', '=', 'confirmed')]" />
<filter name="distributed" string="Distributed" domain="[('state', '=', 'distributed')]" />
</search>
</field>
</record>
<record id="hr_lv_allocation_tree" model="ir.ui.view">
<field name="name">hr.lv.allocation.tree</field>
<field name="model">hr.lv.allocation</field>
<field name="arch" type="xml">
<tree string="Luncheon vouchers allocations">
<header>
<button type="object" name="confirm_allocation" string="Confirm" class="btn-primary" />
<button type="object" name="distribute_allocation" string="Distribute Vouchers" class="btn-primary" />
<button type="object" name="back_to_draft" string="Back to draft" class="btn-secundary" />
<button type="object" name="adjust_distribution" string="Adjust distribution" class="btn-secundary" />
</header>
<field name="distrib_campaign_name" />
<field name="employee_id" />
<field name="state" />
<field name="date_from" widget="date" />
<field name="date_to" widget="date" />
<field name="number_acquired_lv" />
<field name="number_dued_lv" />
<field name="number_distributed_lv" />
</tree>
</field>
</record>
<record id="hr_lv_allocation_form" model="ir.ui.view">
<field name="name">hr.lv.allocation.form</field>
<field name="model">hr.lv.allocation</field>
<field name="arch" type="xml">
<form string="">
<header>
<button type="object" name="confirm_allocation" string="Confirm" class="btn-primary" attrs="{'invisible': [('state', '!=', 'draft')]}" />
<button type="object" name="distribute_allocation" string="Distribute Vouchers" class="btn-primary" attrs="{'invisible': [('state', '!=', 'confirmed')]}" />
<button type="object" name="back_to_draft" string="Back to draft" class="btn-secundary" attrs="{'invisible': [('state', '=', 'draft')]}" />
<button type="object" name="adjust_distribution" string="Adjust distribution" class="btn-secundary" attrs="{'invisible': [('state', '!=', 'draft')]}" />
</header>
<sheet>
<h1>
<field name="name" />
</h1>
<group string="Request context">
<field name="distrib_campaign_name" />
<field name="employee_id" />
<field name="state" />
<field name="date_from" widget="date" />
<field name="date_to" widget="date" />
</group>
<group string="Luncheon vouchers calculation">
<field name="number_acquired_lv" />
<field name="number_dued_lv" />
<field name="number_distributed_lv" />
</group>
</sheet>
</form>
</field>
</record>
<record id="act_lv_allocations" model="ir.actions.act_window">
<field name="name">Luncheon vouchers allocations</field>
<field name="res_model">hr.lv.allocation</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="menu_hr_lv_allocations" action="act_lv_allocations" parent="hr.menu_hr_employee_payroll" sequence="1" name="Luncheon vouchers" />
</odoo>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_lv_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.lv</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="99" />
<field name="inherit_id" ref="hr.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//div[@name='employee_rights_setting_container']/.." position="inside">
<h2>Employee Luncheon Vouchers</h2>
<div class="row mt16 o_settings_container" name="employee_lv_container">
<div class="col-12 col-lg-6 o_setting_box" id="employee_lv_halfday_cancel" title="Luncheon Vouchers Half-day Cancel">
<div class="o_setting_left_pane">
<field name="hr_half_day_cancels_voucher" />
</div>
<div class="o_setting_right_pane">
<label for="hr_half_day_cancels_voucher" />
<div class="text-muted" name="hr_presence_options_advanced">
Voucher is acquired only if the employee worked during all his attendance.
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,29 +0,0 @@
from odoo import _, api, fields, models
class GenerateLVAllocationRequests(models.TransientModel):
_name = "generate.lv.allocation.requests"
_description = "Generate Luncheon Vouchers Allocations Requests"
distrib_campaign_name = fields.Char('Distribution campaign', required=True)
date_from = fields.Datetime(
string=_("Start Date"),
required=True
)
date_to = fields.Datetime(
string=_("End Date"),
required=True
)
def generate_lv_allocations(self):
values = {}
values["distrib_campaign_name"] = self.distrib_campaign_name
values["date_from"] = self.date_from
values["date_to"] = self.date_to
employees = self.env["hr.employee"].search(
[
("id", "in", self.env.context.get("active_ids")),
]
)
employees.generate_mass_lv_allocation(values)
# Open lv allocation tree view
return self.env["ir.actions.act_window"]._for_xml_id("hr-luncheon-voucher.act_lv_allocations")

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="lv_allocations_requests_wizard" model="ir.ui.view">
<field name="name">lv.allocations.requests.wizard</field>
<field name="model">generate.lv.allocation.requests</field>
<field name="arch" type="xml">
<form string="Create Luncheon Vouchers allocations requests">
<group name="dates" string="Period to consider">
<group>
<field name="distrib_campaign_name" />
<field name="date_from" widget="date" />
<field name="date_to" widget="date" />
</group>
</group>
<footer>
<button string="Create allocations requests" name="generate_lv_allocations" type="object" class="btn-primary" />
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="lv_allocations_requests_wizard_action" model="ir.actions.act_window">
<field name="name">Create Luncheon Vouchers allocations requests</field>
<field name="res_model">generate.lv.allocation.requests</field>
<field name="view_mode">form</field>
<field name="view_id" ref="lv_allocations_requests_wizard" />
<field name="target">new</field>
</record>
</data>
</odoo>

0
hr_usability/__init__.py Normal file
View File

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': "hr_usability Elabore",
'version': '16.0.1.0.0',
'depends': ['base','hr'],
'author': "Élabore",
'category': 'Human Resources/Employees',
'summary' : "In times off type form view, add 'create_calendar_meeting' field",
'description': """
Go to Times off app > "Setings" > "Type time off"
Select a type
The 'create_calendar_meeting' is check by default
Uncheck it if do not want to display times off in the calendar
One the checkbox is unchecked for a time off type, the next approuved times off (of that type) won't be created as a meeting and won't appear in the calendar
""",
'data': [
'views/hr_leave_type_views.xml',
],
'demo': [
],
'application': False,
'license': 'LGPL-3',
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_leave_type_form_inherit" model="ir.ui.view">
<field name="name">hr.leave.type.form.inherit</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="//field[@name='color']" position="before">
<field name="create_calendar_meeting"/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': "project timesheet holidays type",
'version': '16.0.1.0.0',
'depends': ['project_timesheet_holidays'],
'author': "Élabore",
'category': 'Human Resources/Employees',
'summary' : "add holidays type in project timesheet holidays type description",
'description': """
In project timesheet holidays, all holidays types are name 'Times off (d/d)' in description.
This module changes 'Times off' by the holiday type for better description.
""",
'data': [
],
'demo': [
],
'application': False,
'license': 'LGPL-3',
}

View File

@@ -0,0 +1 @@
from . import hr_holidays

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, _
class Holidays(models.Model):
_inherit = "hr.leave"
def _timesheet_prepare_line_values(self, index, work_hours_data, day_date, work_hours_count):
res = super()._timesheet_prepare_line_values(index, work_hours_data, day_date, work_hours_count)
res['name'] = _("%s",self.holiday_status_id.name)
return res