Exemple #1
0
def handle_crq_or_submit(db, vs, now, conf_string, hr_only):
    user = db.user.getnode(vs.user)
    # always send to supervisor (and/or substitute), too.
    emails = [
        db.user.get(x, 'address') for x in common.tt_clearance_by(db, vs.user)
    ]
    if hr_only:
        emails.extend \
            (db.user.get (u, 'address')
             for u in common.get_uids_with_role (db, 'HR-leave-approval')
            )
    url = '%sleave_submission?@template=approve' % db.config.TRACKER_WEB
    approval_type = ''
    try:
        if hr_only:
            s = 'MAIL_LEAVE_SUPERVISOR_%s_APPROVE_HR' % conf_string
        else:
            s = 'MAIL_LEAVE_SUPERVISOR_%s_APPROVE_SV' % conf_string
        approval_type = getattr(db.config.ext, s)
    except InvalidOptionError:
        pass
    try_send_mail \
        ( db, vs, now
        , 'MAIL_LEAVE_SUPERVISOR_%s_TEXT'    % conf_string
        , 'MAIL_LEAVE_SUPERVISOR_%s_SUBJECT' % conf_string
        , url           = url
        , approval_type = approval_type
        , email         = emails
        )
Exemple #2
0
    def approval_for_leave_submission (db, userid, itemid) :
        """User is allowed to view leave submission if he is the supervisor
           or the person to whom approvals are delegated.

           Viewing is allowed by the supervisor or the person to whom
           approvals are delegated.
        """
        ownerid   = db.leave_submission.get (itemid, 'user')
        clearance = tt_clearance_by (db, ownerid)
        return userid in clearance
Exemple #3
0
    def approval_for_time_record (db, userid, itemid) :
        """User is allowed to view time record if he is the supervisor
           or the person to whom approvals are delegated.

           Viewing is allowed by the supervisor or the person to whom
           approvals are delegated.
        """
        dr        = db.time_record.get  (itemid, 'daily_record')
        ownerid   = db.daily_record.get (dr, 'user')
        clearance = tt_clearance_by (db, ownerid)
        return userid in clearance
Exemple #4
0
    def approver_daily_record (db, userid, itemid) :
        """User is allowed to edit daily record if he is supervisor.

           A negative itemid indicates that the record doesn't exist
           yet -- we allow creation in this case. Modification is only
           allowed by the supervisor.
        """
        if int (itemid) < 0 : # allow creation
            return True
        ownerid   = db.daily_record.get (itemid, 'user')
        if not ownerid :
            return False
        clearance = tt_clearance_by (db, ownerid)
        return userid in clearance
def leave_wp (db, dr, wp, start, end, duration) :
    if not wp :
        return False
    if start is not None or end is not None or duration is None :
        return False
    tp = db.time_project.getnode (db.time_wp.get (wp, 'project'))
    if not tp.approval_required :
        return False
    # Only search for non-cancelled non-retired non-declined
    st  = []
    unwanted = ('cancelled', 'retired', 'declined')
    for stid in db.leave_status.getnodeids (retired = False) :
        if db.leave_status.get (stid, 'name') in unwanted :
            continue
        st.append (stid)
    vs = vacation.leave_submissions_on_date \
        (db, dr.user, dr.date, filter = dict (status = st))
    if not vs :
        return False
    assert len (vs) == 1
    vs = vs [0]
    if vs.status != db.leave_status.lookup ('accepted') :
        return False
    clearer = common.tt_clearance_by (db, dr.user)
    uid     = db.getuid ()
    ld      = vacation.leave_duration (db, dr.user, dr.date)
    if tp.max_hours is not None :
        ld = min (ld, tp.max_hours)
    if not ld and tp.max_hours != 0 :
        return False
    if ld != duration :
        return False
    if  (  (uid in clearer and not tp.approval_hr)
        or (   common.user_has_role (db, uid, 'HR-leave-approval')
           and tp.approval_hr
           )
        ) :
        return True
    return False
Exemple #6
0
 def generate(self, ep_status):
     """ Buttons in leave submission forms (edit or approval)
     """
     ret = []
     self.ep_status = ep_status
     self.user = ep_status.item.user.id
     self.sunick = str(ep_status.item.user.supervisor.nickname).upper()
     stname = str(ep_status.prop.name)
     db = ep_status.item._db
     if (self.uid == self.user and stname in self.user_buttons):
         for b in self.user_buttons[stname]:
             ret.append(self.button(*b))
     elif stname in self.approve_buttons and self.uid != self.user:
         if common.user_has_role(self.db, self.uid, 'HR-leave-approval'):
             for b in self.approve_buttons[stname]:
                 ret.append(self.button(*b))
         else:
             tp = ep_status.item.time_wp.project.id
             tp = db.time_project.getnode(tp)
             first_day = ep_status.item.first_day._value
             last_day = ep_status.item.last_day._value
             dyn       = user_dynamic.get_user_dynamic \
                 (db, self.user, last_day)
             ctype = dyn.contract_type
             need_hr   = vacation.need_hr_approval \
                 (db, tp, self.user, ctype, first_day, last_day, stname)
             if (self.uid in common.tt_clearance_by(self.db, self.user)
                     and not need_hr):
                 for b in self.approve_buttons[stname]:
                     ret.append(self.button(*b))
     if ret:
         ret.append \
             ( '<input type="hidden" name="%s@status" value="%s">'
             % (ep_status.item.designator (), stname)
             )
     return ''.join(ret)
Exemple #7
0
def check_submission(db, cl, nodeid, new_values):
    """ Check that changes to a leave submission are ok.
        We basically allow changes of first_day, last_day, and time_wp
        in status 'open'. The user must never change. The status
        transitions are bound to certain roles. Note that this auditor
        is called *after* it has been verified that a requested state
        change is at least possible (although we still have to check the
        role).
    """
    common.reject_attributes(_, new_values, 'user', 'approval_hr')
    old = cl.getnode(nodeid)
    uid = db.getuid()
    user = old.user
    old_status = db.leave_status.get(old.status, 'name')
    if old_status != 'accepted':
        common.reject_attributes(_, new_values, 'comment_cancel')
    new_status = db.leave_status.get \
        (new_values.get ('status', old.status), 'name')
    if old_status != 'open':
        common.reject_attributes \
            (_, new_values, 'first_day', 'last_day', 'time_wp', 'comment')
    fix_dates(new_values)
    first_day = new_values.get('first_day', cl.get(nodeid, 'first_day'))
    last_day = new_values.get('last_day', cl.get(nodeid, 'last_day'))
    if freeze.frozen(db, user, first_day):
        raise Reject(_("Frozen"))
    time_wp = new_values.get('time_wp', cl.get(nodeid, 'time_wp'))
    comment = new_values.get('comment', cl.get(nodeid, 'comment'))
    check_range(db, nodeid, user, first_day, last_day)
    check_wp(db, time_wp, user, first_day, last_day, comment)
    if old_status in ('open', 'submitted'):
        vacation.create_daily_recs(db, user, first_day, last_day)
    if 'first_day' in new_values or 'last_day' in new_values:
        if vacation.leave_days(db, user, first_day, last_day) == 0:
            raise Reject(_("Vacation request for 0 days"))
        check_dyn_user_params(db, user, first_day, last_day)
    if old_status in ('open', 'submitted'):
        check_dr_status(db, user, first_day, last_day, 'open')
    if old_status in ('accepted', 'cancel requested'):
        check_dr_status(db, user, first_day, last_day, 'leave')
    if old_status != new_status:
        if (old_status == 'accepted' and new_status == 'cancel requested'):
            common.require_attributes \
                (_, cl, nodeid, new_values, 'comment_cancel')
        # Allow special HR role to do any (possible) state changes
        # Except for approval of own records
        if (common.user_has_role(db, uid, 'HR-vacation') and
            (uid != user
             or new_status not in ('accepted', 'declined', 'cancelled'))):
            ok = True
        else:
            ok = False
            tp = db.time_project.getnode \
                (db.time_wp.get (old.time_wp, 'project'))
            if not ok and uid == user:
                if old_status == 'open' and new_status == 'submitted':
                    ok = True
                if (old_status == 'accepted'
                        and new_status == 'cancel requested'):
                    ok = True
                if old_status == 'submitted' and new_status == 'open':
                    ok = True
                if old_status == 'open' and new_status == 'cancelled':
                    ok = True
            elif not ok:
                clearer = common.tt_clearance_by(db, user)
                dyn = user_dynamic.get_user_dynamic(db, user, first_day)
                ctype = dyn.contract_type
                hr_only = vacation.need_hr_approval \
                    (db, tp, user, ctype, first_day, last_day, old_status)
                if (uid != user and
                    ((uid in clearer and not hr_only)
                     or common.user_has_role(db, uid, 'HR-leave-approval'))):
                    if (old_status == 'submitted'
                            and new_status in ('accepted', 'declined')):
                        ok = True
                    if (old_status == 'cancel requested'
                            and (new_status == 'cancelled'
                                 or new_status == 'accepted')):
                        ok = True
            if not ok:
                raise Reject(_("Permission denied"))
def check_daily_record (db, cl, nodeid, new_values) :
    """ Check that status changes are OK. Allowed changes:

         - From open to submitted by user or by HR
           But only if no leave submission in state 'submitted',
           'approved', 'cancel requested' exists
         - From submitted to accepted by supervisor or by HR
           but don't allow accepting own records
         - From submitted to open     by supervisor or by HR or by user
         - From accepted  to open     by HR
         - From open to leave if an accepted leave_submission exists
         - From leave to open if leave_submissions exist which are *all*
           in state cancel
    """
    for i in 'user', 'date' :
        if i in new_values and db.getuid () != '1' :
            raise Reject, _ ("%(attr)s may not be changed") % {'attr' : _ (i)}
    if i in ('status',) :
        if i in new_values and not new_values [i] :
            raise Reject, _ ("%(attr)s must be set") % {'attr' : _ (i)}
    user       = cl.get (nodeid, 'user')
    date       = cl.get (nodeid, 'date')
    if frozen (db, user, date) and new_values.keys () != ['tr_duration_ok'] :
        uname = db.user.get (user, 'username')
        raise Reject, _ ("Frozen: %(uname)s, %(date)s") % locals ()
    uid        = db.getuid ()
    is_hr      = common.user_has_role (db, uid, 'hr')
    old_status = cl.get (nodeid, 'status')
    status     = new_values.get ('status', old_status)
    may_give_clearance = uid in common.tt_clearance_by (db, user)

    vs_exists = False
    st_accp = db.leave_status.lookup ('accepted')
    vs = vacation.leave_submissions_on_date (db, user, date)
    # All leave submissions in state cancelled (or declined)?
    # Check if at least one is cancelled
    cn = db.leave_status.lookup ('cancelled')
    dc = db.leave_status.lookup ('declined')
    op = db.leave_status.lookup ('open')
    vs_cancelled = True
    if not vs :
        vs_cancelled = False
    if vs_cancelled :
        for v in vs :
            if v.status == dc :
                continue
            if v.status == cn :
                vs_cancelled = True
            else :
                vs_cancelled = False
                break
    vs_has_valid  = False
    for v in vs :
        if v.status == op or v.status == cn or v.status == dc :
            continue
        vs_has_valid = True
        break
    vs = [v for v in vs if v.status == st_accp]
    if vs :
        assert len (vs) == 1
        vs_accepted = True

    old_status, status = \
        [db.daily_record_status.get (i, 'name') for i in [old_status, status]]
    ttby = db.user.get (user, 'timetracking_by')
    if status != old_status :
        if not (  (   status == 'submitted' and old_status == 'open'
                  and (is_hr or user == uid or ttby == uid)
                  and time_records_consistent (db, cl, nodeid)
                  and not vs_has_valid
                  )
               or (   status == 'accepted'  and old_status == 'submitted'
                  and (is_hr or may_give_clearance)
                  and user != uid
                  )
               or (   status == 'open'      and old_status == 'submitted'
                  and (is_hr or user == uid or may_give_clearance)
                  )
               or (   status == 'open'      and old_status == 'accepted'
                  and is_hr
                  )
               or (   status == 'leave'     and old_status == 'open'
                  and vs_accepted
                  )
               or (   status == 'open'      and old_status == 'leave'
                  and vs_cancelled
                  )
               ) :
            msg = "Invalid Transition"
            if old_status == 'open' :
                if 'status' == 'submitted' :
                    if not is_hr and user != uid :
                        msg = _ ("Permission denied")
                    elif not time_records_consistent (db, cl, nodeid) :
                        msg = _ ("Inkonsistent time records")
                    elif vs_has_valid :
                        msg = _ ("Leave submission exists")
                elif 'status' == 'leave' :
                    msg = _ ("No accepted leave submission")
            elif old_status == 'leave' :
                msg = _ ("Leave submission not cancelled")
            elif old_status == 'accepted' :
                msg = _ ("Re-open only by HR")
            elif old_status == 'submitted' :
                if status == 'accepted' :
                    if not is_hr and not may_give_clearance :
                        msg = _ ("Permission denied")
                    elif user == uid :
                        msg = _ ("May not self-approve")
                elif status == 'open' :
                    if not is_hr and user != uid and not may_give_clearance :
                        msg = _ ("Permission denied")
            raise Reject, \
                ( _ ("Denied state change: %(old_status)s->%(status)s: %(msg)s")
                % locals ()
                )
#!/usr/bin/python

import sys, os
from roundup import date
from roundup import instance
tracker = sys.argv[1]
sys.path.insert(1, os.path.join(tracker, 'lib'))
from common import tt_clearance_by

tracker = instance.open(tracker)
db = tracker.open('admin')

submitted = db.daily_record_status.lookup('submitted')
drecs = db.daily_record.find(status=submitted)
users = {}
clearers = {}
for dr in drecs:
    users[db.daily_record.get(dr, 'user')] = 1
for u in users.iterkeys():
    for c in tt_clearance_by(db, u, only_subs=True):
        clearers[c] = 1
print clearers