<commit_before>#-*- coding:utf-8 -*-
##############################################################################
#
#    Copyright (C) 2013 <NAME> <<EMAIL>>.
#    All Rights Reserved.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License 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 <http://www.gnu.org/licenses/>.
#
##############################################################################

import time

import netsvc

from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from pytz import timezone, utc

from osv import fields, osv
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as OE_DTFORMAT
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as OE_DFORMAT
from openerp.tools.translate import _
import logging
_logger = logging.getLogger(__name__)

class hr_schedule(osv.osv):
    
    _name = 'hr.schedule'
    _inherit = ['mail.thread']
    _description = 'Employee Schedule'
    
    def _compute_alerts(self, cr, uid, ids, field_name, args, context=None):
        res = dict.fromkeys(ids, '')
        for obj in self.browse(cr, uid, ids, context=context):
            alert_ids = []
            for detail in obj.detail_ids:
                [alert_ids.append(a.id) for a in detail.alert_ids]
            res[obj.id] = alert_ids
        return res
    
    _columns = {
        'name' : fields.char("Description", size=64, required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'company_id' : fields.many2one('res.company', 'Company', readonly=True),
        'employee_id': fields.many2one('hr.employee', 'Employee', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'template_id': fields.many2one('hr.schedule.template', 'Schedule Template', readonly=True, states={'draft': [('readonly',False)]}),
        'detail_ids': fields.one2many('hr.schedule.detail', 'schedule_id', 'Schedule Detail', readonly=True, states={'draft': [('readonly',False)]}),
        'date_start': fields.date('Start Date', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'date_end': fields.date('End Date', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'department_id': fields.related('employee_id', 'department_id', type='many2one',
                                        relation='hr.department', string='Department', readonly=True,
                                        store={'hr.schedule': (lambda s, cr, u, ids, ctx: ids, ['employee_id'], 10)}),
        'alert_ids': fields.function(_compute_alerts, type='one2many', relation='hr.schedule.alert', string='Alerts', method=True, readonly=True),
        'state': fields.selection((
                                   ('draft', 'Draft'), ('validate', 'Confirmed'),
                                   ('locked', 'Locked'), ('unlocked', 'Unlocked'),
                                  ), 'State', required=True, readonly=True),
    }
    
    _defaults = {
        'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'hr.schedule', context=context),
        'state': 'draft',
    }
    
    def _schedule_date(self, cr, uid, ids, context=None):
        for schedule in self.browse(cr, uid, ids, context=context):
            cr.execute('SELECT id \
                FROM hr_schedule \
                WHERE (date_start <= %s and %s <= date_end) \
                    AND employee_id=%s \
                    AND id <> %s',(schedule.date_end, schedule.date_start, schedule.employee_id.id, schedule.id))
            if cr.fetchall():
                return False
        return True


    _constraints = [
        (_schedule_date, 'You cannot have schedules that overlap!', ['date_start','date_end']),
    ]
    
    def get_rest_days(self, cr, uid, employee_id, dt, context=None):
        
        day = dt.strftime(OE_DTFORMAT)
        ids = self.search(cr, uid, [('employee_id', '=', employee_id),
                                    ('date_start', '<=', day),
                                    ('date_end', '>=', day)], context=context)
        if len(ids) == 0:
            return None
        elif len(ids) > 1:
            raise osv.except_osv(_('Programming Error'), _('Employee has a scheduled date in more than one schedule.'))
        
        # If the day is in the middle of the week get the start of the week
        if dt.weekday() == 0:
            week_start = dt.strftime(OE_DFORMAT)
        else:
            week_start = (dt + relativedelta(days= -dt.weekday())).strftime(OE_DFORMAT)
        
        # Set the boundaries of the week (i.e- start of current week and start of next week)
        #
        sched = self.browse(cr, uid, ids[0], context=context)
        dtFirstDay = datetime.strptime(sched.detail_ids[0].date_start, OE_DTFORMAT)
        date_start = dtFirstDay.strftime(OE_DFORMAT) < week_start and week_start +' '+ dtFirstDay.strftime('%H:%M:%S') or dtFirstDay.strftime(OE_DTFORMAT)
        dtNextWeek = datetime.strptime(date_start, OE_DTFORMAT) + relativedelta(weeks= +1)
        
        weekdays = ['0','1','2','3','4','5','6']
        scheddays = []
        for dtl in sched.detail_ids:
            # Make sure the date we're examining isn't in the previous week or the next one
            if dtl.date_start < week_start or datetime.strptime(dtl.date_start, OE_DTFORMAT) >= dtNextWeek:
                continue
            if dtl.dayofweek not in scheddays:
                scheddays.append(dtl.dayofweek)
        res = [int(d) for d in weekdays if d not in scheddays]
        # If there are no sched.details return nothing instead of *ALL* the days in the week
        if len(res) == 7:
            res = []
        
        return res
    
    def onchange_employee_start_date(self, cr, uid, ids, employee_id, date_start, context=None):
        
        res = {
            'value': {<commit_msg>hr_schedule: when checking rest days if there is a weekly schedule but no days return an empty list<commit_after>#-*- coding:utf-8 -*-
##############################################################################
#
#    Copyright (C) 2013 <NAME> <<EMAIL>>.
#    All Rights Reserved.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License 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 <http://www.gnu.org/licenses/>.
#
##############################################################################

import time

import netsvc

from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from pytz import timezone, utc

from osv import fields, osv
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as OE_DTFORMAT
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as OE_DFORMAT
from openerp.tools.translate import _
import logging
_logger = logging.getLogger(__name__)

class hr_schedule(osv.osv):
    
    _name = 'hr.schedule'
    _inherit = ['mail.thread']
    _description = 'Employee Schedule'
    
    def _compute_alerts(self, cr, uid, ids, field_name, args, context=None):
        res = dict.fromkeys(ids, '')
        for obj in self.browse(cr, uid, ids, context=context):
            alert_ids = []
            for detail in obj.detail_ids:
                [alert_ids.append(a.id) for a in detail.alert_ids]
            res[obj.id] = alert_ids
        return res
    
    _columns = {
        'name' : fields.char("Description", size=64, required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'company_id' : fields.many2one('res.company', 'Company', readonly=True),
        'employee_id': fields.many2one('hr.employee', 'Employee', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'template_id': fields.many2one('hr.schedule.template', 'Schedule Template', readonly=True, states={'draft': [('readonly',False)]}),
        'detail_ids': fields.one2many('hr.schedule.detail', 'schedule_id', 'Schedule Detail', readonly=True, states={'draft': [('readonly',False)]}),
        'date_start': fields.date('Start Date', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'date_end': fields.date('End Date', required=True, readonly=True, states={'draft': [('readonly',False)]}),
        'department_id': fields.related('employee_id', 'department_id', type='many2one',
                                        relation='hr.department', string='Department', readonly=True,
                                        store={'hr.schedule': (lambda s, cr, u, ids, ctx: ids, ['employee_id'], 10)}),
        'alert_ids': fields.function(_compute_alerts, type='one2many', relation='hr.schedule.alert', string='Alerts', method=True, readonly=True),
        'state': fields.selection((
                                   ('draft', 'Draft'), ('validate', 'Confirmed'),
                                   ('locked', 'Locked'), ('unlocked', 'Unlocked'),
                                  ), 'State', required=True, readonly=True),
    }
    
    _defaults = {
        'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'hr.schedule', context=context),
        'state': 'draft',
    }
    
    def _schedule_date(self, cr, uid, ids, context=None):
        for schedule in self.browse(cr, uid, ids, context=context):
            cr.execute('SELECT id \
                FROM hr_schedule \
                WHERE (date_start <= %s and %s <= date_end) \
                    AND employee_id=%s \
                    AND id <> %s',(schedule.date_end, schedule.date_start, schedule.employee_id.id, schedule.id))
            if cr.fetchall():
                return False
        return True


    _constraints = [
        (_schedule_date, 'You cannot have schedules that overlap!', ['date_start','date_end']),
    ]
    
    def get_rest_days(self, cr, uid, employee_id, dt, context=None):
        
        res = []
        day = dt.strftime(OE_DTFORMAT)
        ids = self.search(cr, uid, [('employee_id', '=', employee_id),
                                    ('date_start', '<=', day),
                                    ('date_end', '>=', day)], context=context)
        if len(ids) == 0:
            return None
        elif len(ids) > 1:
            raise osv.except_osv(_('Programming Error'), _('Employee has a scheduled date in more than one schedule.'))
        
        # If the day is in the middle of the week get the start of the week
        if dt.weekday() == 0:
            week_start = dt.strftime(OE_DFORMAT)
        else:
            week_start = (dt + relativedelta(days= -dt.weekday())).strftime(OE_DFORMAT)
        
        # Set the boundaries of the week (i.e- start of current week and start of next week)
        #
        sched = self.browse(cr, uid, ids[0], context=context)
        if not sched.detail_ids:
            return res
        dtFirstDay = datetime.strptime(sched.detail_ids[0].date_start, OE_DTFORMAT)
        date_start = dtFirstDay.strftime(OE_DFORMAT) < week_start and week_start +' '+ dtFirstDay.strftime('%H:%M:%S') or dtFirstDay.strftime(OE_DTFORMAT)
        dtNextWeek = datetime.strptime(date_start, OE_DTFORMAT) + relativedelta(weeks= +1)
        
        weekdays = ['0','1','2','3','4','5','6']
        scheddays = []
        for dtl in sched.detail_ids:
            # Make sure the date we're examining isn't in the previous week or the next one
            if dtl.date_start < week_start or datetime.strptime(dtl.date_start, OE_DTFORMAT) >= dtNextWeek:
                continue
            if dtl.dayofweek not in scheddays:
                scheddays.append(dtl.dayofweek)
        res = [int(d) for d in weekdays if d not in scheddays]
        # If there are no sched.details return nothing instead of *ALL* the days in the week
        if len(res) == 7:
            res = []
        
        return res
    
    def onchange_employee_start_date(self, cr, uid, ids, employee_id, date_start, context=None):
        
        res = {
            'value': {
{'fraction_non_alphanumeric': 0.1456466804502642, 'fraction_numerical': 0.004594532506317482, 'mean_word_length': 2.653146853146853, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6581860', 'n_tokens_mistral': 3844, 'n_tokens_neox': 3691, 'n_words': 1063}