def new_machine_name(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'name') namecheck(new_values['name']) adr = new_values.get('network_address', []) mn = new_values.get('machine_name', None) drt = new_values.get('dns_record_type', None) check_nw_adr_location(db, nodeid, adr, mn, drt, new_values)
def olo_check(db, cl, nodeid, new_values): """ Require vac_aliq if do_leave_process is turned on """ lp = new_values.get('do_leave_process') if lp is None and nodeid: lp = cl.get(nodeid, 'do_leave_process') if lp: common.require_attributes(_, cl, nodeid, new_values, 'vac_aliq')
def check_product_price (db, cl, nodeid, new_values) : common.require_attributes (_, cl, nodeid, new_values, 'price', 'currency') if ( 'currency' in new_values and cl.get (nodeid, 'currency') != new_values ['currency'] ) : attr = _ ('currency') raise Reject, _ ("%(attr)s must not be changed") % locals ()
def check_dupe_qsl_type (db, cl, nodeid, new_values) : common.require_attributes (_, cl, nodeid, new_values, 'qsl_type', 'qso') type = new_values ['qsl_type'] qso = new_values ['qso'] qsl = db.qsl.filter (None, dict (qso = qso, qsl_type = type)) qn = db.qsl_type.get (type, 'name') if qsl : raise Reject, _ ('Duplicate QSL type "%s" for QSO' % qn)
def check_room(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'location') if 'name' in new_values: l_id = new_values.get('location', None) if not l_id: # No check necessary, we require the location exists above l_id = cl.get(nodeid, 'location') location = db.location.getnode(l_id) pfx = location.room_prefix if pfx and not new_values['name'].startswith(pfx): raise Reject \ (_ ('Room name must start with prefix "%(pfx)s"') % locals ())
def new_daily_record (db, cl, nodeid, new_values) : """ Only create a daily_record if a user_dynamic record exists for the user. If a new daily_record is created, we check the date provided: If hours, minutes, seconds are all zero we think the time was entered in UTC and do no conversion. If one is non-zero, we get the timezone from the user information and re-encode the date as UTC -- this effectively makes the date a 'naive' date. Then we nullify hour, minute, second of the date. After that, we check that there is no duplicate daily_record with the same date for this user. """ uid = db.getuid () common.require_attributes (_, cl, nodeid, new_values, 'user', 'date') user = new_values ['user'] ttby = db.user.get (user, 'timetracking_by') uname = db.user.get (user, 'username') if ( uid != user and uid != ttby and not common.user_has_role (db, uid, 'controlling', 'admin') ) : raise Reject, _ \ ("Only user, Timetracking by user, " "and Controlling may create daily records" ) common.reject_attributes (_, new_values, 'time_record') # the following is allowed for the admin (import!) if uid != '1' : common.reject_attributes (_, new_values, 'status') date = new_values ['date'] date.hour = date.minute = date.second = 0 new_values ['date'] = date dyn = user_dynamic.get_user_dynamic (db, user, date) if not dyn and uid != '1' : raise Reject, \ _ ("No dynamic user data for %(uname)s, %(date)s") % locals () if uid != '1' and not dyn.booking_allowed : raise Reject, _ \ ("Booking not allowed for %(uname)s, %(date)s") % locals () if frozen (db, user, date) : raise Reject, _ ("Frozen: %(uname)s, %(date)s") % locals () if db.daily_record.filter \ (None, {'date' : date.pretty ('%Y-%m-%d'), 'user' : user}) : raise Reject, _ ("Duplicate record: date = %(date)s, user = %(user)s") \ % new_values new_values ['time_record'] = [] if 'status' not in new_values : new_values ['status'] = db.daily_record_status.lookup ('open') new_values ['tr_duration_ok'] = None
def check_time_project (db, cl, nodeid, new_values) : for i in 'wp_no', 'project' : if i in new_values and cl.get (nodeid, i) : raise Reject, "%(attr)s may not be changed" % {'attr' : _ (i)} common.check_prop_len (_, new_values.get ('name', cl.get (nodeid, 'name'))) if 'work_location' in cl.properties : wl = new_values.get ('work_location', cl.get (nodeid, 'work_location')) if not wl : common.require_attributes \ (_, cl, nodeid, new_values, 'organisation') required = ['cost_center', 'approval_hr', 'approval_required'] if 'is_extern' in cl.properties : required.append ('is_extern') common.require_attributes (_, cl, nodeid, new_values, *required)
def cust_agree (db, cl, nodeid, new_values) : common.require_attributes (_, cl, nodeid, new_values, 'description') customer = product = None if 'customer' in new_values : customer = new_values ['customer'] elif nodeid : customer = cl.get (nodeid, 'customer') if 'product' in new_values : product = new_values ['product'] elif nodeid : product = cl.get (nodeid, 'product') if not customer and not product : raise Reject \ ( _ ("At least one of %(customer)s or %(product)s must be defined") % dict ((k, _ (k)) for k in ('product', 'customer')) )
def new_submission(db, cl, nodeid, new_values): """ Check that new leave submission is allowed and has sensible parameters """ common.reject_attributes(_, new_values, 'approval_hr', 'comment_cancel') uid = db.getuid() st_subm = db.leave_status.lookup('submitted') if 'user' not in new_values: user = new_values['user'] = uid else: user = new_values['user'] common.require_attributes \ (_, cl, nodeid, new_values, 'first_day', 'last_day', 'user') first_day = new_values['first_day'] last_day = new_values['last_day'] fix_dates(new_values) if 'time_wp' not in new_values: wps = vacation.valid_leave_wps \ ( db , user , last_day , [('-', 'project.is_vacation'), ('-', 'project.approval_hr')] ) if wps: new_values['time_wp'] = wps[0] common.require_attributes(_, cl, nodeid, new_values, 'time_wp') if freeze.frozen(db, user, first_day): raise Reject(_("Frozen")) comment = new_values.get('comment') check_range(db, None, user, first_day, last_day) check_wp(db, new_values['time_wp'], user, first_day, last_day, comment) is_admin = (uid == '1') if 'status' in new_values and new_values[ 'status'] != st_subm and not is_admin: raise Reject(_('Initial status must be "submitted"')) if 'status' not in new_values: new_values['status'] = st_subm if (user != uid and not (is_admin or common.user_has_role(db, uid, 'HR-vacation'))): raise Reject \ (_ ("Only special role may create submission for other user")) vacation.create_daily_recs(db, user, first_day, last_day) if vacation.leave_days(db, user, first_day, last_day) == 0: raise Reject(_("Vacation request for 0 days")) check_dr_status(db, user, first_day, last_day, 'open') check_dyn_user_params(db, user, first_day, last_day)
def new_payment(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'amount', 'invoice') inv = db.invoice.getnode(new_values['invoice']) if new_values['receipt_no'] == 'auto': rnum = inv.invoice_no.replace('R', 'B') if rnum[0] != 'B': rnum = 'b' + rnum max = 0 for p_id in inv.payment: rn = db.payment.get(p_id, 'receipt_no') if not rn.startswith(rnum) or rn == rnum: continue n = int(rn[len(rnum):], base=10) if n > max: max = n new_values['receipt_no'] = rnum + '%s' % (max + 1) if 'date_payed' not in new_values: new_values['date_payed'] = Date('.')
def check_params (db, cl, nodeid, new_values) : """ Check for existence of mandatory parameters """ st_open = db.sup_status.lookup ('open') if 'status' not in new_values or new_values ['status'] == st_open : return common.require_attributes (_, cl, nodeid, new_values, 'type') type = new_values.get ('type') if not type : type = cl.get (nodeid, 'type') type = db.sup_type.get (type, 'name') required = mandatory_by_type [type] closed = db.sup_status.lookup ('closed') common.require_attributes (_, cl, nodeid, new_values, * required) if type == 'RMA Issue' and new_values ['status'] == closed : common.require_attributes \ (_, cl, nodeid, new_values, 'execution', 'classification')
def check_contact(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'contact') # get correct contact_type class tc = db.getclass(cl.properties['contact_type'].classname) if nodeid: common.require_attributes(_, cl, nodeid, new_values, 'contact_type') if not nodeid and 'contact_type' not in new_values: ct = tc.filter(None, {}, sort=[('+', 'order')]) assert (ct) new_values['contact_type'] = ct[0] # Make emails lowercase but not for user_contact if 'contact' in new_values and cl.classname != 'user_contact': ct = new_values.get('contact_type') if not ct: ct = cl.get(nodeid, 'contact_type') if tc.get(ct, 'is_email'): new_values['contact'] = new_values['contact'].lower()
def check_weekly_hours(db, cl, nodeid, new_values): spp = new_values.get('supp_per_period') if spp is None and nodeid: spp = cl.get(nodeid, 'supp_per_period') swh = new_values.get('supp_weekly_hours') if swh is None and nodeid: swh = cl.get(nodeid, 'supp_weekly_hours') wh = new_values.get('weekly_hours') if wh is None and nodeid: wh = cl.get(nodeid, 'weekly_hours') if spp or swh: common.require_attributes(_, cl, nodeid, new_values, 'weekly_hours') # weekly_hours must not be 0 in case we have overtime if not wh: msg = ''"Weekly hours must not be 0 when user has " \ "supplementary hours (weekly or otherwise)" raise Reject(_(msg))
def doc_issue_status(db, cl, nodeid, new_values): """ Check if doc_issue_status is set, if no we set it to undecided. Don't allow to set this to empty. """ n = 'doc_issue_status' old = cl.get(nodeid, n) if old: common.require_attributes(_, cl, nodeid, new_values, n) else: if n not in new_values or not new_values[n]: new_values [n] = db.doc_issue_status.filter \ (None, {}, sort = [('+', 'order')]) [0] if (n in new_values): di = db.doc_issue_status.getnode(new_values[n]) if di.need_msg and 'messages' not in new_values: raise Reject, _ \ ("Change of %(doc_issue_status)s requires a message") \ % {n : _ (n)}
def check_prodcat (db, cl, nodeid, new_values) : """ Check that prodcat level is correct. """ if 'valid' in new_values and not new_values ['valid'] : return common.require_attributes (_, cl, nodeid, new_values, 'name') if 'name' in new_values : name = new_values ['name'] else : name = cl.get (nodeid, 'name') if 'level' in new_values : level = new_values.get ('level') elif nodeid : level = cl.get (nodeid, 'level') if not level : new_values ['level'] = 1 if level > 4 : raise Reject, _ ('Max. %s is ') % _ ('level')
def check_kpm(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'issue') if new_values.get('ready_for_sync', None): # required fields only for *new* kpm issue. Issues that were # synced *from* KPM have these fields marked non-editable. iid = new_values.get('issue') if not iid: iid = cl.get(nodeid, 'issue') kpmtr = db.ext_tracker.lookup('KPM') common.require_attributes(_, db.issue, iid, {}, 'release', 'severity') ets = db.ext_tracker_state.filter \ (None, dict (issue = iid, ext_tracker = kpmtr)) assert len(ets) <= 1 if not ets: common.require_attributes \ ( _, cl, nodeid, new_values , 'description', 'fault_frequency', 'reproduceable' )
def check_bu (db, cl, nodeid, new_values) : """ Check BU is set Make an exception for the SPAM customer when closing the support issue. Another exception is when status moves to open, this happens when an incoming mail re-opens an issue. """ # only check if status changed: we don't want simple email replies # to fail if 'status' in new_values : closed = db.sup_status.lookup ('closed') open = db.sup_status.lookup ('open') if new_values ['status'] == closed : cust = new_values.get ('customer', cl.get (nodeid, 'customer')) spam = db.customer.lookup ('SPAM') if cust == spam : return if new_values ['status'] == open : return common.require_attributes (_, cl, nodeid, new_values, 'business_unit')
def new_invoice(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'abo') abo_id = new_values.get('abo', None) abo = db.abo.getnode(abo_id) abo_price = db.abo_price.getnode(abo['aboprice']) abo_type = db.abo_type.getnode(abo_price['abotype']) common.reject_attributes \ ( _ , new_values , 'balance_open' , 'n_sent' , 'last_sent' , 'payer' , 'subscriber' , 'send_it' , 'period_start' , 'period_end' , 'invoice_no' , 'payment' , 'invoice_group' ) if 'amount' not in new_values: new_values['amount'] = abo['amount'] if 'currency' not in new_values: new_values['currency'] = abo_price['currency'] new_values['balance_open'] = new_values['amount'] new_values['open'] = new_values['balance_open'] > 0 new_values['n_sent'] = 0 new_values['payer'] = abo['payer'] new_values['subscriber'] = abo['subscriber'] new_values['send_it'] = False if not len(abo['invoices']): start = abo['begin'] else: maxinv = abo_max_invoice(db, abo) start = maxinv['period_end'] + Interval('1d') end = start + Interval('%dm' % abo_type['period']) end = end - Interval('1d') new_values['period_start'] = start new_values['period_end'] = end new_values['invoice_no'] = "R%s%s" % (abo_id, end.pretty('%m%y'))
def check_statechange (db, cl, nodeid, newvalues) : """ Things to do for a state change: Add doc admins to nosy for certain state changes """ if 'status' not in newvalues : return oldstate = cl.get (nodeid, 'status') newstate = newvalues ['status'] wip = get_wip (db) if newstate != oldstate and oldstate != wip : nosy = newvalues.get ('nosy', cl.get (nodeid, 'nosy')) if not nosy : nosy = [db.getuid ()] nosy = dict.fromkeys (nosy) for u in db.user.getnodeids () : if common.user_has_role (db, u, 'Doc_Admin') : nosy [u] = True newvalues ['nosy'] = nosy.keys () if newstate != oldstate : newvalues ['state_changed_by'] = db.getuid () st = db.doc_status.getnode (newstate) if st.rq_link : common.require_attributes (_, cl, nodeid, newvalues, 'link')
def new_time_project(db, cl, nodeid, new_values): defaults = \ ( ('approval_required', False) , ('approval_hr', False) , ('op_project', True) ) common.require_attributes(_, cl, nodeid, new_values, 'name', 'responsible') if 'work_location' in cl.properties and 'work_location' not in new_values: common.require_attributes(_, cl, nodeid, new_values, 'organisation') for k, v in defaults: if k in cl.properties and k not in new_values: new_values[k] = v common.check_prop_len(_, new_values['name']) if 'status' not in new_values: try: new_values['status'] = db.time_project_status.lookup('New') except KeyError: new_values['status'] = '1' common.require_attributes(_, cl, nodeid, new_values, 'cost_center')
def set_alarm (db, cl, nodeid, new_values) : if 'last_triggered' not in new_values : new_values ['last_triggered'] = None if 'is_lower' not in new_values : new_values ['is_lower'] = False require_attributes (_, cl, nodeid, new_values, 'sensor')
def check_klass(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'klass') klass = new_values.get('klass') if klass: if klass not in db.classes: raise Reject(_("Invalid Class: %(klass)s") % locals())
def check_discount_group(db, cl, nodeid, new_values): common.require_attributes(cl, nodeid, new_values, 'currency') check_group_discount(db, new_values) check_overall_discount(db, new_values) common.auto_retire(db, cl, nodeid, new_values, 'group_discount') common.auto_retire(db, cl, nodeid, new_values, 'overall_discount')
def new_public_holiday(db, cl, nodeid, new_values): require_attributes(_, cl, nodeid, new_values, 'name', 'date', 'locations')
def check_bank_account(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'bank')
def _check_for_description (db, cl, nodeid, newvalues) : """Checks that `description` is given and unique.""" common.require_attributes (_, cl, nodeid, newvalues, 'description') if 'description' in newvalues : desc = newvalues ['description'] common.check_unique (_, cl, nodeid, description = desc)
def check_document_required (db, cl, nodeid, newvalues) : req = ['product_type', 'reference', 'artefact', 'department', 'title'] if nodeid : req.append ('document_nr') req.append ('responsible') common.require_attributes (_, cl, nodeid, newvalues, * req)
def new_time_record (db, cl, nodeid, new_values) : """ auditor on time_record """ uid = db.getuid () travel = False common.require_attributes (_, cl, nodeid, new_values, 'daily_record') common.reject_attributes (_, new_values, 'dist', 'tr_duration') check_generated (new_values) dr = db.daily_record.getnode (new_values ['daily_record']) uname = db.user.get (dr.user, 'username') if dr.status != db.daily_record_status.lookup ('open') and uid != '1' : raise Reject, _ ('Editing of time records only for status "open"') if frozen (db, dr.user, dr.date) : date = dr.date raise Reject, _ ("Frozen: %(uname)s, %(date)s") % locals () start = new_values.get ('start', None) end = new_values.get ('end', None) duration = new_values.get ('duration', None) wpid = new_values.get ('wp') ttby = db.user.get (dr.user, 'timetracking_by') if ( uid != dr.user and uid != ttby and not common.user_has_role (db, uid, 'controlling', 'admin') and not leave_wp (db, dr, wpid, start, end, duration) and not vacation_wp (db, wpid) ) : raise Reject, _ \ ( ("Only %(uname)s, Timetracking by, and Controlling " "may create time records" ) % locals () ) dynamic = user_dynamic.get_user_dynamic (db, dr.user, dr.date) date = dr.date.pretty (common.ymd) if not dynamic : if uid != '1' : raise Reject, _ \ ("No dynamic user data for %(uname)s, %(date)s") % locals () else : if not dynamic.booking_allowed and uid != '1' : raise Reject, _ \ ("Booking not allowed for %(uname)s, %(date)s") % locals () if not (dr.weekend_allowed or dynamic.weekend_allowed) and uid != '1' : wday = gmtime (dr.date.timestamp ())[6] if wday in (5, 6) : raise Reject, _ ('No weekend booking allowed') dstart, dend = check_start_end_duration \ (dr.date, start, end, duration, new_values) # set default work location for new time record by work location ID # for ID reference values check file initial_data.py or use endpoint # /work_location in the web interface if 'work_location' not in new_values : new_values ['work_location'] = '2' # set default values according to selected work package if 'wp' in new_values and new_values ['wp'] : wp = new_values ['wp'] # overwrite work location default if default specified in time category correct_work_location (db, wp, new_values) travel = travel or db.time_wp.get (wp, 'travel') if 'time_activity' in new_values and new_values ['time_activity'] : act = new_values ['time_activity'] travel = travel or db.time_activity.get (act, 'travel') duration = new_values.get ('duration', None) ls = Date (db.user.get (dr.user, 'lunch_start') or '12:00') ls.year = dr.date.year ls.month = dr.date.month ls.day = dr.date.day ld = db.user.get (dr.user, 'lunch_duration') or 1 hours = int (ld) minutes = (ld - hours) * 60 le = ls + Interval ('%d:%d' % (hours, minutes)) if not travel and duration > 6 and start and dstart < ls and dend > ls : newrec = { 'daily_record' : new_values ['daily_record'] , 'start' : le.pretty (hour_format) } dur1 = (ls - dstart).as_seconds () / 3600. dur2 = duration - dur1 if end : dur2 -= ld newrec ['duration'] = dur2 for attr in 'wp', 'time_activity', 'work_location' : if attr in new_values and new_values [attr] : newrec [attr] = new_values [attr] new_values ['end'] = ls.pretty (hour_format) new_values ['duration'] = dur1 if dur2 > 0 : db.time_record.create (** newrec)
def check_mailgroup (db, cl, nodeid, new_values) : common.require_attributes (_, cl, nodeid, new_values, 'nosy')
def check_ext_tracker_state(db, cl, nodeid, new_values): common.require_attributes(_, cl, nodeid, new_values, 'issue')