Beispiel #1
0
 def month_links(self):
     """ Return month name with links to prev/next month
     """
     pms = self.fdd - Interval('1m')
     nms = self.fdd + Interval('1m')
     pme = common.end_of_month(pms)
     nme = common.end_of_month(nms)
     return '&nbsp'.join \
         (( self.month_link (pms, pme, '<<')
          , self.month
          , str (self.fdd.year)
          , self.month_link (nms, nme, '>>')
         ))
Beispiel #2
0
def consolidated_vacation \
    (db, user, ctype = -1, date = None, vc = None, to_eoy = True) :
    """ Compute remaining vacation on the given date
    """
    if date is None :
        date = Date ('.')
    if ctype == -1 :
        ctype = _get_ctype (db, user, date)
    if ctype == -1 :
        return
    vc  = vc or get_vacation_correction (db, user, ctype, date)
    if not vc :
        return None
    ed  = next_yearly_vacation_date (db, user, ctype, date)
    if not to_eoy :
        ed = min (ed, date + common.day)
    d   = vc.date
    dyn = vac_get_user_dynamic (db, user, ctype, d)
    while dyn and dyn.valid_to and dyn.valid_to <= d :
        dyn = vac_next_user_dynamic (db, dyn)
    if dyn is None :
        return None
    vac = float (vc.days)
    msg = "vac_aliq None for user_dynamic%s" % dyn.id
    assert dyn.vac_aliq, msg
    va = db.vac_aliq.getnode (dyn.vac_aliq)
    assert va.name in ('Daily', 'Monthly')
    # Need to skip first period without a dyn user record
    # sd is the current start date for german aliquotation
    # We subtract 1 day to easily compare the day of the ending-date
    # with the day of the start date
    sd = d
    # This is used for corrections if the start day lies beyond 28 -- in
    # that case there are months that simply don't have that date. So we
    # must correct for this in months with less days.
    sd_day = 0
    if dyn.valid_from > d :
        sd = d = dyn.valid_from
    while dyn and d < ed :
        if dyn.valid_from > d :
            # We want to check if the days that are lost here whenever a
            # jump in dyn user records occurs are OK for monthly aliqotation
            sd = d = dyn.valid_from
            continue
        assert not dyn.valid_to or dyn.valid_to > d
        eoy = Date ('%s-12-31' % d.year)
        msg = "vacation_yearly None for user_dynamic%s" % dyn.id
        assert dyn.vacation_yearly is not None, msg
        msg = ( "vac_aliq changes w/o absolute vac_corr for user_dynamic%s"
              % dyn.id
              )
        assert dyn.vac_aliq == va.id, msg
        if dyn.valid_to and dyn.valid_to <= ed and dyn.valid_to < eoy :
            if va.name == 'Daily' :
                yd = float (common.ydays (dyn.valid_to))
                vac += interval_days \
                    (dyn.valid_to - d) * dyn.vacation_yearly / yd
            else :
                md  = month_diff (sd, dyn.valid_to)
                dy  = sd_day or sd.day
                if dyn.valid_to.day < dy :
                    md -= 1
                    # Example: sd = 2018-04-03 valid_to = 2018-06-01
                    # Need to set sd=2018-05-03, i.e. the next start
                    # day before valid_to
                    # Even more complex is the case where e.g.
                    # sd = 2018-03-31 valid_to = 2018-05-01
                    # We set sd=2018-04-30 and sd_day=31
                    # Get last day of last month
                    lm = dyn.valid_to - Interval ('%sd' % dyn.valid_to.day)
                    em = common.end_of_month (lm)
                    if dy > em.day :
                        sd_day = sd.day
                        sd = em
                    else :
                        sd = Date (lm.pretty ("%%Y-%%m-%s" % sd.day))
                        sd_day = 0
                else :
                    sd = Date (dyn.valid_to.pretty ("%%Y-%%m-%s" % sd.day))
                    sd_day = 0
                d = dyn.valid_to
                vac += dyn.vacation_yearly * md / 12.0
            dyn = vac_next_user_dynamic (db, dyn)
        elif eoy < ed :
            if va.name == 'Daily' :
                yd = float (common.ydays (eoy))
                iv = eoy + common.day - d
                vac += interval_days (iv) * dyn.vacation_yearly / yd
            else :
                md  = month_diff (sd, eoy)
                dy  = sd_day or sd.day
                assert eoy.day >= dy
                if dy == 1 :
                    md += 1
                    sd = eoy + common.day
                else :
                    sd = Date (eoy.pretty ("%%Y-%%m-%s" % sd.day))
                sd_day = 0
                vac += dyn.vacation_yearly * md / 12.0
            d  = eoy + common.day
            if dyn.valid_to == d :
                dyn = vac_next_user_dynamic (db, dyn)
        else :
            if va.name == 'Daily' :
                yd = float (common.ydays (ed - common.day))
                vac += interval_days (ed - d) * dyn.vacation_yearly / yd
            else :
                md = month_diff (sd, ed)
                dy  = sd_day or sd.day
                if ed.day < dy :
                    md -= 1
                sd = ed
                vac += dyn.vacation_yearly * md / 12.0
            d = ed
    return vac
Beispiel #3
0
    def __init__(self, db, request):
        self.db = db = db._db
        now = Date('.')
        user = None
        dt = None
        department = None
        supervisor = None
        self.filterspec = request.filterspec
        self.request = request
        if request.filterspec:
            if 'first_day' in request.filterspec:
                dt = request.filterspec['first_day']
            if 'user' in request.filterspec:
                user = request.filterspec['user']
            if 'supervisor' in request.filterspec:
                supervisor = request.filterspec['supervisor']
            if 'department' in request.filterspec:
                department = request.filterspec['department']
        if not dt:
            som = common.start_of_month(now)
            eom = common.end_of_month(now)
            dt = common.pretty_range(som, eom)
        try:
            fd, ld = dt.split(';')
        except ValueError:
            fd = ld = dt
        self.fdd = fdd = Date(fd)
        self.ldd = ldd = Date(ld)
        self.month = month_name(self.fdd)
        if common.start_of_month(fdd) != common.start_of_month(ldd):
            self.ldd = ldd = common.end_of_month(fdd)
            dt = common.pretty_range(fdd, ldd)
        srt = [('+', a) for a in ('lastname', 'firstname')]
        self.users = users = []
        if user:
            self.users = users = db.user.filter(user, {}, sort=srt)
        if supervisor:
            u = db.user.filter \
                (None, dict (supervisor = supervisor), sort = srt)
            users.extend(u)
        if department:
            u = db.user.filter \
                (None, dict (department = department), sort = srt)
            users.extend(u)
        valid = db.user_status.lookup('valid')
        if not self.users:
            users = db.user.filter(None, dict(status=valid), sort=srt)
            self.users = users
        else:
            users = db.user.filter(users, dict(status=valid), sort=srt)
            self.users = users
        acc = db.leave_status.lookup('accepted')
        flt = dict \
            ( first_day = ';%s' % fd
            , last_day  = '%s;' % ld
            , user      = users
            , status    = acc
            )
        sp = ('user.lastname', 'user.firstname', 'first_day')
        srt = [('+', a) for a in sp]
        lvfirst  = db.leave_submission.filter \
            (None, dict (first_day = dt, user = users, status = acc))
        lvlast   = db.leave_submission.filter \
            (None, dict (last_day = dt, user = users, status = acc))
        lvperiod = db.leave_submission.filter(None, flt)
        lvs = dict.fromkeys(lvfirst + lvlast + lvperiod).keys()
        # Put them in a dict by user-id
        self.lvdict = {}
        for id in lvs:
            lv = db.leave_submission.getnode(id)
            if lv.user not in self.lvdict:
                self.lvdict[lv.user] = []
            self.lvdict[lv.user].append(lv)

        # Get all absence records in the given time range, same algo as for
        if 'status' in flt:
            del flt['status']
        abfirst  = db.absence.filter \
            (None, dict (first_day = dt, user = users))
        ablast   = db.absence.filter \
            (None, dict (last_day  = dt, user = users))
        abperiod = db.absence.filter(None, flt)
        abs = dict.fromkeys(abfirst + ablast + abperiod).keys()
        # Put them in a dict by user-id
        self.abdict = {}
        for id in abs:
            ab = db.absence.getnode(id)
            if ab.user not in self.abdict:
                self.abdict[ab.user] = []
            self.abdict[ab.user].append(ab)

        # Get public holidays
        srt = [('+', 'date')]
        ph = db.public_holiday.filter(None, dict(date=dt), sort=srt)
        # Index by location and sort by date
        self.by_location = {}
        for id in ph:
            holiday = db.public_holiday.getnode(id)
            for loc in holiday.locations:
                if loc not in self.by_location:
                    self.by_location[loc] = []
                self.by_location[loc].append(holiday)

        self.abs_v = db.absence_type.getnode(db.absence_type.lookup('V'))
        self.abs_a = db.absence_type.getnode(db.absence_type.lookup('A'))