[MIG] resource: Migrated to new api.

This commit is contained in:
Mansi Gandhi
2016-07-13 12:53:34 +02:00
committed by Yannick Tivisse
parent 22ef7c15b5
commit a4e57ea16c
5 changed files with 201 additions and 216 deletions
+3 -6
View File
@@ -2,10 +2,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name' : 'Resource',
'version' : '1.1',
'category' : 'Hidden',
'website' : 'http://www.openerp.com',
'name': 'Resource',
'version': '1.1',
'category': 'Hidden',
'description': """
Module for resource management.
===============================
@@ -25,6 +24,4 @@ associated to every resource. It also manages the leaves of every resource.
'test/resource.yml',
'test/duplicate_resource.yml',
],
'installable': True,
'auto_install': False,
}
+2 -4
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<!-- Example employee -->
@@ -121,5 +120,4 @@
<field name="date_to" eval="time.strftime('%Y-%m-%d 11:00:00')"/>
</record>
</data>
</openerp>
</odoo>
+191 -199
View File
@@ -2,21 +2,19 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
import functools
import pytz
from datetime import timedelta
from dateutil import rrule
from dateutil.relativedelta import relativedelta
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
from operator import itemgetter
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.float_utils import float_compare
from openerp.tools.translate import _
from openerp.exceptions import UserError
import pytz
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare
class resource_calendar(osv.osv):
class ResourceCalendar(models.Model):
""" Calendar model for a resource. It has
- attendance_ids: list of resource.calendar.attendance that are a working
@@ -30,19 +28,15 @@ class resource_calendar(osv.osv):
_name = "resource.calendar"
_description = "Resource Calendar"
_columns = {
'name': fields.char("Name", required=True),
'company_id': fields.many2one('res.company', 'Company', required=False),
'attendance_ids': fields.one2many('resource.calendar.attendance', 'calendar_id', 'Working Time', copy=True),
'manager': fields.many2one('res.users', 'Workgroup Manager'),
'leave_ids': fields.one2many(
'resource.calendar.leaves', 'calendar_id', 'Leaves',
help=''
),
}
_defaults = {
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.calendar', context=context)
}
name = fields.Char(required=True)
company_id = fields.Many2one('res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get())
attendance_ids = fields.One2many(
'resource.calendar.attendance', 'calendar_id', string='Working Time',
copy=True)
manager = fields.Many2one('res.users', string='Workgroup Manager')
leave_ids = fields.One2many(
'resource.calendar.leaves', 'calendar_id', string='Leaves')
# --------------------------------------------------
# Utility methods
@@ -72,7 +66,8 @@ class resource_calendar(osv.osv):
cleaned.append(tuple(working_interval))
return cleaned
def interval_remove_leaves(self, cr, uid, interval, leave_intervals, context=None):
@api.model
def interval_remove_leaves(self, interval, leave_intervals):
""" Utility method that remove leave intervals from a base interval:
- clean the leave intervals, to have an ordered list of not-overlapping
@@ -112,7 +107,6 @@ class resource_calendar(osv.osv):
current_interval[1] = leave[0]
intervals.append((current_interval[0], current_interval[1]))
current_interval = [leave[1], interval[1]]
# if current_interval[0] <= leave[1] <= current_interval[1]:
if current_interval[0] <= leave[1]:
current_interval[0] = leave[1]
if current_interval and current_interval[0] < interval[1]: # remove intervals moved outside base interval due to leaves
@@ -139,14 +133,14 @@ class resource_calendar(osv.osv):
is greater than the possible scheduling in the intervals, no extra-scheduling
is done, and results == intervals. """
results = []
res = datetime.timedelta()
limit = datetime.timedelta(hours=hour)
res = timedelta()
limit = timedelta(hours=hour)
for interval in intervals:
res += interval[1] - interval[0]
if res > limit and remove_at_end:
interval = (interval[0], interval[1] + relativedelta(seconds=seconds(limit-res)))
interval = (interval[0], interval[1] + relativedelta(seconds=seconds(limit - res)))
elif res > limit:
interval = (interval[0] + relativedelta(seconds=seconds(res-limit)), interval[1])
interval = (interval[0] + relativedelta(seconds=seconds(res - limit)), interval[1])
results.append(interval)
if res > limit:
break
@@ -156,41 +150,40 @@ class resource_calendar(osv.osv):
# Date and hours computation
# --------------------------------------------------
def get_attendances_for_weekday(self, cr, uid, id, date, context=None):
@api.multi
def get_attendances_for_weekday(self, date):
""" Given a list of weekdays, return matching resource.calendar.attendance"""
calendar = self.browse(cr, uid, id, context=None)
self.ensure_one()
weekday = date.weekday()
date = date.strftime(DEFAULT_SERVER_DATE_FORMAT)
res = []
for att in calendar.attendance_ids:
if int(att.dayofweek) == weekday:
if not ((att.date_from and date < att.date_from) or (att.date_to and date > att.date_to)):
res.append(att)
return res
date = fields.Date.today()
attendances = self.env['resource.calendar.attendance']
for attendance in self.attendance_ids.filtered(lambda att: int(att.dayofweek) == weekday and
not ((att.date_from and date < att.date_from) or (att.date_to and date > att.date_to))):
attendances |= attendance
return attendances
def get_weekdays(self, cr, uid, id, default_weekdays=None, context=None):
@api.multi
def get_weekdays(self, default_weekdays=None):
""" Return the list of weekdays that contain at least one working interval.
If no id is given (no calendar), return default weekdays. """
if id is None:
if not self:
return default_weekdays if default_weekdays is not None else [0, 1, 2, 3, 4]
calendar = self.browse(cr, uid, id, context=None)
weekdays = set()
for attendance in calendar.attendance_ids:
weekdays.add(int(attendance.dayofweek))
self.ensure_one()
weekdays = set(map(int, (self.attendance_ids.mapped('dayofweek'))))
return list(weekdays)
def get_next_day(self, cr, uid, id, day_date, context=None):
@api.multi
def get_next_day(self, day_date):
""" Get following date of day_date, based on resource.calendar. If no
calendar is provided, just return the next day.
:param int id: id of a resource.calendar. If not given, simply add one day
to the submitted date.
:param date day_date: current day as a date
:return date: next day of calendar, or just next day """
if not id:
if not self:
return day_date + relativedelta(days=1)
weekdays = self.get_weekdays(cr, uid, id, context)
self.ensure_one()
weekdays = self.get_weekdays()
base_index = -1
for weekday in weekdays:
@@ -205,18 +198,18 @@ class resource_calendar(osv.osv):
return day_date + relativedelta(days=days)
def get_previous_day(self, cr, uid, id, day_date, context=None):
@api.multi
def get_previous_day(self, day_date):
""" Get previous date of day_date, based on resource.calendar. If no
calendar is provided, just return the previous day.
:param int id: id of a resource.calendar. If not given, simply remove
one day from the submitted date.
:param date day_date: current day as a date
:return date: previous day of calendar, or just previous day """
if not id:
if not self:
return day_date + relativedelta(days=-1)
weekdays = self.get_weekdays(cr, uid, id, context)
self.ensure_one()
weekdays = self.get_weekdays()
weekdays.reverse()
base_index = -1
@@ -232,9 +225,9 @@ class resource_calendar(osv.osv):
return day_date + relativedelta(days=days)
def get_leave_intervals(self, cr, uid, id, resource_id=None,
start_datetime=None, end_datetime=None,
context=None):
@api.multi
def get_leave_intervals(self, resource_id=None,
start_datetime=None, end_datetime=None):
"""Get the leaves of the calendar. Leaves can be filtered on the resource,
the start datetime or the end datetime.
@@ -250,27 +243,27 @@ class resource_calendar(osv.osv):
:return list leaves: list of tuples (start_datetime, end_datetime) of
leave intervals
"""
resource_calendar = self.browse(cr, uid, id, context=context)
self.ensure_one()
leaves = []
for leave in resource_calendar.leave_ids:
for leave in self.leave_ids:
if leave.resource_id and not resource_id == leave.resource_id.id:
continue
date_from = datetime.datetime.strptime(leave.date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT)
date_from = fields.Datetime.from_string(leave.date_from)
if end_datetime and date_from > end_datetime:
continue
date_to = datetime.datetime.strptime(leave.date_to, tools.DEFAULT_SERVER_DATETIME_FORMAT)
date_to = fields.Datetime.from_string(leave.date_to)
if start_datetime and date_to < start_datetime:
continue
leaves.append((date_from, date_to))
return leaves
def get_working_intervals_of_day(self, cr, uid, id, start_dt=None, end_dt=None,
@api.multi
def get_working_intervals_of_day(self, start_dt=None, end_dt=None,
leaves=None, compute_leaves=False, resource_id=None,
default_interval=None, context=None):
default_interval=None):
""" Get the working intervals of the day based on calendar. This method
handle leaves that come directly from the leaves parameter or can be computed.
:param int id: resource.calendar id; take the first one if is a list
:param datetime start_dt: datetime object that is the beginning hours
for the working intervals computation; any
working interval beginning before start_dt
@@ -300,8 +293,6 @@ class resource_calendar(osv.osv):
:return list intervals: a list of tuples (start_datetime, end_datetime)
of work intervals """
if isinstance(id, (list, tuple)):
id = id[0]
# Computes start_dt, end_dt (with default values if not set) + off-interval work limits
work_limits = []
@@ -321,17 +312,17 @@ class resource_calendar(osv.osv):
work_dt = start_dt.replace(hour=0, minute=0, second=0)
# no calendar: try to use the default_interval, then return directly
if id is None:
if not self:
working_interval = []
if default_interval:
working_interval = (start_dt.replace(hour=default_interval[0], minute=0, second=0),
start_dt.replace(hour=default_interval[1], minute=0, second=0))
intervals = self.interval_remove_leaves(cr, uid, working_interval, work_limits, context=context)
intervals = self.interval_remove_leaves(working_interval, work_limits)
return intervals
working_intervals = []
tz_info = fields.datetime.context_timestamp(cr, uid, work_dt, context=context).tzinfo
for calendar_working_day in self.get_attendances_for_weekday(cr, uid, id, start_dt, context=context):
tz_info = fields.Datetime.context_timestamp(self, work_dt).tzinfo
for calendar_working_day in self.get_attendances_for_weekday(start_dt):
dt_f = work_dt.replace(hour=0, minute=0, second=0) + timedelta(seconds=(calendar_working_day.hour_from * 3600))
dt_t = work_dt.replace(hour=0, minute=0, second=0) + timedelta(seconds=(calendar_working_day.hour_to * 3600))
@@ -341,41 +332,42 @@ class resource_calendar(osv.osv):
dt_t.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None),
calendar_working_day.id
)
working_intervals += self.interval_remove_leaves(cr, uid, working_interval, work_limits, context=context)
working_intervals += self.interval_remove_leaves(working_interval, work_limits)
# find leave intervals
if leaves is None and compute_leaves:
leaves = self.get_leave_intervals(cr, uid, id, resource_id=resource_id, context=context)
leaves = self.get_leave_intervals(resource_id=resource_id)
# filter according to leaves
for interval in working_intervals:
work_intervals = self.interval_remove_leaves(cr, uid, interval, leaves, context=context)
work_intervals = self.interval_remove_leaves(interval, leaves)
intervals += work_intervals
return intervals
def get_working_hours_of_date(self, cr, uid, id, start_dt=None, end_dt=None,
@api.multi
def get_working_hours_of_date(self, start_dt=None, end_dt=None,
leaves=None, compute_leaves=False, resource_id=None,
default_interval=None, context=None):
default_interval=None):
""" Get the working hours of the day based on calendar. This method uses
get_working_intervals_of_day to have the work intervals of the day. It
then calculates the number of hours contained in those intervals. """
res = datetime.timedelta()
res = timedelta()
intervals = self.get_working_intervals_of_day(
cr, uid, id,
start_dt, end_dt, leaves,
compute_leaves, resource_id,
default_interval, context)
default_interval)
for interval in intervals:
res += interval[1] - interval[0]
return seconds(res) / 3600.0
def get_working_hours(self, cr, uid, id, start_dt, end_dt, compute_leaves=False,
resource_id=None, default_interval=None, context=None):
@api.multi
def get_working_hours(self, start_dt, end_dt, compute_leaves=False,
resource_id=None, default_interval=None):
hours = 0.0
for day in rrule.rrule(rrule.DAILY, dtstart=start_dt,
until=(end_dt + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0),
byweekday=self.get_weekdays(cr, uid, id, context=context)):
until=(end_dt + timedelta(days=1)).replace(hour=0, minute=0, second=0),
byweekday=self.get_weekdays()):
day_start_dt = day.replace(hour=0, minute=0, second=0)
if start_dt and day.date() == start_dt.date():
day_start_dt = start_dt
@@ -383,20 +375,19 @@ class resource_calendar(osv.osv):
if end_dt and day.date() == end_dt.date():
day_end_dt = end_dt
hours += self.get_working_hours_of_date(
cr, uid, id, start_dt=day_start_dt, end_dt=day_end_dt,
start_dt=day_start_dt, end_dt=day_end_dt,
compute_leaves=compute_leaves, resource_id=resource_id,
default_interval=default_interval,
context=context)
default_interval=default_interval)
return hours
# --------------------------------------------------
# Hours scheduling
# --------------------------------------------------
def _schedule_hours(self, cr, uid, id, hours, day_dt=None,
@api.multi
def _schedule_hours(self, hours, day_dt=None,
compute_leaves=False, resource_id=None,
default_interval=None, context=None):
default_interval=None):
""" Schedule hours of work, using a calendar and an optional resource to
compute working and leave days. This method can be used backwards, i.e.
scheduling days before a deadline.
@@ -436,7 +427,7 @@ class resource_calendar(osv.osv):
iterations = 0
current_datetime = day_dt
call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id, default_interval=default_interval, context=context)
call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id, default_interval=default_interval)
while float_compare(remaining_hours, 0.0, precision_digits=2) in (1, 0) and iterations < 1000:
if backwards:
@@ -444,9 +435,9 @@ class resource_calendar(osv.osv):
else:
call_args['start_dt'] = current_datetime
working_intervals = self.get_working_intervals_of_day(cr, uid, id, **call_args)
working_intervals = self.get_working_intervals_of_day(**call_args)
if id is None and not working_intervals: # no calendar -> consider working 8 hours
if not self and not working_intervals: # no calendar -> consider working 8 hours
remaining_hours -= 8.0
elif working_intervals:
if backwards:
@@ -455,7 +446,7 @@ class resource_calendar(osv.osv):
if backwards:
new_working_intervals.reverse()
res = datetime.timedelta()
res = timedelta()
for interval in working_intervals:
res += interval[1] - interval[0]
remaining_hours -= (seconds(res) / 3600.0)
@@ -465,36 +456,38 @@ class resource_calendar(osv.osv):
intervals = intervals + new_working_intervals
# get next day
if backwards:
current_datetime = datetime.datetime.combine(self.get_previous_day(cr, uid, id, current_datetime, context), datetime.time(23, 59, 59))
current_datetime = datetime.datetime.combine(self.get_previous_day(current_datetime), datetime.time(23, 59, 59))
else:
current_datetime = datetime.datetime.combine(self.get_next_day(cr, uid, id, current_datetime, context), datetime.time())
current_datetime = datetime.datetime.combine(self.get_next_day(current_datetime), datetime.time())
# avoid infinite loops
iterations += 1
return intervals
def schedule_hours_get_date(self, cr, uid, id, hours, day_dt=None,
@api.multi
def schedule_hours_get_date(self, hours, day_dt=None,
compute_leaves=False, resource_id=None,
default_interval=None, context=None):
default_interval=None):
""" Wrapper on _schedule_hours: return the beginning/ending datetime of
an hours scheduling. """
res = self._schedule_hours(cr, uid, id, hours, day_dt, compute_leaves, resource_id, default_interval, context)
res = self._schedule_hours(hours, day_dt, compute_leaves, resource_id, default_interval)
return res and res[0][0] or False
def schedule_hours(self, cr, uid, id, hours, day_dt=None,
@api.multi
def schedule_hours(self, hours, day_dt=None,
compute_leaves=False, resource_id=None,
default_interval=None, context=None):
default_interval=None):
""" Wrapper on _schedule_hours: return the working intervals of an hours
scheduling. """
return self._schedule_hours(cr, uid, id, hours, day_dt, compute_leaves, resource_id, default_interval, context)
return self._schedule_hours(hours, day_dt, compute_leaves, resource_id, default_interval)
# --------------------------------------------------
# Days scheduling
# --------------------------------------------------
def _schedule_days(self, cr, uid, id, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None, context=None):
@api.multi
def _schedule_days(self, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None):
"""Schedule days of work, using a calendar and an optional resource to
compute working and leave days. This method can be used backwards, i.e.
scheduling days before a deadline.
@@ -536,157 +529,165 @@ class resource_calendar(osv.osv):
while planned_days < days and iterations < 100:
working_intervals = self.get_working_intervals_of_day(
cr, uid, id, current_datetime,
current_datetime,
compute_leaves=compute_leaves, resource_id=resource_id,
default_interval=default_interval,
context=context)
if id is None or working_intervals: # no calendar -> no working hours, but day is considered as worked
default_interval=default_interval)
if not self or working_intervals: # no calendar -> no working hours, but day is considered as worked
planned_days += 1
intervals += working_intervals
# get next day
if backwards:
current_datetime = self.get_previous_day(cr, uid, id, current_datetime, context)
current_datetime = self.get_previous_day(current_datetime)
else:
current_datetime = self.get_next_day(cr, uid, id, current_datetime, context)
current_datetime = self.get_next_day(current_datetime)
# avoid infinite loops
iterations += 1
return intervals
def schedule_days_get_date(self, cr, uid, id, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None, context=None):
@api.multi
def schedule_days_get_date(self, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None):
""" Wrapper on _schedule_days: return the beginning/ending datetime of
a days scheduling. """
res = self._schedule_days(cr, uid, id, days, day_date, compute_leaves, resource_id, default_interval, context)
res = self._schedule_days(days, day_date, compute_leaves, resource_id, default_interval)
return res and res[-1][1] or False
def schedule_days(self, cr, uid, id, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None, context=None):
@api.multi
def schedule_days(self, days, day_date=None, compute_leaves=False,
resource_id=None, default_interval=None):
""" Wrapper on _schedule_days: return the working intervals of a days
scheduling. """
return self._schedule_days(cr, uid, id, days, day_date, compute_leaves, resource_id, default_interval, context)
return self._schedule_days(days, day_date, compute_leaves, resource_id, default_interval)
# --------------------------------------------------
# Compatibility / to clean / to remove
# --------------------------------------------------
def working_hours_on_day(self, cr, uid, resource_calendar_id, day, context=None):
@api.multi
def working_hours_on_day(self, day):
""" Used in hr_payroll/hr_payroll.py
:deprecated: OpenERP saas-3. Use get_working_hours_of_date instead. Note:
:deprecated: Odoo saas-3. Use get_working_hours_of_date instead. Note:
since saas-3, take hour/minutes into account, not just the whole day."""
if isinstance(day, datetime.datetime):
day = day.replace(hour=0, minute=0)
return self.get_working_hours_of_date(cr, uid, resource_calendar_id.id, start_dt=day, context=None)
return self.get_working_hours_of_date(start_dt=day)
def interval_min_get(self, cr, uid, id, dt_from, hours, resource=False):
@api.multi
def interval_min_get(self, dt_from, hours, resource=False):
""" Schedule hours backwards. Used in mrp_operations/mrp_operations.py.
:deprecated: OpenERP saas-3. Use schedule_hours instead. Note: since
:deprecated: Odoo saas-3. Use schedule_hours instead. Note: since
saas-3, counts leave hours instead of all-day leaves."""
return self.schedule_hours(
cr, uid, id, hours * -1.0,
hours * -1.0,
day_dt=dt_from.replace(minute=0, second=0),
compute_leaves=True, resource_id=resource,
default_interval=(8, 16)
)
def interval_get_multi(self, cr, uid, date_and_hours_by_cal, resource=False, byday=True):
@api.model
def interval_get_multi(self, date_and_hours_by_cal, resource=False, byday=True):
""" Used in mrp_operations/mrp_operations.py (default parameters) and in
interval_get()
:deprecated: OpenERP saas-3. Use schedule_hours instead. Note:
:deprecated: Odoo saas-3. Use schedule_hours instead. Note:
Byday was not used. Since saas-3, counts Leave hours instead of all-day leaves."""
res = {}
for dt_str, hours, calendar_id in date_and_hours_by_cal:
result = self.schedule_hours(
cr, uid, calendar_id, hours,
day_dt=datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S').replace(second=0),
result = self.browse(calendar_id).schedule_hours(
hours,
day_dt=fields.Datetime.from_string(dt_str).replace(second=0),
compute_leaves=True, resource_id=resource,
default_interval=(8, 16)
)
res[(dt_str, hours, calendar_id)] = result
return res
def interval_get(self, cr, uid, id, dt_from, hours, resource=False, byday=True):
@api.multi
def interval_get(self, dt_from, hours, resource=False, byday=True):
""" Unifier of interval_get_multi. Used in: mrp_operations/mrp_operations.py,
crm/crm_lead.py (res given).
:deprecated: OpenERP saas-3. Use get_working_hours instead."""
:deprecated: Odoo saas-3. Use get_working_hours instead."""
self.ensure_one()
res = self.interval_get_multi(
cr, uid, [(dt_from.strftime('%Y-%m-%d %H:%M:%S'), hours, id)], resource, byday)[(dt_from.strftime('%Y-%m-%d %H:%M:%S'), hours, id)]
[(fields.Datetime.to_string(dt_from), hours, self.id)], resource, byday)[(fields.Datetime.to_string(dt_from), hours, self.id)]
return res
def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False):
@api.multi
def interval_hours_get(self, dt_from, dt_to, resource=False):
""" Unused wrapper.
:deprecated: OpenERP saas-3. Use get_working_hours instead."""
return self._interval_hours_get(cr, uid, id, dt_from, dt_to, resource_id=resource)
:deprecated: Odoo saas-3. Use get_working_hours instead."""
return self._interval_hours_get(dt_from, dt_to, resource_id=resource)
def _interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource_id=False, timezone_from_uid=None, exclude_leaves=True, context=None):
""" Computes working hours between two dates, taking always same hour/minutes.
:deprecated: OpenERP saas-3. Use get_working_hours instead. Note: since saas-3,
@api.multi
def _interval_hours_get(self, dt_from, dt_to, resource_id=False, timezone_from_uid=None, exclude_leaves=True):
""" Computes working hours between two dates, taking always same hour/minuts.
:deprecated: Odoo saas-3. Use get_working_hours instead. Note: since saas-3,
now resets hour/minuts. Now counts leave hours instead of all-day leaves."""
return self.get_working_hours(
cr, uid, id, dt_from, dt_to,
dt_from, dt_to,
compute_leaves=(not exclude_leaves), resource_id=resource_id,
default_interval=(8, 16), context=context)
default_interval=(8, 16))
class resource_calendar_attendance(osv.osv):
class ResourceCalendarAttendance(models.Model):
_name = "resource.calendar.attendance"
_description = "Work Detail"
_columns = {
'name' : fields.char("Name", required=True),
'dayofweek': fields.selection([('0','Monday'),('1','Tuesday'),('2','Wednesday'),('3','Thursday'),('4','Friday'),('5','Saturday'),('6','Sunday')], 'Day of Week', required=True, select=True),
'date_from' : fields.date('Starting Date'),
'date_to': fields.date('End Date'),
'hour_from' : fields.float('Work from', required=True, help="Start and End time of working.", select=True),
'hour_to' : fields.float("Work to", required=True),
'calendar_id' : fields.many2one("resource.calendar", "Resource's Calendar", required=True),
}
_order = 'dayofweek, hour_from'
_defaults = {
'dayofweek' : '0'
}
name = fields.Char(required=True)
dayofweek = fields.Selection([
('0', 'Monday'),
('1', 'Tuesday'),
('2', 'Wednesday'),
('3', 'Thursday'),
('4', 'Friday'),
('5', 'Saturday'),
('6', 'Sunday')
], 'Day of Week', required=True, index=True, default='0')
date_from = fields.Date(string='Starting Date')
date_to = fields.Date(string='End Date')
hour_from = fields.Float(string='Work from', required=True, index=True, help="Start and End time of working.")
hour_to = fields.Float(string='Work to', required=True)
calendar_id = fields.Many2one("resource.calendar", string="Resource's Calendar", required=True)
def hours_time_string(hours):
""" convert a number of hours (float) into a string with format '%H:%M' """
minutes = int(round(hours * 60))
return "%02d:%02d" % divmod(minutes, 60)
class resource_resource(osv.osv):
class ResourceResource(models.Model):
_name = "resource.resource"
_description = "Resource Detail"
_columns = {
'name': fields.char("Name", required=True),
'code': fields.char('Code', size=16, copy=False),
'active' : fields.boolean('Active', track_visibility='onchange',
help="If the active field is set to False, it will allow you to hide the resource record without removing it."),
'company_id' : fields.many2one('res.company', 'Company'),
'resource_type': fields.selection([('user','Human'),('material','Material')], 'Resource Type', required=True),
'user_id' : fields.many2one('res.users', 'User', help='Related user name for the resource to manage its access.'),
'time_efficiency' : fields.float('Efficiency Factor', size=8, required=True, help="An efficiency of 50% means the resource is two times smaller than his usual speed."),
'calendar_id' : fields.many2one("resource.calendar", "Working Time", help="Define the schedule of resource"),
}
_defaults = {
'resource_type' : 'user',
'time_efficiency' : 100,
'active' : True,
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.resource', context=context)
}
name = fields.Char(required=True)
code = fields.Char(copy=False)
active = fields.Boolean(track_visibility='onchange', default=True,
help="If the active field is set to False, it will allow you to hide the resource record without removing it.")
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env['res.company']._company_default_get())
resource_type = fields.Selection([
('user', 'Human'),
('material', 'Material')
], string='Resource Type', required=True, default='user')
user_id = fields.Many2one('res.users', string='User', help='Related user name for the resource to manage its access.')
time_efficiency = fields.Float(string='Efficiency Factor', required=True, default=100,
help="This field depict the efficiency of the resource to complete tasks. e.g resource put alone on a phase of 5 days with 5 tasks assigned to him, will show a load of 100% for this phase by default, but if we put a efficiency of 200%, then his load will only be 50%.")
calendar_id = fields.Many2one("resource.calendar", string='Working Time', help="Define the schedule of resource")
def copy(self, cr, uid, id, default=None, context=None):
@api.multi
def copy(self, default=None):
self.ensure_one()
if default is None:
default = {}
if not default.get('name', False):
default.update(name=_('%s (copy)') % (self.browse(cr, uid, id, context=context).name))
return super(resource_resource, self).copy(cr, uid, id, default, context)
if not default.get('name'):
default.update(name=_('%s (copy)') % (self.name))
return super(ResourceResource, self).copy(default)
def _is_work_day(self, date):
""" Whether the provided date is a work day for the subject resource.
@@ -719,37 +720,28 @@ class resource_resource(osv.osv):
if intervals and intervals[0]:
yield dt.date()
class resource_calendar_leaves(osv.osv):
class ResourceCalendarLeaves(models.Model):
_name = "resource.calendar.leaves"
_description = "Leave Detail"
_columns = {
'name' : fields.char("Name"),
'company_id' : fields.related('calendar_id','company_id',type='many2one',relation='res.company',string="Company", store=True, readonly=True),
'calendar_id' : fields.many2one("resource.calendar", "Working Time"),
'date_from' : fields.datetime('Start Date', required=True),
'date_to' : fields.datetime('End Date', required=True),
'resource_id' : fields.many2one("resource.resource", "Resource", help="If empty, this is a generic holiday for the company. If a resource is set, the holiday/leave is only for this resource"),
}
def check_dates(self, cr, uid, ids, context=None):
for leave in self.browse(cr, uid, ids, context=context):
if leave.date_from and leave.date_to and leave.date_from > leave.date_to:
return False
return True
name = fields.Char()
company_id = fields.Many2one('res.company', related='calendar_id.company_id', string="Company", store=True, readonly=True)
calendar_id = fields.Many2one('resource.calendar', string='Working Time')
date_from = fields.Datetime(string='Start Date', required=True)
date_to = fields.Datetime(string='End Date', required=True)
resource_id = fields.Many2one("resource.resource", string='Resource',
help="If empty, this is a generic holiday for the company. If a resource is set, the holiday/leave is only for this resource")
_constraints = [
(check_dates, 'Error! leave start-date must be lower then leave end-date.', ['date_from', 'date_to'])
]
@api.constrains('date_from', 'date_to')
def check_dates(self):
if self.filtered(lambda leave: leave.date_from > leave.date_to):
raise ValidationError(_('Error! leave start-date must be lower then leave end-date.'))
def onchange_resource(self, cr, uid, ids, resource, context=None):
result = {}
if resource:
resource_pool = self.pool.get('resource.resource')
result['calendar_id'] = resource_pool.browse(cr, uid, resource, context=context).calendar_id.id
return {'value': result}
return {'value': {'calendar_id': []}}
@api.onchange('resource_id')
def onchange_resource(self):
self.calendar_id = self.resource_id.calendar_id
def seconds(td):
assert isinstance(td, datetime.timedelta)
assert isinstance(td, timedelta)
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<data noupdate="1">
<record model="ir.rule" id="resource_own_leaves">
@@ -13,4 +13,4 @@
</record>
</data>
</openerp>
</odoo>
+3 -5
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<!-- Search Views -->
@@ -212,7 +211,7 @@
<form string="Leave Detail">
<group>
<group>
<field name="resource_id" on_change="onchange_resource(resource_id)"/>
<field name="resource_id"/>
<field name="name" string="Reason"/>
</group>
<group>
@@ -259,5 +258,4 @@
<menuitem action="resource.action_resource_calendar_form" id="menu_resource_calendar" parent="menu_resource_config" sequence="1"/>
<menuitem action="resource.action_resource_calendar_leave_tree" id="menu_view_resource_calendar_leaves_search" parent="menu_resource_config" sequence="2"/>
<menuitem action="resource.action_resource_resource_tree" id="menu_resource_resource" parent="menu_resource_config" sequence="3"/>
</data>
</openerp>
</odoo>