1 Commits

19 changed files with 83 additions and 485 deletions

View File

@@ -0,0 +1,43 @@
==========================================================
allow_negative_leave_and_allocation_hr_holidays_attendance
==========================================================
manage heritance of Duration in TimeOffCard
Installation
============
The module self-installs when ``allow_negative_leave_and_allocation`` and ``hr_holidays_attendance``.
Known issues / Roadmap
======================
None yet.
Bug Tracker
===========
Bugs are tracked on `our issues website <https://github.com/elabore-coop/allow_negative_leave_and_allocation_hr_holidays_attendance/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
------------
* `Elabore <mailto:laetitia.dacosta@elabore.coop>`
Funders
-------
The development of this module has been financially supported by:
* Elabore (https://elabore.coop)
Maintainer
----------
This module is maintained by Elabore.

View File

@@ -1,28 +1,30 @@
# Copyright 2024 Elabore () # Copyright 2025 Elabore ()
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
"name": "hr_negative_leave", "name": "allow_negative_leave_and_allocation_hr_holidays_attendance",
"version": "16.0.3.0.0", "version": "16.0.1.0.0",
"author": "Elabore", "author": "Elabore",
"website": "https://elabore.coop", "website": "https://elabore.coop",
"maintainer": "Elabore", "maintainer": "Elabore",
"license": "AGPL-3", "license": "AGPL-3",
"category": "hr", "category": "HR",
"summary": "allow negative leaves, manage negative leave balances and negative allocations", "summary": "manage heritance of Duration in TimeOffCard",
# any module necessary for this one to work correctly # any module necessary for this one to work correctly
"depends": [ "depends": [
"base","hr_holidays", "base","allow_negative_leave_and_allocation","hr_holidays_attendance",
], ],
"qweb": [], "qweb": [],
"external_dependencies": { "external_dependencies": {
"python": [], "python": [],
}, },
# always loaded # always loaded
"data": [ "data": [],
"views/hr_leave_type_views.xml", "assets": {
"views/hr_leave_views.xml", 'web.assets_backend': [
'allow_negative_leave_and_allocation_hr_holidays_attendance/static/src/xml/time_off_card.xml',
], ],
},
# only loaded in demonstration mode # only loaded in demonstration mode
"demo": [], "demo": [],
"js": [], "js": [],
@@ -30,6 +32,6 @@
"installable": True, "installable": True,
# Install this module automatically if all dependency have been previously # Install this module automatically if all dependency have been previously
# and independently installed. Used for synergetic or glue modules. # and independently installed. Used for synergetic or glue modules.
"auto_install": False, "auto_install": True,
"application": False, "application": False,
} }

View File

@@ -0,0 +1,11 @@
<template>
<t t-name="allow_negative_hr_holidays_attendance.TimeOffCard" t-inherit="hr_holidays.TimeOffCard" t-inherit-mode="extension" owl="1">
<xpath expr="//t[@t-set='duration']" position="replace">
<t t-set="duration" t-value="props.requires_allocation
? (props.data['allows_negative'] ? data.usable_remaining_leaves : data.virtual_remaining_leaves)
: data.overtime_deductible
? data.usable_remaining_leaves
: data.virtual_leaves_taken" />
</xpath>
</t>
</template>

View File

@@ -27,7 +27,7 @@ None yet.
Bug Tracker Bug Tracker
=========== ===========
Bugs are tracked on `our issues website <https://git.elabore.coop/Elabore/hr-tools/issues>`_. In case of Bugs are tracked on `our issues website <https://github.com/elabore-coop/allow_negative_leave_and_allocation/issues>`_. In case of
trouble, please check there if your issue has already been trouble, please check there if your issue has already been
reported. If you spotted it first, help us smashing it by providing a reported. If you spotted it first, help us smashing it by providing a
detailed and welcomed feedback. detailed and welcomed feedback.
@@ -39,7 +39,7 @@ Contributors
------------ ------------
* `Alusage : Nicolas JEUDY` * `Alusage : Nicolas JEUDY`
* `Elabore <mailto:contact@elabore.coop>` * `Elabore <mailto:laetitia.dacosta@elabore.coop>`
Funders Funders
------- -------

View File

@@ -1,6 +1,6 @@
{ {
"name": "hr_employee_stats_sheet", "name": "hr_employee_stats_sheet",
"version": "16.0.2.1.0", "version": "16.0.3.0.0",
"description": "Add global sheet for employee stats", "description": "Add global sheet for employee stats",
"summary": "Add global sheet for employee stats", "summary": "Add global sheet for employee stats",
"author": "Nicolas JEUDY", "author": "Nicolas JEUDY",
@@ -8,13 +8,14 @@
"license": "LGPL-3", "license": "LGPL-3",
"category": "Human Resources", "category": "Human Resources",
"depends": [ "depends": [
"hr_negative_leave", "allow_negative_leave_and_allocation",
"base", "base",
"hr", "hr",
"hr_holidays", "hr_holidays",
"hr_timesheet", "hr_timesheet",
"hr_timesheet_sheet", "hr_timesheet_sheet",
"resource", "resource",
"hr_employee_calendar_planning",
], ],
"data": [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",

View File

@@ -100,38 +100,29 @@ class HrTimesheetSheet(models.Model):
sheet.recovery_allocation_ids.write({"state": "refuse"}) sheet.recovery_allocation_ids.write({"state": "refuse"})
return res return res
def _get_contracts_in_progress_during_timesheet_sheet_time_period(self): def _get_calendar_in_progress_during_timesheet_time_period(self):
""" """
get the contracts which was in progress during the timesheet sheet range time get the ressource calendar which was used during the timesheet sheet time period
""" """
contracts = self.env["hr.contract"].search( #find calendar(s) running over the duration of the timesheet
calendars = self.env["hr.employee.calendar"].search(
[ [
("employee_id", "=", self.employee_id.id), ("employee_id", "=", self.employee_id.id),
("state", "in", ("open", "close")),
("date_start", "<=", self.date_end), ("date_start", "<=", self.date_end),
"|", "|",
("date_end", "=", False), # pas de date de fin OU ("date_end", "=", False), # pas de date de fin OU
("date_end", ">=", self.date_start), # date de fin après le début ("date_end", ">=", self.date_start), # date de fin après le début
], ],
) )
return contracts if len(calendars) > 1:
def _get_calendar_in_progress_during_timesheet_time_period(self):
"""
get the ressource calendar which was used during the timesheet sheet time period
"""
#checks if only one contract runs over the duration of the timesheet
contracts = self._get_contracts_in_progress_during_timesheet_sheet_time_period()
if len(contracts) > 1:
# check if a new contract start during timesheet sheet time period. If yes, raise an error
raise UserError( raise UserError(
_("There is a contract starting during the timesheet sheet time period for the employee %s" _("There is a calendar starting during the timesheet sheet time period for the employee %s"
"Please create a new timesheet sheet starting from the new contract start date") "Please create a new timesheet sheet starting from the new calendar start date")
% self.employee_id.display_name % self.employee_id.display_name
) )
# get the ressource calendar id according to the work contract # get the ressource calendar id according to the work contract
elif self.employee_id.resource_calendar_id: elif calendars and calendars[0].calendar_id:
return self.employee_id.resource_calendar_id return calendars[0].calendar_id
#get the ressource calendar linked to the employee #get the ressource calendar linked to the employee
elif self.env.company.resource_calendar_id: elif self.env.company.resource_calendar_id:
return self.env.company.resource_calendar_id return self.env.company.resource_calendar_id

View File

@@ -1,44 +0,0 @@
===================================
allow_negative_leave_and_allocation
===================================
allow negative leaves, manage negative leave balances and negative allocations
Installation
============
Use Odoo normal module installation procedure to install
``allow_negative_leave_and_allocation``.
Known issues / Roadmap
======================
None yet.
Bug Tracker
===========
Bugs are tracked on `our issues website <https://git.elabore.coop/Elabore/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
------------
* `Elabore <mailto:contact@elabore.coop>`
Funders
-------
The development of this module has been financially supported by:
* Elabore (https://elabore.coop)
Maintainer
----------
This module is maintained by Elabore.

View File

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

View File

@@ -1,54 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_negative_leave
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-31 08:25+0000\n"
"PO-Revision-Date: 2025-10-31 08:25+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__allows_negative
msgid "Allow Negative Leaves"
msgstr "Autoriser les demandes et les soldes de congés négatifs"
#. module: hr_negative_leave
#: model_terms:ir.ui.view,arch_db:hr_negative_leave.hr_leave_type_negative_leave
msgid "Allow negative"
msgstr "Autoriser les soldes négatifs"
#. module: hr_negative_leave
#: model:ir.model.fields,help:hr_negative_leave.field_hr_leave_type__allows_negative
msgid ""
"If checked, users request can exceed the allocated days and balance can go "
"in negative."
msgstr ""
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__remaining_leaves_allowing_negative
msgid "Remaining Leaves when Negative Allowed"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave__smart_search
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__smart_search
msgid "Smart Search"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model,name:hr_negative_leave.model_hr_leave
msgid "Time Off"
msgstr "Congés"
#. module: hr_negative_leave
#: model:ir.model,name:hr_negative_leave.model_hr_leave_type
msgid "Time Off Type"
msgstr "Type de congés"

View File

@@ -1,54 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_negative_leave
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-31 08:23+0000\n"
"PO-Revision-Date: 2025-10-31 08:23+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__allows_negative
msgid "Allow Negative Leaves"
msgstr ""
#. module: hr_negative_leave
#: model_terms:ir.ui.view,arch_db:hr_negative_leave.hr_leave_type_negative_leave
msgid "Allow negative"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model.fields,help:hr_negative_leave.field_hr_leave_type__allows_negative
msgid ""
"If checked, users request can exceed the allocated days and balance can go "
"in negative."
msgstr ""
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__remaining_leaves_allowing_negative
msgid "Remaining Leaves when Negative Allowed"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave__smart_search
#: model:ir.model.fields,field_description:hr_negative_leave.field_hr_leave_type__smart_search
msgid "Smart Search"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model,name:hr_negative_leave.model_hr_leave
msgid "Time Off"
msgstr ""
#. module: hr_negative_leave
#: model:ir.model,name:hr_negative_leave.model_hr_leave_type
msgid "Time Off Type"
msgstr ""

View File

@@ -1 +0,0 @@
from . import hr_leave_type, hr_leave

View File

@@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Copyright (c) 2005-2006 Axelor SARL. (http://www.axelor.com)
from odoo import api, models
class HrLeave(models.Model):
_inherit = "hr.leave"
@api.constrains('state', 'number_of_days', 'holiday_status_id')
def _check_holidays(self):
# Keep only leaves that do not allow negative balances
to_check = self.filtered(lambda h: not h.holiday_status_id.allows_negative)
if to_check:
super(HrLeave, to_check)._check_holidays()

View File

@@ -1,241 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from collections import defaultdict
from datetime import time, timedelta
from odoo import api, fields, models
from odoo.tools.translate import _
from odoo.addons.resource.models.resource import Intervals
class HolidaysType(models.Model):
_inherit = "hr.leave.type"
# negative time off
allows_negative = fields.Boolean(string='Allow Negative Leaves',
help="If checked, users request can exceed the allocated days and balance can go in negative.")
remaining_leaves_allowing_negative = fields.Float(
string="Remaining Leaves when Negative Allowed",
compute='_compute_remaining_leaves_allowing_negative',
)
def _compute_remaining_leaves_allowing_negative(self):
for holiday_type in self:
if holiday_type.allows_negative:
# if left != usable : remaining_leaves_allowing_negative = left + usable
if holiday_type.virtual_remaining_leaves < 0 (holiday_type.max_leaves - holiday_type.virtual_leaves_taken) != holiday_type.virtual_remaining_leaves:
holiday_type.remaining_leaves_allowing_negative = holiday_type.max_leaves - holiday_type.virtual_leaves_taken + holiday_type.virtual_remaining_leaves
else:
# else : remaining_leaves_allowing_negative = left as usual
holiday_type.remaining_leaves_allowing_negative = holiday_type.max_leaves - holiday_type.virtual_leaves_taken
else:
holiday_type.remaining_leaves_allowing_negative = None
@api.depends('requires_allocation')
def _compute_valid(self):
res = super()._compute_valid()
for holiday_type in res:
if not holiday_type.has_valid_allocation:
holiday_type.has_valid_allocation = holiday_type.allows_negative
#overwrite _get_employees_days_per_allocation() from hr_holidays module
def _get_employees_days_per_allocation(self, employee_ids, date=None):
if not date:
date = fields.Date.to_date(self.env.context.get('default_date_from')) or fields.Date.context_today(self)
leaves_domain = [
('employee_id', 'in', employee_ids),
('state', 'in', ['confirm', 'validate1', 'validate']),
('holiday_status_id', 'in', self.ids)
]
if self.env.context.get("ignore_future"):
leaves_domain.append(('date_from', '<=', date))
leaves = self.env['hr.leave'].search(leaves_domain)
allocations = self.env['hr.leave.allocation'].with_context(active_test=False).search([
('employee_id', 'in', employee_ids),
('state', 'in', ['validate']),
('holiday_status_id', 'in', self.ids),
])
# The allocation_employees dictionary groups the allocations based on the employee and the holiday type
# The structure is the following:
# - KEYS:
# allocation_employees
# |--employee_id
# |--holiday_status_id
# - VALUES:
# Intervals with the start and end date of each allocation and associated allocations within this interval
allocation_employees = defaultdict(lambda: defaultdict(list))
### Creation of the allocation intervals ###
for holiday_status_id in allocations.holiday_status_id:
for employee_id in employee_ids:
allocation_intervals = Intervals([(
fields.datetime.combine(allocation.date_from, time.min),
fields.datetime.combine(allocation.date_to or datetime.date.max, time.max),
allocation)
for allocation in allocations.filtered(lambda allocation: allocation.employee_id.id == employee_id and allocation.holiday_status_id == holiday_status_id)])
allocation_employees[employee_id][holiday_status_id] = allocation_intervals
# The leave_employees dictionary groups the leavess based on the employee and the holiday type
# The structure is the following:
# - KEYS:
# leave_employees
# |--employee_id
# |--holiday_status_id
# - VALUES:
# Intervals with the start and end date of each leave and associated leave within this interval
leaves_employees = defaultdict(lambda: defaultdict(list))
leave_intervals = []
### Creation of the leave intervals ###
if leaves:
for holiday_status_id in leaves.holiday_status_id:
for employee_id in employee_ids:
leave_intervals = Intervals([(
fields.datetime.combine(leave.date_from, time.min),
fields.datetime.combine(leave.date_to, time.max),
leave)
for leave in leaves.filtered(lambda leave: leave.employee_id.id == employee_id and leave.holiday_status_id == holiday_status_id)])
leaves_employees[employee_id][holiday_status_id] = leave_intervals
# allocation_days_consumed is a dictionary to map the number of days/hours of leaves taken per allocation
# The structure is the following:
# - KEYS:
# allocation_days_consumed
# |--employee_id
# |--holiday_status_id
# |--allocation
# |--virtual_leaves_taken
# |--leaves_taken
# |--virtual_remaining_leaves
# |--remaining_leaves
# |--max_leaves
# |--closest_allocation_to_expire
# - VALUES:
# Integer representing the number of (virtual) remaining leaves, (virtual) leaves taken or max leaves for each allocation.
# The unit is in hour or days depending on the leave type request unit
allocations_days_consumed = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: 0))))
company_domain = [('company_id', 'in', list(set(self.env.company.ids + self.env.context.get('allowed_company_ids', []))))]
### Existing leaves assigned to allocations ###
if leaves_employees:
for employee_id, leaves_interval_by_status in leaves_employees.items():
for holiday_status_id in leaves_interval_by_status:
days_consumed = allocations_days_consumed[employee_id][holiday_status_id]
if allocation_employees[employee_id][holiday_status_id]:
allocations = allocation_employees[employee_id][holiday_status_id] & leaves_interval_by_status[holiday_status_id]
available_allocations = self.env['hr.leave.allocation']
for allocation_interval in allocations._items:
available_allocations |= allocation_interval[2]
# Consume the allocations that are close to expiration first
sorted_available_allocations = available_allocations.filtered('date_to').sorted(key='date_to')
sorted_available_allocations += available_allocations.filtered(lambda allocation: not allocation.date_to)
leave_intervals = leaves_interval_by_status[holiday_status_id]._items
sorted_allocations_with_remaining_leaves = self.env['hr.leave.allocation']
for leave_interval in leave_intervals:
leaves = leave_interval[2]
for leave in leaves:
if leave.leave_type_request_unit in ['day', 'half_day']:
leave_duration = leave.number_of_days
leave_unit = 'days'
else:
leave_duration = leave.number_of_hours_display
leave_unit = 'hours'
if holiday_status_id.requires_allocation != 'no':
for available_allocation in sorted_available_allocations:
# if the allocation is not valid for the leave period, continue
if (available_allocation.date_to and available_allocation.date_to < leave.date_from.date()) \
or (available_allocation.date_from > leave.date_to.date()):
continue
# calculate the number of days/hours for this allocation (allocation days/hours - leaves already taken)
virtual_remaining_leaves = (available_allocation.number_of_days if leave_unit == 'days' else available_allocation.number_of_hours_display) - allocations_days_consumed[employee_id][holiday_status_id][available_allocation]['virtual_leaves_taken']
###########################################
# Modification for leaves allowing negative #
###########################################
# if negative is allowed for this leave type, we can exceed the number of available days in this allocation
if holiday_status_id.allows_negative:
max_leaves = leave_duration
else:
# if negative is not allowed for this leave type, then we cannot exceed the allocation amount
# the max leaves for this allocation is the minimum between the remaining available days and the leave duration
max_leaves = min(virtual_remaining_leaves, leave_duration)
# the new calculation of days taken for this allocation is previous taken + max_leaves (which can never exceed the allocation total)
days_consumed[available_allocation]['virtual_leaves_taken'] += max_leaves
if leave.state == 'validate':
days_consumed[available_allocation]['leaves_taken'] += max_leaves
leave_duration -= max_leaves
# Check valid allocations with still availabe leaves on it
if days_consumed[available_allocation]['virtual_remaining_leaves'] > 0 and available_allocation.date_to and available_allocation.date_to > date:
sorted_allocations_with_remaining_leaves |= available_allocation
if leave_duration > 0:
# There are not enough allocation for the number of leaves
days_consumed[False]['virtual_remaining_leaves'] -= leave_duration
else:
days_consumed[False]['virtual_leaves_taken'] += leave_duration
if leave.state == 'validate':
days_consumed[False]['leaves_taken'] += leave_duration
# no need to sort the allocations again
allocations_days_consumed[employee_id][holiday_status_id][False]['closest_allocation_to_expire'] = sorted_allocations_with_remaining_leaves[0] if sorted_allocations_with_remaining_leaves else False
# Future available leaves
future_allocations_date_from = fields.datetime.combine(date, time.min)
future_allocations_date_to = fields.datetime.combine(date, time.max) + timedelta(days=5*365)
for employee_id, allocation_intervals_by_status in allocation_employees.items():
employee = self.env['hr.employee'].browse(employee_id)
for holiday_status_id, intervals in allocation_intervals_by_status.items():
if not intervals:
continue
future_allocation_intervals = intervals & Intervals([(
future_allocations_date_from,
future_allocations_date_to,
self.env['hr.leave'])])
search_date = date
closest_allocations = self.env['hr.leave.allocation']
for interval in intervals._items:
closest_allocations |= interval[2]
allocations_with_remaining_leaves = self.env['hr.leave.allocation']
for interval_from, interval_to, interval_allocations in future_allocation_intervals._items:
if interval_from.date() > search_date:
continue
interval_allocations = interval_allocations.filtered('active')
if not interval_allocations:
continue
# If no end date to the allocation, consider the number of days remaining as infinite
employee_quantity_available = (
employee._get_work_days_data_batch(interval_from, interval_to, compute_leaves=False, domain=company_domain)[employee_id]
if interval_to != future_allocations_date_to
else {'days': float('inf'), 'hours': float('inf')}
)
reached_remaining_days_limit = False
for allocation in interval_allocations:
if allocation.date_from > search_date:
continue
days_consumed = allocations_days_consumed[employee_id][holiday_status_id][allocation]
if allocation.type_request_unit in ['day', 'half_day']:
quantity_available = employee_quantity_available['days']
remaining_days_allocation = (allocation.number_of_days - days_consumed['virtual_leaves_taken'])
else:
quantity_available = employee_quantity_available['hours']
remaining_days_allocation = (allocation.number_of_hours_display - days_consumed['virtual_leaves_taken'])
#TODO leave allocation allowing negative not yet handled here
if quantity_available <= remaining_days_allocation:
search_date = interval_to.date() + timedelta(days=1)
days_consumed['max_leaves'] = allocation.number_of_days if allocation.type_request_unit in ['day', 'half_day'] else allocation.number_of_hours_display
if not reached_remaining_days_limit:
days_consumed['virtual_remaining_leaves'] += min(quantity_available, remaining_days_allocation)
days_consumed['remaining_leaves'] = days_consumed['max_leaves'] - days_consumed['leaves_taken']
if remaining_days_allocation >= quantity_available:
reached_remaining_days_limit = True
# Check valid allocations with still availabe leaves on it
if days_consumed['virtual_remaining_leaves'] > 0 and allocation.date_to and allocation.date_to > date:
allocations_with_remaining_leaves |= allocation
allocations_sorted = sorted(allocations_with_remaining_leaves, key=lambda a: a.date_to)
allocations_days_consumed[employee_id][holiday_status_id][False]['closest_allocation_to_expire'] = allocations_sorted[0] if allocations_sorted else False
return allocations_days_consumed

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_leave_type_negative_leave" model="ir.ui.view">
<field name="name">hr.leave.type.negative.leave</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="//group[@name='allocation_validation']" position="after">
<group name="negative_leave" id="negative_leave" colspan="4"
string="Allow negative"
attrs="{'invisible':[('requires_allocation', '=', 'no')]}"
>
<field name="allows_negative" />
</group>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,22 +0,0 @@
<odoo>
<record id="hr_leave_view_negative_leave" model="ir.ui.view">
<field name="name">hr.leave.view.negative.leave</field>
<field name="model">hr.leave</field>
<field name="inherit_id" ref="hr_holidays.hr_leave_view_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='holiday_status_id']" position="attributes">
<attribute name="domain">[
'|',
('requires_allocation', '=', 'no'),
'&amp;',
('has_valid_allocation', '=', True),
'|',
('allows_negative', '=', True),
'&amp;',
('virtual_remaining_leaves', '&gt;', 0),
('allows_negative', '=', False),
]</attribute>
</xpath>
</field>
</record>
</odoo>

View File

@@ -29,7 +29,7 @@ None yet.
Bug Tracker Bug Tracker
=========== ===========
Bugs are tracked on `our issues website <https://git.elabore.coop/Elabore/hr-tools/issues>`_. In case of Bugs are tracked on `our issues website <https://github.com/elabore-coop/allow_negative_leave_and_allocation/issues>`_. In case of
trouble, please check there if your issue has already been trouble, please check there if your issue has already been
reported. If you spotted it first, help us smashing it by providing a reported. If you spotted it first, help us smashing it by providing a
detailed and welcomed feedback. detailed and welcomed feedback.