def _get_ctype (db, user, date) : # None is a valide contract_type, return -1 in case of error dyn = user_dynamic.get_user_dynamic (db, user, date) if not dyn : dyn = user_dynamic.last_user_dynamic (db, user, date) if not dyn : return -1 return dyn.contract_type
def new_user_dynamic(db, cl, nodeid, new_values): common.require_attributes \ ( _, cl, nodeid, new_values , 'user' , 'valid_from' , 'org_location' , 'department' ) user = new_values['user'] valid_from = new_values['valid_from'] valid_to = new_values.get('valid_to', None) olo = new_values['org_location'] dept = new_values['department'] if freeze.frozen(db, user, valid_from): raise Reject(_("Frozen: %(valid_from)s") % locals()) last = user_dynamic.last_user_dynamic(db, user) if not valid_to or not last or last.valid_from < valid_from: update_user_olo_dept(db, user, olo, dept) if 'durations_allowed' not in new_values: new_values['durations_allowed'] = False new_values ['valid_from'], new_values ['valid_to'] = \ check_ranges (cl, nodeid, user, valid_from, valid_to) check_overtime_parameters(db, cl, nodeid, new_values) user_dynamic.invalidate_tr_duration \ (db, user, new_values ['valid_from'], new_values ['valid_to']) orgl = db.org_location.getnode(olo) prev_dyn = user_dynamic.find_user_dynamic(db, user, valid_from, '-') if 'vacation_month' not in new_values and 'vacation_day' not in new_values: if prev_dyn: new_values['vacation_month'] = prev_dyn.vacation_month new_values['vacation_day'] = prev_dyn.vacation_day elif orgl.vacation_legal_year: new_values['vacation_month'] = 1 new_values['vacation_day'] = 1 else: d = new_values['valid_from'] month, mday = (int(x) for x in d.get_tuple()[1:3]) if month == 2 and mday == 29: mday = 28 new_values['vacation_month'] = month new_values['vacation_day'] = mday if 'vacation_yearly' not in new_values: if prev_dyn: new_values['vacation_yearly'] = prev_dyn.vacation_yearly elif orgl.vacation_yearly: new_values['vacation_yearly'] = orgl.vacation_yearly check_vacation(db, cl, nodeid, 'vacation_yearly', new_values) check_weekly_hours(db, cl, nodeid, new_values)
def create_dynuser(db, cl, nodeid, old_values): u = db.user.getnode(nodeid) s = None if 'user_status' in db.classes: s = db.user_status.lookup('valid') olo = cl.get(nodeid, 'org_location') dep = cl.get(nodeid, 'department') dyn = last_user_dynamic(db, nodeid) if nodeid > 2 and (not s or u.status == s) and not dyn and olo and dep: db.user_dynamic.create \ ( user = nodeid , valid_from = Date ('.') , org_location = olo , department = dep , vacation_yearly = 25 )
def approvals_pending (db, request, userlist) : try : db = db._db except AttributeError : pass pending = {} submitted = db.daily_record_status.lookup ('submitted') spec = copy (request.filterspec) filter = request.filterspec editdict = {':template' : 'edit', ':filter' : 'user,date'} now = Date ('.') for u in userlist : find_user = dict (user = u, status = submitted) fdate = None last_frozen = db.daily_record_freeze.filter \ ( None , dict (user = u, date = now.pretty (';%Y-%m-%d'), frozen = True) , group = [('-', 'date')] ) if last_frozen : fdate = db.daily_record_freeze.get (last_frozen [0], 'date') \ + common.day find_user ['date'] = fdate.pretty ('%Y-%m-%d;') dr_per_user = db.daily_record.filter (None, find_user) pending [u] = {} if dr_per_user : earliest = latest = None for p in dr_per_user : date = db.daily_record.get (p, 'date') week, year = common.weekno_year_from_day (date) if not earliest or date < earliest : earliest = date if not latest or date > latest : latest = date start, end = common.week_from_date (date) if fdate and start < fdate : start = fdate filter ['date'] = common.pretty_range (start, end) filter ['user'] = u pending [u][(year, week)] = \ [ None , request.indexargs_url ('', editdict) , 'todo' ] interval = latest - earliest for k in pending [u].iterkeys () : if interval < Interval ('31d') : filter ['date'] = common.pretty_range (earliest, latest) pending [u][k][0] = request.indexargs_url ('', editdict) else : pending [u][k][0] = pending [u][k][1] else : dyn = user_dynamic.last_user_dynamic (db, u) if dyn and (not dyn.valid_to or not fdate or dyn.valid_to > fdate) : date = now if dyn.valid_to and dyn.valid_to < date : date = dyn.valid_to week, year = common.weekno_year_from_day (date) start, end = common.week_from_date (date) if fdate and start < fdate : start = fdate if dyn.valid_to and dyn.valid_to < end : end = dyn.valid_to filter ['date'] = common.pretty_range (start, end) filter ['user'] = u url = request.indexargs_url ('', editdict) pending [u][(year, week)] = [url, url, 'done'] request.filterspec = spec return pending
) if dyn.contract_type: d['contract_type'] = dyn.contract_type print("Creating dynamic user for user%s" % dyn.user) dynid = db.user_dynamic.create(**d) dyn = db.user_dynamic.getnode(dynid) sys.stdout.flush() # Commit new dyn. user record for each user db.commit() # Loop over all obsolete users, find WPs where a user is the only one # allowed booking and set these WPs to the end-date of the last dyn. # user record for that user obs = db.user_status.lookup('obsolete') for uid in db.user.filter(None, dict(status=obs)): dyn = user_dynamic.last_user_dynamic(db, uid) if not dyn: print("Obsolete user%s has no dynamic user data" % uid) if dyn and dyn.valid_to is None: print("Obsolete user%s has a valid dynamic user record!" % uid) continue vt = date.Date('2000-01-01') if dyn: vt = dyn.valid_to user = db.user.getnode(uid) snam = user.username.split('@', 1)[0] # Find WPs where this user is on the bookers list and which has no # end-date set. Note that we do not attempt to set the end-date to # the correct valid_to of the dynamic user if there already is an # end-date -- this would change the end-date of some project WPs # too.
def check_freeze_record (db, cl, nodeid, new_values) : """Check that edits of a freeze record are ok. - editable - no thawed records before current record This also has to handle the case that while thawed the daily record was edited and we don't have a valid daily_record any longer. In that case we change the date to the last valid daily_record date. If that date is already frozen we retire the current record. """ for i in ('date', 'user') : if i in new_values : raise Reject, _ ("%(attr)s must not be changed") % {'attr' : _ (i)} date = cl.get (nodeid, 'date') user = cl.get (nodeid, 'user') # special cases for fixing existing freeze records: if ( db.getuid () == '1' and new_values.keys () == ['validity_date'] and new_values ['validity_date'] == date and cl.get (nodeid, 'validity_date') is None ) : return if ( db.getuid () == '1' and new_values.keys () == ['achieved_hours'] and new_values ['achieved_hours'] == 0 and cl.get (nodeid, 'achieved_hours') is None ) : return dyn = get_user_dynamic (db, user, date) if not dyn : dyn = last_user_dynamic (db, user, date = date) prev = cl.filter \ ( None , dict (user = user, date = date.pretty (';%Y-%m-%d')) , group = [('-', 'date')] ) prev = [p for p in prev if p != nodeid] if prev : prev = db.daily_record_freeze.getnode (prev [0]) assert (dyn.valid_to) # already frozen?? if prev and prev.date >= dyn.valid_to - day : for k in new_values.keys () : del new_values [k] cl.retire (nodeid) return date = dyn.valid_to - day new_values ['date'] = date check_editable (db, cl, nodeid, new_values, date = date) old_frozen = cl.get (nodeid, 'frozen') new_frozen = new_values.get ('frozen', old_frozen) freezing = new_frozen != old_frozen and new_frozen attr = 'balance' if freezing : check_thawed_records (db, user, date) fdate = new_values ['validity_date'] = min_freeze (db, user, date) balance, achieved = compute_balance (db, user, fdate, not_after = True) new_values [attr] = start_balance = balance new_values ['achieved_hours'] = achieved else : new_values ['validity_date'] = None new_values ['achieved_hours'] = None new_values [attr] = None
def check_avc(db, cl, nodeid, new_values): """ Check that an absolute vacation correction exists at the date of the user_dynamic record if either the vac_aliq changed or the vac_aliq is monthly and the vacation changed (compared to the last user_dynamic record). We currently do not require a vacation correction if one already exists *and* there is a gap in user_dynamic record validity ranges. """ # At least one of the following attributes must be in new_values # otherwise we don't have anything to check. attrs = ('vac_aliq', 'vacation_yearly', 'valid_from') for a in attrs: if a in new_values: break else: return va = new_values.get('vac_aliq') if not va and nodeid: va = cl.get(nodeid, 'vac_aliq') vy = new_values.get('vacation_yearly') if vy is None and nodeid: vy = cl.get(nodeid, 'vacation_yearly') # User must exist user = new_values.get('user') if not user: user = cl.get(nodeid, 'user') # valid_from must exist valid_from = new_values.get('valid_from') if not valid_from: valid_from = cl.get(nodeid, 'valid_from') prev_dyn = user_dynamic.find_user_dynamic(db, user, valid_from, '-') if not prev_dyn: return # Check if there is an absolute vacation correction for our # valid_from, everything ok if there is: dt = valid_from.pretty(common.ymd) vcs = db.vacation_correction.filter \ (None, dict (user = user, date = dt, absolute = True)) assert len(vcs) <= 1 if not vcs: # Find the next vc backwards and check if it is at the end of # employment vcs = db.vacation_correction.filter \ ( None , dict (user = user, date = ';%s' % dt, absolute = True) , sort = ('+', 'date') ) if vcs: vc = db.vacation_correction.getnode(vcs[0]) day = common.day # - day because we don't want to find the currently-change dyn vcdyn = user_dynamic.last_user_dynamic(db, user, valid_from - day) if not vcdyn.valid_to or vcdyn.valid_to > vc.date: vcs = [] if vcs: assert db.vacation_correction.get(vcs[0], 'date') <= valid_from return if prev_dyn.vac_aliq != va: van = _('vac_aliq') raise Reject \ ( _ ('Change of "%(van)s" without absolute vacation correction') % locals () ) vyo = prev_dyn.vacation_yearly if db.vac_aliq.get(va, 'name') == 'Monthly' and vy != vyo: vyn = _('vacation_yearly') raise Reject \ ( _ ('Change of "%(vyn)s" without absolute vacation correction') % locals () )
def check_user_dynamic(db, cl, nodeid, new_values): old_ot = cl.get(nodeid, 'overtime_period') for i in 'user', : if i in new_values and cl.get(nodeid, i): raise Reject(_("%(attr)s may not be changed") % {'attr': _(i)}) common.require_attributes \ ( _, cl, nodeid, new_values , 'valid_from' , 'org_location' , 'department' ) user = new_values.get('user', cl.get(nodeid, 'user')) old_from = cl.get(nodeid, 'valid_from') val_from = new_values.get('valid_from', old_from) val_to = new_values.get('valid_to', cl.get(nodeid, 'valid_to')) olo = new_values.get('org_location', cl.get(nodeid, 'org_location')) dept = new_values.get('department', cl.get(nodeid, 'department')) # Note: The valid_to date is *not* part of the validity interval of # the user_dynamic record. So when checking for frozen status we # can allow exactly the valid_to date. otw = common.overtime_period_week(db) nvk = list(sorted(new_values.keys())) old_flexmax = cl.get(nodeid, 'max_flexitime') vac_all = ('vacation_day', 'vacation_month', 'vacation_yearly', 'vac_aliq') vac_aliq = cl.get(nodeid, 'vac_aliq') vac_fix = \ ( set (nvk) <= set (vac_all) and 'vac_aliq' not in nvk or vac_aliq is None and db.getuid () == '1' ) flexi_fix = \ new_values.keys () == ['max_flexitime'] and old_flexmax is None if (freeze.frozen(db, user, old_from) and (new_values.keys() != ['valid_to'] or not val_to or freeze.frozen(db, user, val_to)) and (db.getuid() != '1' or old_ot or not otw or new_values != dict(overtime_period=otw.id)) and (db.getuid() != '1' or not flexi_fix) and not vac_fix): raise Reject(_("Frozen: %(old_from)s") % locals()) last = user_dynamic.last_user_dynamic(db, user) if (('org_location' in new_values or 'department' in new_values) and (not val_to or last.id == nodeid or last.valid_from < val_from)): update_user_olo_dept(db, user, olo, dept) if 'valid_from' in new_values or 'valid_to' in new_values: new_values ['valid_from'], new_values ['valid_to'] = \ check_ranges (cl, nodeid, user, val_from, val_to) val_from = new_values['valid_from'] val_to = new_values['valid_to'] if not vac_fix and not flexi_fix: check_overtime_parameters(db, cl, nodeid, new_values) check_vacation(db, cl, nodeid, 'vacation_yearly', new_values) if not freeze.frozen(db, user, old_from): user_dynamic.invalidate_tr_duration(db, user, val_from, val_to) else: old_to = cl.get(nodeid, 'valid_to') use_to = val_to if old_to: if val_to: use_to = min(old_to, val_to) else: use_to = old_to user_dynamic.invalidate_tr_duration(db, user, use_to, None) check_weekly_hours(db, cl, nodeid, new_values)