From 0dcb117df0969e31e735ef03819d04ee9af3dd0e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 10 Jan 2021 18:54:39 +0100 Subject: [PATCH] code refactoring: sco_abs --- ZAbsences.py | 602 ++------------------------------- ZEntreprises.py | 86 ++--- ZScolar.py | 17 +- html_sidebar.py | 2 +- sco_abs.py | 595 ++++++++++++++++++++++++++++++++ sco_abs_views.py | 4 +- sco_bulletins.py | 4 +- sco_bulletins_json.py | 4 +- sco_bulletins_xml.py | 4 +- sco_compute_moy.py | 4 +- sco_evaluations.py | 4 +- sco_formsemestre_validation.py | 2 +- sco_groups_view.py | 6 +- sco_moduleimpl_status.py | 4 +- sco_poursuite_dut.py | 4 +- sco_prepajury.py | 2 +- sco_trombino_tours.py | 6 +- 17 files changed, 699 insertions(+), 651 deletions(-) create mode 100644 sco_abs.py diff --git a/ZAbsences.py b/ZAbsences.py index 6ebf844e..8e50e72a 100644 --- a/ZAbsences.py +++ b/ZAbsences.py @@ -48,6 +48,13 @@ import urllib import datetime import jaxml import cgi +import string +import re +import time +import calendar + +from mx.DateTime import DateTime as mxDateTime +from mx.DateTime.ISO import ParseDateTimeUTC # --------------- from sco_zope import * @@ -68,10 +75,8 @@ import sco_groups_view import sco_excel import sco_abs_notification, sco_abs_views import sco_compute_moy -import string, re -import time, calendar -from mx.DateTime import DateTime as mxDateTime -from mx.DateTime.ISO import ParseDateTimeUTC +import sco_abs +from sco_abs import ddmmyyyy def _toboolean(x): @@ -84,189 +89,6 @@ def _toboolean(x): return False -def MonthNbDays(month, year): - "returns nb of days in month" - if month > 7: - month = month + 1 - if month % 2: - return 31 - elif month == 2: - if calendar.isleap(year): - return 29 - else: - return 28 - else: - return 30 - - -class ddmmyyyy: - """immutable dates""" - - def __init__(self, date=None, fmt="ddmmyyyy", work_saturday=False): - self.work_saturday = work_saturday - if date is None: - return - try: - if fmt == "ddmmyyyy": - self.day, self.month, self.year = string.split(date, "/") - elif fmt == "iso": - self.year, self.month, self.day = string.split(date, "-") - else: - raise ValueError("invalid format spec. (%s)" % fmt) - self.year = string.atoi(self.year) - self.month = string.atoi(self.month) - self.day = string.atoi(self.day) - except: - raise ScoValueError("date invalide: %s" % date) - # accept years YYYY or YY, uses 1970 as pivot - if self.year < 1970: - if self.year > 100: - raise ScoInvalidDateError("Année invalide: %s" % self.year) - if self.year < 70: - self.year = self.year + 2000 - else: - self.year = self.year + 1900 - if self.month < 1 or self.month > 12: - raise ScoInvalidDateError("Mois invalide: %s" % self.month) - - if self.day < 1 or self.day > MonthNbDays(self.month, self.year): - raise ScoInvalidDateError("Jour invalide: %s" % self.day) - - # weekday in 0-6, where 0 is monday - self.weekday = calendar.weekday(self.year, self.month, self.day) - - self.time = time.mktime((self.year, self.month, self.day, 0, 0, 0, 0, 0, 0)) - - def iswork(self): - "returns true if workable day" - if self.work_saturday: - nbdays = 6 - else: - nbdays = 5 - if ( - self.weekday >= 0 and self.weekday < nbdays - ): # monday-friday or monday-saturday - return 1 - else: - return 0 - - def __repr__(self): - return "'%02d/%02d/%04d'" % (self.day, self.month, self.year) - - def __str__(self): - return "%02d/%02d/%04d" % (self.day, self.month, self.year) - - def ISO(self): - "iso8601 representation of the date" - return "%04d-%02d-%02d" % (self.year, self.month, self.day) - - def next(self, days=1): - "date for the next day (nota: may be a non workable day)" - day = self.day + days - month = self.month - year = self.year - - while day > MonthNbDays(month, year): - day = day - MonthNbDays(month, year) - month = month + 1 - if month > 12: - month = 1 - year = year + 1 - return self.__class__( - "%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday - ) - - def prev(self, days=1): - "date for previous day" - day = self.day - days - month = self.month - year = self.year - while day <= 0: - month = month - 1 - if month == 0: - month = 12 - year = year - 1 - day = day + MonthNbDays(month, year) - - return self.__class__( - "%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday - ) - - def next_monday(self): - "date of next monday" - return self.next((7 - self.weekday) % 7) - - def prev_monday(self): - "date of last monday, but on sunday, pick next monday" - if self.weekday == 6: - return self.next_monday() - else: - return self.prev(self.weekday) - - def __cmp__(self, other): - """return a negative integer if self < other, - zero if self == other, a positive integer if self > other""" - return int(self.time - other.time) - - def __hash__(self): - "we are immutable !" - return hash(self.time) ^ hash(str(self)) - - -# d = ddmmyyyy( '21/12/99' ) - - -def YearTable( - context, - year, - events=[], - firstmonth=9, - lastmonth=7, - halfday=0, - dayattributes="", - pad_width=8, -): - """Generate a calendar table - events = list of tuples (date, text, color, href [,halfday]) - where date is a string in ISO format (yyyy-mm-dd) - halfday is boolean (true: morning, false: afternoon) - text = text to put in calendar (must be short, 1-5 cars) (optional) - if halfday, generate 2 cells per day (morning, afternoon) - """ - T = [ - '' - ] - T.append("") - month = firstmonth - while 1: - T.append('") - if month == lastmonth: - break - month = month + 1 - if month > 12: - month = 1 - year = year + 1 - T.append("
') - T.append(MonthTableHead(month)) - T.append( - MonthTableBody( - month, - year, - events, - halfday, - dayattributes, - context.is_work_saturday(), - pad_width=pad_width, - ) - ) - T.append(MonthTableTail()) - T.append("
") - return string.join(T, "\n") - - -# --------------- - - class ZAbsences( ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit ): @@ -373,7 +195,7 @@ class ZAbsences( % vars(), ) cnx.commit() - invalidateAbsEtudDate(self, etudid, jour) + sco_abs.invalidateAbsEtudDate(self, etudid, jour) sco_abs_notification.abs_notify(self, etudid, jour) def _AddJustif(self, etudid, jour, matin, REQUEST, description=None): @@ -396,7 +218,7 @@ class ZAbsences( msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(), ) cnx.commit() - invalidateAbsEtudDate(self, etudid, jour) + sco_abs.invalidateAbsEtudDate(self, etudid, jour) def _AnnuleAbsence(self, etudid, jour, matin, moduleimpl_id=None, REQUEST=None): """Annule une absence ds base @@ -419,7 +241,7 @@ class ZAbsences( % vars(), ) cnx.commit() - invalidateAbsEtudDate(self, etudid, jour) + sco_abs.invalidateAbsEtudDate(self, etudid, jour) def _AnnuleJustif(self, etudid, jour, matin, REQUEST=None): "Annule un justificatif" @@ -443,7 +265,7 @@ class ZAbsences( msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(), ) cnx.commit() - invalidateAbsEtudDate(self, etudid, jour) + sco_abs.invalidateAbsEtudDate(self, etudid, jour) # Fonction inutile à supprimer (gestion moduleimpl_id incorrecte): # def _AnnuleAbsencesPeriodNoJust(self, etudid, datedebut, datefin, @@ -462,8 +284,8 @@ class ZAbsences( # logdb(REQUEST, cnx, 'AnnuleAbsencesPeriodNoJust', etudid=etudid, # msg='%(datedebut)s - %(datefin)s - (moduleimpl_id)s'%vars()) # cnx.commit() - # invalidateAbsEtudDate(self, etudid, datedebut) - # invalidateAbsEtudDate(self, etudid, datefin) # si un semestre commence apres datedebut et termine avant datefin, il ne sera pas invalide. Tant pis ;-) + # sco_abs.invalidateAbsEtudDate(self, etudid, datedebut) + # sco_abs.invalidateAbsEtudDate(self, etudid, datefin) # si un semestre commence apres datedebut et termine avant datefin, il ne sera pas invalide. Tant pis ;-) security.declareProtected(ScoAbsChange, "AnnuleAbsencesDatesNoJust") @@ -497,7 +319,7 @@ class ZAbsences( "delete from absences where etudid=%(etudid)s and (not estjust) and jour=%(date)s and moduleimpl_id=%(moduleimpl_id)s", vars(), ) - invalidateAbsEtudDate(self, etudid, date) + sco_abs.invalidateAbsEtudDate(self, etudid, date) # s'assure que les justificatifs ne sont pas "absents" for date in dates: cursor.execute( @@ -855,7 +677,7 @@ class ZAbsences( js = "" else: js = 'onmouseover="highlightweek(this);" onmouseout="deselectweeks();" onclick="wclick(this);"' - C = YearTable(self, int(year), dayattributes=js) + C = sco_abs.YearTable(self, int(year), dayattributes=js) return C # --- Misc tools.... ------------------ @@ -1352,7 +1174,7 @@ class ZAbsences( else: checked = "" # bulle lors du passage souris - coljour = DAYNAMES[ + coljour = sco_abs.DAYNAMES[ (calendar.weekday(int(date[:4]), int(date[5:7]), int(date[8:]))) ] datecol = coljour + " " + date[8:] + "/" + date[5:7] + "/" + date[:4] @@ -1798,7 +1620,7 @@ ou entrez une date pour visualiser les absents un jour donné : justified = int(justified) # cnx = self.GetDBConnexion() - billet_id = billet_absence_create( + billet_id = sco_abs.billet_absence_create( cnx, { "etudid": etud["etudid"], @@ -1814,7 +1636,7 @@ ou entrez une date pour visualiser les absents un jour donné : if REQUEST: REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE) - billets = billet_absence_list(cnx, {"billet_id": billet_id}) + billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) tab = self._tableBillets(billets, etud=etud) log( "AddBilletAbsence: new billet_id=%s (%gs)" @@ -1940,7 +1762,7 @@ ou entrez une date pour visualiser les absents un jour donné : etud = etuds[0] cnx = self.GetDBConnexion() - billets = billet_absence_list(cnx, {"etudid": etud["etudid"]}) + billets = sco_abs.billet_absence_list(cnx, {"etudid": etud["etudid"]}) tab = self._tableBillets(billets, etud=etud) return tab.make_page(self, REQUEST=REQUEST, format=format) @@ -1960,7 +1782,7 @@ ou entrez une date pour visualiser les absents un jour donné : def listeBillets(self, REQUEST=None): """Page liste des billets non traités et formulaire recherche d'un billet""" cnx = self.GetDBConnexion() - billets = billet_absence_list(cnx, {"etat": 0}) + billets = sco_abs.billet_absence_list(cnx, {"etat": 0}) tab = self._tableBillets(billets) T = tab.html() H = [ @@ -1986,7 +1808,7 @@ ou entrez une date pour visualiser les absents un jour donné : def deleteBilletAbsence(self, billet_id, REQUEST=None, dialog_confirmed=False): """Supprime un billet.""" cnx = self.GetDBConnexion() - billets = billet_absence_list(cnx, {"billet_id": billet_id}) + billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) if not billets: return REQUEST.RESPONSE.redirect( "listeBillets?head_message=Billet%%20%s%%20inexistant !" % billet_id @@ -2001,7 +1823,7 @@ ou entrez une date pour visualiser les absents un jour donné : parameters={"billet_id": billet_id}, ) - billet_absence_delete(cnx, billet_id) + sco_abs.billet_absence_delete(cnx, billet_id) return REQUEST.RESPONSE.redirect("listeBillets?head_message=Billet%20supprimé") @@ -2050,7 +1872,7 @@ ou entrez une date pour visualiser les absents un jour donné : n += 2 # 2- change etat du billet - billet_absence_edit(cnx, {"billet_id": billet["billet_id"], "etat": 1}) + sco_abs.billet_absence_edit(cnx, {"billet_id": billet["billet_id"], "etat": 1}) return n @@ -2059,7 +1881,7 @@ ou entrez une date pour visualiser les absents un jour donné : def ProcessBilletAbsenceForm(self, billet_id, REQUEST=None): """Formulaire traitement d'un billet""" cnx = self.GetDBConnexion() - billets = billet_absence_list(cnx, {"billet_id": billet_id}) + billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id}) if not billets: return REQUEST.RESPONSE.redirect( "listeBillets?head_message=Billet%%20%s%%20inexistant !" % billet_id @@ -2134,7 +1956,7 @@ ou entrez une date pour visualiser les absents un jour donné : '

Autre billets en attente

Billets déclarés par %s

' % (etud["nomprenom"]) ) - billets = billet_absence_list(cnx, {"etudid": etud["etudid"]}) + billets = sco_abs.billet_absence_list(cnx, {"etudid": etud["etudid"]}) tab = self._tableBillets(billets, etud=etud) H.append(tab.html()) return "\n".join(H) + self.sco_footer(REQUEST) @@ -2172,258 +1994,6 @@ ou entrez une date pour visualiser les absents un jour donné : return repr(doc) -_billet_absenceEditor = notesdb.EditableTable( - "billet_absence", - "billet_id", - ( - "billet_id", - "etudid", - "abs_begin", - "abs_end", - "description", - "etat", - "entry_date", - "justified", - ), - sortkey="entry_date desc", -) - -billet_absence_create = _billet_absenceEditor.create -billet_absence_delete = _billet_absenceEditor.delete -billet_absence_list = _billet_absenceEditor.list -billet_absence_edit = _billet_absenceEditor.edit - -# ------ HTML Calendar functions (see YearTable function) - -# MONTH/DAY NAMES: - -MONTHNAMES = ( - "Janvier", - "Février", - "Mars", - "Avril", - "Mai", - "Juin", - "Juillet", - "Aout", - "Septembre", - "Octobre", - "Novembre", - "Décembre", -) - -MONTHNAMES_ABREV = ( - "Jan.", - "Fév.", - "Mars", - "Avr.", - "Mai ", - "Juin", - "Juil", - "Aout", - "Sept", - "Oct.", - "Nov.", - "Déc.", -) - -DAYNAMES = ("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche") - -DAYNAMES_ABREV = ("L", "M", "M", "J", "V", "S", "D") - -# COLORS: - -WHITE = "#FFFFFF" -GRAY1 = "#EEEEEE" -GREEN3 = "#99CC99" -WEEKDAYCOLOR = GRAY1 -WEEKENDCOLOR = GREEN3 - - -def MonthTableHead(month): - color = WHITE - return """ - \n""" % ( - color, - MONTHNAMES_ABREV[month - 1], - ) - - -def MonthTableTail(): - return "
%s
\n" - - -def MonthTableBody( - month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8 -): - firstday, nbdays = calendar.monthrange(year, month) - localtime = time.localtime() - current_weeknum = time.strftime("%U", localtime) - current_year = localtime[0] - T = [] - # cherche date du lundi de la 1ere semaine de ce mois - monday = ddmmyyyy("1/%d/%d" % (month, year)) - while monday.weekday != 0: - monday = monday.prev() - - if work_saturday: - weekend = ("D",) - else: - weekend = ("S", "D") - - if not halfday: - for d in range(1, nbdays + 1): - weeknum = time.strftime( - "%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y") - ) - day = DAYNAMES_ABREV[(firstday + d - 1) % 7] - if day in weekend: - bgcolor = WEEKENDCOLOR - weekclass = "wkend" - attrs = "" - else: - bgcolor = WEEKDAYCOLOR - weekclass = "wk" + str(monday).replace("/", "_") - attrs = trattributes - color = None - legend = "" - href = "" - descr = "" - # event this day ? - # each event is a tuple (date, text, color, href) - # where date is a string in ISO format (yyyy-mm-dd) - for ev in events: - ev_year = int(ev[0][:4]) - ev_month = int(ev[0][5:7]) - ev_day = int(ev[0][8:10]) - if year == ev_year and month == ev_month and ev_day == d: - if ev[1]: - legend = ev[1] - if ev[2]: - color = ev[2] - if ev[3]: - href = ev[3] - if len(ev) > 4 and ev[4]: - descr = ev[4] - # - cc = [] - if color != None: - cc.append('' % color) - else: - cc.append('') - - if href: - href = 'href="%s"' % href - if descr: - descr = 'title="%s"' % cgi.escape(descr, quote=True) - if href or descr: - cc.append("" % (href, descr)) - - if legend or d == 1: - if pad_width != None: - n = pad_width - len(legend) # pad to 8 cars - if n > 0: - legend = " " * (n / 2) + legend + " " * ((n + 1) / 2) - else: - legend = " " # empty cell - cc.append(legend) - if href or descr: - cc.append("") - cc.append("") - cell = string.join(cc, "") - if day == "D": - monday = monday.next(7) - if ( - weeknum == current_weeknum - and current_year == year - and weekclass != "wkend" - ): - weekclass += " currentweek" - T.append( - '%d%s%s' - % (bgcolor, weekclass, attrs, d, day, cell) - ) - else: - # Calendar with 2 cells / day - for d in range(1, nbdays + 1): - weeknum = time.strftime( - "%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y") - ) - day = DAYNAMES_ABREV[(firstday + d - 1) % 7] - if day in weekend: - bgcolor = WEEKENDCOLOR - weekclass = "wkend" - attrs = "" - else: - bgcolor = WEEKDAYCOLOR - weekclass = "wk" + str(monday).replace("/", "_") - attrs = trattributes - if ( - weeknum == current_weeknum - and current_year == year - and weekclass != "wkend" - ): - weeknum += " currentweek" - - if day == "D": - monday = monday.next(7) - T.append( - '%d%s' - % (bgcolor, weekclass, attrs, d, day) - ) - cc = [] - for morning in (1, 0): - color = None - legend = "" - href = "" - descr = "" - for ev in events: - ev_year = int(ev[0][:4]) - ev_month = int(ev[0][5:7]) - ev_day = int(ev[0][8:10]) - if ev[4] != None: - ev_half = int(ev[4]) - else: - ev_half = 0 - if ( - year == ev_year - and month == ev_month - and ev_day == d - and morning == ev_half - ): - if ev[1]: - legend = ev[1] - if ev[2]: - color = ev[2] - if ev[3]: - href = ev[3] - if len(ev) > 5 and ev[5]: - descr = ev[5] - # - if color != None: - cc.append('' % (color)) - else: - cc.append('') - if href: - href = 'href="%s"' % href - if descr: - descr = 'title="%s"' % cgi.escape(descr, quote=True) - if href or descr: - cc.append("" % (href, descr)) - if legend or d == 1: - n = 3 - len(legend) # pad to 3 cars - if n > 0: - legend = " " * (n / 2) + legend + " " * ((n + 1) / 2) - else: - legend = "   " # empty cell - cc.append(legend) - if href or descr: - cc.append("") - cc.append("\n") - T.append(string.join(cc, "") + "") - return string.join(T, "\n") - - # -------------------------------------------------------------------- # # Zope Product Administration @@ -2441,121 +2011,3 @@ def manage_addZAbsences( # The form used to get the instance id from the user. # manage_addZAbsencesForm = DTMLFile('dtml/manage_addZAbsencesForm', globals()) - - -# -------------------------------------------------------------------- -# -# Cache absences -# -# On cache simplement (à la demande) le nombre d'absences de chaque etudiant -# dans un semestre donné. -# Toute modification du semestre (invalidation) invalide le cache -# (simple mécanisme de "listener" sur le cache de semestres) -# Toute modification des absences d'un étudiant invalide les caches des semestres -# concernés à cette date (en général un seul semestre) -# -# On ne cache pas la liste des absences car elle est rarement utilisée (calendrier, -# absences à une date donnée). -# -# -------------------------------------------------------------------- -class CAbsSemEtud: - """Comptes d'absences d'un etudiant dans un semestre""" - - def __init__(self, context, sem, etudid): - self.context = context - self.sem = sem - self.etudid = etudid - self._loaded = False - formsemestre_id = sem["formsemestre_id"] - context.Notes._getNotesCache().add_listener( - self.invalidate, formsemestre_id, (etudid, formsemestre_id) - ) - - def CountAbs(self): - if not self._loaded: - self.load() - return self._CountAbs - - def CountAbsJust(self): - if not self._loaded: - self.load() - return self._CountAbsJust - - def load(self): - "Load state from DB" - # log('loading CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id'])) - # Reload sem, it may have changed - self.sem = sco_formsemestre.get_formsemestre( - self.context, self.sem["formsemestre_id"] - ) - debut_sem = notesdb.DateDMYtoISO(self.sem["date_debut"]) - fin_sem = notesdb.DateDMYtoISO(self.sem["date_fin"]) - - self._CountAbs = self.context.Absences.CountAbs( - etudid=self.etudid, debut=debut_sem, fin=fin_sem - ) - self._CountAbsJust = self.context.Absences.CountAbsJust( - etudid=self.etudid, debut=debut_sem, fin=fin_sem - ) - self._loaded = True - - def invalidate(self, args=None): - "Notify me that DB has been modified" - # log('invalidate CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id'])) - self._loaded = False - - -# Accès au cache des absences -ABS_CACHE_INST = {} # { DeptId : { formsemestre_id : { etudid : CAbsEtudSem } } } - - -def getAbsSemEtud(context, sem, etudid): - AbsSemEtuds = getAbsSemEtuds(context, sem) - if not etudid in AbsSemEtuds: - AbsSemEtuds[etudid] = CAbsSemEtud(context, sem, etudid) - return AbsSemEtuds[etudid] - - -def getAbsSemEtuds(context, sem): - u = context.GetDBConnexionString() # identifie le dept de facon fiable - if not u in ABS_CACHE_INST: - ABS_CACHE_INST[u] = {} - C = ABS_CACHE_INST[u] - if sem["formsemestre_id"] not in C: - C[sem["formsemestre_id"]] = {} - return C[sem["formsemestre_id"]] - - -def invalidateAbsEtudDate(context, etudid, date): - """Doit etre appelé à chaque modification des absences pour cet étudiant et cette date. - Invalide cache absence et PDF bulletins si nécessaire. - date: date au format ISO - """ - # Semestres a cette date: - etud = context.getEtudInfo(etudid=etudid, filled=True)[0] - sems = [ - sem - for sem in etud["sems"] - if sem["date_debut_iso"] <= date and sem["date_fin_iso"] >= date - ] - - # Invalide les PDF et les abscences: - for sem in sems: - # Inval cache bulletin et/ou note_table - if sco_compute_moy.formsemestre_expressions_use_abscounts( - context, sem["formsemestre_id"] - ): - pdfonly = False # seules certaines formules utilisent les absences - else: - pdfonly = ( - True # efface toujours le PDF car il affiche en général les absences - ) - - context.Notes._inval_cache( - pdfonly=pdfonly, formsemestre_id=sem["formsemestre_id"] - ) - - # Inval cache compteurs absences: - AbsSemEtuds = getAbsSemEtuds(context, sem) - if etudid in AbsSemEtuds: - AbsSemEtuds[etudid].invalidate() diff --git a/ZEntreprises.py b/ZEntreprises.py index e835c80d..3e8a4468 100644 --- a/ZEntreprises.py +++ b/ZEntreprises.py @@ -107,7 +107,7 @@ class EntreprisesEditor(EditableTable): "select E.*, I.nom as etud_nom, I.prenom as etud_prenom, C.date from entreprises E, entreprise_contact C, identite I where C.entreprise_id = E.entreprise_id and C.etudid = I.etudid and I.nom ~* %(etud_nom)s ORDER BY E.nom", args, ) - titles, res = [x[0] for x in cursor.description], cursor.dictfetchall() + _, res = [x[0] for x in cursor.description], cursor.dictfetchall() R = [] for r in res: r["etud_prenom"] = r["etud_prenom"] or "" @@ -450,7 +450,6 @@ class ZEntreprises( def do_entreprise_correspondant_listnames(self, args={}): "-> liste des noms des correspondants (pour affichage menu)" - cnx = self.GetDBConnexion() C = self.do_entreprise_correspondant_list(args=args) return [ (x["prenom"] + " " + x["nom"], str(x["entreprise_corresp_id"])) for x in C @@ -538,43 +537,48 @@ class ZEntreprises( # (fonction ad-hoc car requete sur plusieurs tables) raise NotImplementedError # XXXXX fonction non achevee , non testee... - cnx = self.GetDBConnexion() - cursor = cnx.cursor(cursor_factory=ScoDocCursor) - vals = dictfilter(args, self.dbfields) - # DBSelect - what = ["*"] - operator = " " + operator + " " - cond = " E.entreprise_id = C.entreprise_id " - if vals: - cond += " where " + operator.join( - ["%s%s%%(%s)s" % (x, test, x) for x in vals.keys() if vals[x] != None] - ) - cnuls = " and ".join( - ["%s is NULL" % x for x in vals.keys() if vals[x] is None] - ) - if cnuls: - cond = cond + " and " + cnuls - else: - cond += "" - cursor.execute( - "select distinct" - + ", ".join(what) - + " from entreprises E, entreprise_contact C " - + cond - + orderby, - vals, - ) - titles, res = [x[0] for x in cursor.description], cursor.fetchall() - # - R = [] - for r in res: - d = {} - for i in range(len(titles)): - v = r[i] - # value not formatted ! (see EditableTable.list()) - d[titles[i]] = v - R.append(d) - return R + + # cnx = self.GetDBConnexion() + # cursor = cnx.cursor(cursor_factory=ScoDocCursor) + # if sortkey: + # orderby = " order by " + sortkey + # else: + # orderby = "" + # vals = dictfilter(args, self.dbfields) + # # DBSelect + # what = ["*"] + # operator = " " + operator + " " + # cond = " E.entreprise_id = C.entreprise_id " + # if vals: + # cond += " where " + operator.join( + # ["%s%s%%(%s)s" % (x, test, x) for x in vals.keys() if vals[x] != None] + # ) + # cnuls = " and ".join( + # ["%s is NULL" % x for x in vals.keys() if vals[x] is None] + # ) + # if cnuls: + # cond = cond + " and " + cnuls + # else: + # cond += "" + # cursor.execute( + # "select distinct" + # + ", ".join(what) + # + " from entreprises E, entreprise_contact C " + # + cond + # + orderby, + # vals, + # ) + # titles, res = [x[0] for x in cursor.description], cursor.fetchall() + # # + # R = [] + # for r in res: + # d = {} + # for i in range(len(titles)): + # v = r[i] + # # value not formatted ! (see EditableTable.list()) + # d[titles[i]] = v + # R.append(d) + # return R # -------- Formulaires: traductions du DTML security.declareProtected(ScoEntrepriseChange, "entreprise_create") @@ -892,7 +896,3 @@ def manage_addZEntreprises( if REQUEST is not None: return self.manage_main(self, REQUEST) # return self.manage_editForm(self, REQUEST) - - -# The form used to get the instance id from the user. -# manage_addZAbsencesForm = DTMLFile('dtml/manage_addZAbsencesForm', globals()) diff --git a/ZScolar.py b/ZScolar.py index 7a635570..d09e2ac5 100644 --- a/ZScolar.py +++ b/ZScolar.py @@ -89,6 +89,7 @@ import ZEntreprises import ZScoUsers import sco_modalites import ImportScolars +import sco_abs import sco_portal_apogee import sco_synchro_etuds import sco_page_etud @@ -274,13 +275,13 @@ UE11 Découverte métiers (code UCOD46, 16 ECTS, Apo """ - return ( - self.sco_header(REQUEST) - + """
%s
""" % x - + self.sco_footer(REQUEST) - ) - b = "

Hello, World !


" - raise ValueError("essai exception") + # return ( + # self.sco_header(REQUEST) + # + """
%s
""" % x + # + self.sco_footer(REQUEST) + # ) + # b = "

Hello, World !


" + # raise ValueError("essai exception") # raise ScoValueError('essai exception !', dest_url='totoro', REQUEST=REQUEST) # cursor = cnx.cursor(cursor_factory=ScoDocCursor) @@ -592,7 +593,7 @@ UE11 Découverte métiers (code UCOD46, 16 ECTS, Apo
' diff --git a/html_sidebar.py b/html_sidebar.py index ea05e71c..df7bb59b 100644 --- a/html_sidebar.py +++ b/html_sidebar.py @@ -26,7 +26,7 @@ ############################################################################## from sco_utils import * -from ZAbsences import getAbsSemEtud +from sco_abs import getAbsSemEtud """ Génération de la "sidebar" (marge gauche des pages HTML) diff --git a/sco_abs.py b/sco_abs.py new file mode 100644 index 00000000..8d97d949 --- /dev/null +++ b/sco_abs.py @@ -0,0 +1,595 @@ +# -*- mode: python -*- +# -*- coding: utf-8 -*- + +############################################################################## +# +# Gestion scolarite IUT +# +# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Emmanuel Viennet emmanuel.viennet@viennet.net +# +############################################################################## + +"""Fonctions sur les absences +""" + +# Anciennement dans ZAbscences.py, séparé pour migration + +import string +import datetime +import re +import time +import calendar +import cgi + +import notesdb +from sco_exceptions import ScoValueError, ScoInvalidDateError +import sco_formsemestre +import sco_compute_moy + + +def MonthNbDays(month, year): + "returns nb of days in month" + if month > 7: + month = month + 1 + if month % 2: + return 31 + elif month == 2: + if calendar.isleap(year): + return 29 + else: + return 28 + else: + return 30 + + +class ddmmyyyy: + """immutable dates""" + + def __init__(self, date=None, fmt="ddmmyyyy", work_saturday=False): + self.work_saturday = work_saturday + if date is None: + return + try: + if fmt == "ddmmyyyy": + self.day, self.month, self.year = string.split(date, "/") + elif fmt == "iso": + self.year, self.month, self.day = string.split(date, "-") + else: + raise ValueError("invalid format spec. (%s)" % fmt) + self.year = string.atoi(self.year) + self.month = string.atoi(self.month) + self.day = string.atoi(self.day) + except: + raise ScoValueError("date invalide: %s" % date) + # accept years YYYY or YY, uses 1970 as pivot + if self.year < 1970: + if self.year > 100: + raise ScoInvalidDateError("Année invalide: %s" % self.year) + if self.year < 70: + self.year = self.year + 2000 + else: + self.year = self.year + 1900 + if self.month < 1 or self.month > 12: + raise ScoInvalidDateError("Mois invalide: %s" % self.month) + + if self.day < 1 or self.day > MonthNbDays(self.month, self.year): + raise ScoInvalidDateError("Jour invalide: %s" % self.day) + + # weekday in 0-6, where 0 is monday + self.weekday = calendar.weekday(self.year, self.month, self.day) + + self.time = time.mktime((self.year, self.month, self.day, 0, 0, 0, 0, 0, 0)) + + def iswork(self): + "returns true if workable day" + if self.work_saturday: + nbdays = 6 + else: + nbdays = 5 + if ( + self.weekday >= 0 and self.weekday < nbdays + ): # monday-friday or monday-saturday + return 1 + else: + return 0 + + def __repr__(self): + return "'%02d/%02d/%04d'" % (self.day, self.month, self.year) + + def __str__(self): + return "%02d/%02d/%04d" % (self.day, self.month, self.year) + + def ISO(self): + "iso8601 representation of the date" + return "%04d-%02d-%02d" % (self.year, self.month, self.day) + + def next(self, days=1): + "date for the next day (nota: may be a non workable day)" + day = self.day + days + month = self.month + year = self.year + + while day > MonthNbDays(month, year): + day = day - MonthNbDays(month, year) + month = month + 1 + if month > 12: + month = 1 + year = year + 1 + return self.__class__( + "%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday + ) + + def prev(self, days=1): + "date for previous day" + day = self.day - days + month = self.month + year = self.year + while day <= 0: + month = month - 1 + if month == 0: + month = 12 + year = year - 1 + day = day + MonthNbDays(month, year) + + return self.__class__( + "%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday + ) + + def next_monday(self): + "date of next monday" + return self.next((7 - self.weekday) % 7) + + def prev_monday(self): + "date of last monday, but on sunday, pick next monday" + if self.weekday == 6: + return self.next_monday() + else: + return self.prev(self.weekday) + + def __cmp__(self, other): + """return a negative integer if self < other, + zero if self == other, a positive integer if self > other""" + return int(self.time - other.time) + + def __hash__(self): + "we are immutable !" + return hash(self.time) ^ hash(str(self)) + + +# d = ddmmyyyy( '21/12/99' ) + + +def YearTable( + context, + year, + events=[], + firstmonth=9, + lastmonth=7, + halfday=0, + dayattributes="", + pad_width=8, +): + """Generate a calendar table + events = list of tuples (date, text, color, href [,halfday]) + where date is a string in ISO format (yyyy-mm-dd) + halfday is boolean (true: morning, false: afternoon) + text = text to put in calendar (must be short, 1-5 cars) (optional) + if halfday, generate 2 cells per day (morning, afternoon) + """ + T = [ + '' + ] + T.append("") + month = firstmonth + while 1: + T.append('") + if month == lastmonth: + break + month = month + 1 + if month > 12: + month = 1 + year = year + 1 + T.append("
') + T.append(MonthTableHead(month)) + T.append( + MonthTableBody( + month, + year, + events, + halfday, + dayattributes, + context.is_work_saturday(), + pad_width=pad_width, + ) + ) + T.append(MonthTableTail()) + T.append("
") + return string.join(T, "\n") + + +# ---- BILLETS + +_billet_absenceEditor = notesdb.EditableTable( + "billet_absence", + "billet_id", + ( + "billet_id", + "etudid", + "abs_begin", + "abs_end", + "description", + "etat", + "entry_date", + "justified", + ), + sortkey="entry_date desc", +) + +billet_absence_create = _billet_absenceEditor.create +billet_absence_delete = _billet_absenceEditor.delete +billet_absence_list = _billet_absenceEditor.list +billet_absence_edit = _billet_absenceEditor.edit + +# ------ HTML Calendar functions (see YearTable function) + +# MONTH/DAY NAMES: + +MONTHNAMES = ( + "Janvier", + "Février", + "Mars", + "Avril", + "Mai", + "Juin", + "Juillet", + "Aout", + "Septembre", + "Octobre", + "Novembre", + "Décembre", +) + +MONTHNAMES_ABREV = ( + "Jan.", + "Fév.", + "Mars", + "Avr.", + "Mai ", + "Juin", + "Juil", + "Aout", + "Sept", + "Oct.", + "Nov.", + "Déc.", +) + +DAYNAMES = ("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche") + +DAYNAMES_ABREV = ("L", "M", "M", "J", "V", "S", "D") + +# COLORS: + +WHITE = "#FFFFFF" +GRAY1 = "#EEEEEE" +GREEN3 = "#99CC99" +WEEKDAYCOLOR = GRAY1 +WEEKENDCOLOR = GREEN3 + + +def MonthTableHead(month): + color = WHITE + return """ + \n""" % ( + color, + MONTHNAMES_ABREV[month - 1], + ) + + +def MonthTableTail(): + return "
%s
\n" + + +def MonthTableBody( + month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8 +): + firstday, nbdays = calendar.monthrange(year, month) + localtime = time.localtime() + current_weeknum = time.strftime("%U", localtime) + current_year = localtime[0] + T = [] + # cherche date du lundi de la 1ere semaine de ce mois + monday = ddmmyyyy("1/%d/%d" % (month, year)) + while monday.weekday != 0: + monday = monday.prev() + + if work_saturday: + weekend = ("D",) + else: + weekend = ("S", "D") + + if not halfday: + for d in range(1, nbdays + 1): + weeknum = time.strftime( + "%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y") + ) + day = DAYNAMES_ABREV[(firstday + d - 1) % 7] + if day in weekend: + bgcolor = WEEKENDCOLOR + weekclass = "wkend" + attrs = "" + else: + bgcolor = WEEKDAYCOLOR + weekclass = "wk" + str(monday).replace("/", "_") + attrs = trattributes + color = None + legend = "" + href = "" + descr = "" + # event this day ? + # each event is a tuple (date, text, color, href) + # where date is a string in ISO format (yyyy-mm-dd) + for ev in events: + ev_year = int(ev[0][:4]) + ev_month = int(ev[0][5:7]) + ev_day = int(ev[0][8:10]) + if year == ev_year and month == ev_month and ev_day == d: + if ev[1]: + legend = ev[1] + if ev[2]: + color = ev[2] + if ev[3]: + href = ev[3] + if len(ev) > 4 and ev[4]: + descr = ev[4] + # + cc = [] + if color != None: + cc.append('' % color) + else: + cc.append('') + + if href: + href = 'href="%s"' % href + if descr: + descr = 'title="%s"' % cgi.escape(descr, quote=True) + if href or descr: + cc.append("" % (href, descr)) + + if legend or d == 1: + if pad_width != None: + n = pad_width - len(legend) # pad to 8 cars + if n > 0: + legend = " " * (n / 2) + legend + " " * ((n + 1) / 2) + else: + legend = " " # empty cell + cc.append(legend) + if href or descr: + cc.append("") + cc.append("") + cell = string.join(cc, "") + if day == "D": + monday = monday.next(7) + if ( + weeknum == current_weeknum + and current_year == year + and weekclass != "wkend" + ): + weekclass += " currentweek" + T.append( + '%d%s%s' + % (bgcolor, weekclass, attrs, d, day, cell) + ) + else: + # Calendar with 2 cells / day + for d in range(1, nbdays + 1): + weeknum = time.strftime( + "%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y") + ) + day = DAYNAMES_ABREV[(firstday + d - 1) % 7] + if day in weekend: + bgcolor = WEEKENDCOLOR + weekclass = "wkend" + attrs = "" + else: + bgcolor = WEEKDAYCOLOR + weekclass = "wk" + str(monday).replace("/", "_") + attrs = trattributes + if ( + weeknum == current_weeknum + and current_year == year + and weekclass != "wkend" + ): + weeknum += " currentweek" + + if day == "D": + monday = monday.next(7) + T.append( + '%d%s' + % (bgcolor, weekclass, attrs, d, day) + ) + cc = [] + for morning in (1, 0): + color = None + legend = "" + href = "" + descr = "" + for ev in events: + ev_year = int(ev[0][:4]) + ev_month = int(ev[0][5:7]) + ev_day = int(ev[0][8:10]) + if ev[4] != None: + ev_half = int(ev[4]) + else: + ev_half = 0 + if ( + year == ev_year + and month == ev_month + and ev_day == d + and morning == ev_half + ): + if ev[1]: + legend = ev[1] + if ev[2]: + color = ev[2] + if ev[3]: + href = ev[3] + if len(ev) > 5 and ev[5]: + descr = ev[5] + # + if color != None: + cc.append('' % (color)) + else: + cc.append('') + if href: + href = 'href="%s"' % href + if descr: + descr = 'title="%s"' % cgi.escape(descr, quote=True) + if href or descr: + cc.append("" % (href, descr)) + if legend or d == 1: + n = 3 - len(legend) # pad to 3 cars + if n > 0: + legend = " " * (n / 2) + legend + " " * ((n + 1) / 2) + else: + legend = "   " # empty cell + cc.append(legend) + if href or descr: + cc.append("") + cc.append("\n") + T.append(string.join(cc, "") + "") + return string.join(T, "\n") + + +# -------------------------------------------------------------------- +# +# Cache absences +# +# On cache simplement (à la demande) le nombre d'absences de chaque etudiant +# dans un semestre donné. +# Toute modification du semestre (invalidation) invalide le cache +# (simple mécanisme de "listener" sur le cache de semestres) +# Toute modification des absences d'un étudiant invalide les caches des semestres +# concernés à cette date (en général un seul semestre) +# +# On ne cache pas la liste des absences car elle est rarement utilisée (calendrier, +# absences à une date donnée). +# +# -------------------------------------------------------------------- +class CAbsSemEtud: + """Comptes d'absences d'un etudiant dans un semestre""" + + def __init__(self, context, sem, etudid): + self.context = context + self.sem = sem + self.etudid = etudid + self._loaded = False + formsemestre_id = sem["formsemestre_id"] + context.Notes._getNotesCache().add_listener( + self.invalidate, formsemestre_id, (etudid, formsemestre_id) + ) + + def CountAbs(self): + if not self._loaded: + self.load() + return self._CountAbs + + def CountAbsJust(self): + if not self._loaded: + self.load() + return self._CountAbsJust + + def load(self): + "Load state from DB" + # log('loading CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id'])) + # Reload sem, it may have changed + self.sem = sco_formsemestre.get_formsemestre( + self.context, self.sem["formsemestre_id"] + ) + debut_sem = notesdb.DateDMYtoISO(self.sem["date_debut"]) + fin_sem = notesdb.DateDMYtoISO(self.sem["date_fin"]) + + self._CountAbs = self.context.Absences.CountAbs( + etudid=self.etudid, debut=debut_sem, fin=fin_sem + ) + self._CountAbsJust = self.context.Absences.CountAbsJust( + etudid=self.etudid, debut=debut_sem, fin=fin_sem + ) + self._loaded = True + + def invalidate(self, args=None): + "Notify me that DB has been modified" + # log('invalidate CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id'])) + self._loaded = False + + +# Accès au cache des absences +ABS_CACHE_INST = {} # { DeptId : { formsemestre_id : { etudid : CAbsEtudSem } } } + + +def getAbsSemEtud(context, sem, etudid): + AbsSemEtuds = getAbsSemEtuds(context, sem) + if not etudid in AbsSemEtuds: + AbsSemEtuds[etudid] = CAbsSemEtud(context, sem, etudid) + return AbsSemEtuds[etudid] + + +def getAbsSemEtuds(context, sem): + u = context.GetDBConnexionString() # identifie le dept de facon fiable + if not u in ABS_CACHE_INST: + ABS_CACHE_INST[u] = {} + C = ABS_CACHE_INST[u] + if sem["formsemestre_id"] not in C: + C[sem["formsemestre_id"]] = {} + return C[sem["formsemestre_id"]] + + +def invalidateAbsEtudDate(context, etudid, date): + """Doit etre appelé à chaque modification des absences pour cet étudiant et cette date. + Invalide cache absence et PDF bulletins si nécessaire. + date: date au format ISO + """ + # Semestres a cette date: + etud = context.getEtudInfo(etudid=etudid, filled=True)[0] + sems = [ + sem + for sem in etud["sems"] + if sem["date_debut_iso"] <= date and sem["date_fin_iso"] >= date + ] + + # Invalide les PDF et les abscences: + for sem in sems: + # Inval cache bulletin et/ou note_table + if sco_compute_moy.formsemestre_expressions_use_abscounts( + context, sem["formsemestre_id"] + ): + pdfonly = False # seules certaines formules utilisent les absences + else: + pdfonly = ( + True # efface toujours le PDF car il affiche en général les absences + ) + + context.Notes._inval_cache( + pdfonly=pdfonly, formsemestre_id=sem["formsemestre_id"] + ) + + # Inval cache compteurs absences: + AbsSemEtuds = getAbsSemEtuds(context, sem) + if etudid in AbsSemEtuds: + AbsSemEtuds[etudid].invalidate() diff --git a/sco_abs_views.py b/sco_abs_views.py index af23bfd0..9ede1d38 100644 --- a/sco_abs_views.py +++ b/sco_abs_views.py @@ -40,7 +40,7 @@ import sco_find_etud import sco_formsemestre import sco_photos -import ZAbsences +import sco_abs def doSignaleAbsence( @@ -631,7 +631,7 @@ def CalAbs(context, REQUEST=None): # etud implied events.append( (str(a["jour"]), "X", "#8EA2C6", "", a["matin"], a["description"]) ) - CalHTML = ZAbsences.YearTable(context, anneescolaire, events=events, halfday=1) + CalHTML = sco_abs.YearTable(context, anneescolaire, events=events, halfday=1) # H = [ diff --git a/sco_bulletins.py b/sco_bulletins.py index ab6e2161..1a8fe6d6 100644 --- a/sco_bulletins.py +++ b/sco_bulletins.py @@ -44,7 +44,7 @@ import sco_groups import sco_pvjury import sco_formsemestre_status import sco_photos -import ZAbsences +import sco_abs import sco_abs_views import sco_preferences import sco_codes_parcours @@ -150,7 +150,7 @@ def formsemestre_bulletinetud_dict( context, pid ) # --- Absences - AbsSemEtud = ZAbsences.getAbsSemEtud(context, nt.sem, etudid) + AbsSemEtud = sco_abs.getAbsSemEtud(context, nt.sem, etudid) I["nbabs"] = AbsSemEtud.CountAbs() I["nbabsjust"] = AbsSemEtud.CountAbsJust() diff --git a/sco_bulletins_json.py b/sco_bulletins_json.py index d284ce82..1d19a8c0 100644 --- a/sco_bulletins_json.py +++ b/sco_bulletins_json.py @@ -34,7 +34,7 @@ from notes_table import * import sco_formsemestre import sco_groups import sco_photos -import ZAbsences +import sco_abs import sco_bulletins # -------- Bulletin en JSON @@ -321,7 +321,7 @@ def formsemestre_bulletinetud_published_dict( if context.get_preference("bul_show_abs", formsemestre_id): debut_sem = DateDMYtoISO(sem["date_debut"]) fin_sem = DateDMYtoISO(sem["date_fin"]) - AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid) + AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid) nbabs = AbsEtudSem.CountAbs() nbabsjust = AbsEtudSem.CountAbsJust() diff --git a/sco_bulletins_xml.py b/sco_bulletins_xml.py index 8c65b821..7edd20ae 100644 --- a/sco_bulletins_xml.py +++ b/sco_bulletins_xml.py @@ -41,7 +41,7 @@ from notes_table import * import sco_formsemestre import sco_groups import sco_photos -import ZAbsences +import sco_abs import sco_bulletins # -------- Bulletin en XML @@ -323,7 +323,7 @@ def make_xml_formsemestre_bulletinetud( if context.get_preference("bul_show_abs", formsemestre_id): debut_sem = DateDMYtoISO(sem["date_debut"]) fin_sem = DateDMYtoISO(sem["date_fin"]) - AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid) + AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid) nbabs = AbsEtudSem.CountAbs() nbabsjust = AbsEtudSem.CountAbsJust() doc._push() diff --git a/sco_compute_moy.py b/sco_compute_moy.py index 57a74dab..108f764f 100644 --- a/sco_compute_moy.py +++ b/sco_compute_moy.py @@ -37,7 +37,7 @@ import sco_formsemestre import sco_groups import sco_evaluations from sco_formulas import * -import ZAbsences +import sco_abs def moduleimpl_has_expression(context, mod): @@ -124,7 +124,7 @@ def compute_user_formula( Retourne moy, et en cas d'erreur met à jour diag_info (msg) """ if use_abs: - AbsSemEtud = ZAbsences.getAbsSemEtud(context, sem, etudid) + AbsSemEtud = sco_abs.getAbsSemEtud(context, sem, etudid) nbabs = AbsSemEtud.CountAbs() nbabs_just = AbsSemEtud.CountAbsJust() else: diff --git a/sco_evaluations.py b/sco_evaluations.py index e3db6d00..e877b62c 100644 --- a/sco_evaluations.py +++ b/sco_evaluations.py @@ -42,7 +42,7 @@ from TrivialFormulator import TrivialFormulator import sco_news import sco_formsemestre import sco_groups -import ZAbsences +import sco_abs import sco_evaluations # -------------------------------------------------------------------- @@ -487,7 +487,7 @@ def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None): if day > today: e[2] = color_futur - CalHTML = ZAbsences.YearTable( + CalHTML = sco_abs.YearTable( context.Absences, year, events=events.values(), halfday=False, pad_width=None ) diff --git a/sco_formsemestre_validation.py b/sco_formsemestre_validation.py index afee3e8c..09739779 100644 --- a/sco_formsemestre_validation.py +++ b/sco_formsemestre_validation.py @@ -35,7 +35,7 @@ from notes_log import log from scolog import logdb from notes_table import * import notes_table -from ZAbsences import getAbsSemEtud +from sco_abs import getAbsSemEtud import sco_formsemestre import sco_formsemestre_edit diff --git a/sco_groups_view.py b/sco_groups_view.py index 1ae5387d..152ceb98 100644 --- a/sco_groups_view.py +++ b/sco_groups_view.py @@ -35,7 +35,7 @@ from sco_utils import * import html_sco_header from gen_tables import GenTable import scolars -import ZAbsences +import sco_abs import sco_excel import sco_formsemestre import sco_groups @@ -870,7 +870,7 @@ def form_choix_jour_saisie_hebdo( if not authuser.has_permission(ScoAbsChange, context): return "" sem = groups_infos.formsemestre - first_monday = ZAbsences.ddmmyyyy(sem["date_debut"]).prev_monday() + first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday() today_idx = datetime.date.today().weekday() FA = [] # formulaire avec menu saisi absences @@ -923,7 +923,7 @@ def form_choix_saisie_semaine(context, groups_infos, REQUEST=None): ) # car ici utilisee dans un format string ! DateJour = time.strftime("%d/%m/%Y") - datelundi = ZAbsences.ddmmyyyy(DateJour).prev_monday() + datelundi = sco_abs.ddmmyyyy(DateJour).prev_monday() FA = [] # formulaire avec menu saisi hebdo des absences FA.append('') FA.append('' % datelundi) diff --git a/sco_moduleimpl_status.py b/sco_moduleimpl_status.py index 7a4bf1e7..08c32bfc 100644 --- a/sco_moduleimpl_status.py +++ b/sco_moduleimpl_status.py @@ -43,7 +43,7 @@ import sco_formsemestre import sco_formsemestre_status from sco_formsemestre_status import makeMenu import sco_compute_moy -import ZAbsences +import sco_abs # ported from old DTML code in oct 2009 @@ -241,7 +241,7 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No if authuser.has_permission( ScoAbsChange, context ) and sco_formsemestre.sem_est_courant(context, sem): - datelundi = ZAbsences.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday() + datelundi = sco_abs.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday() H.append( 'Saisie Absences hebdo.' % (formsemestre_id, moduleimpl_id, datelundi) diff --git a/sco_poursuite_dut.py b/sco_poursuite_dut.py index 46334dee..c845ea04 100644 --- a/sco_poursuite_dut.py +++ b/sco_poursuite_dut.py @@ -36,7 +36,7 @@ from notes_log import log from gen_tables import GenTable import sco_formsemestre import sco_groups -import ZAbsences +import sco_abs from sco_codes_parcours import code_semestre_validant, code_semestre_attente @@ -90,7 +90,7 @@ def etud_get_poursuite_info(context, sem, etud): rangs.append(["rang_" + codeModule, rangModule]) # Absences - AbsSemEtud = ZAbsences.getAbsSemEtud(context, nt.sem, etudid) + AbsSemEtud = sco_abs.getAbsSemEtud(context, nt.sem, etudid) NbAbs = AbsSemEtud.CountAbs() NbAbsJust = AbsSemEtud.CountAbsJust() if ( diff --git a/sco_prepajury.py b/sco_prepajury.py index 0df0063d..11f33a54 100644 --- a/sco_prepajury.py +++ b/sco_prepajury.py @@ -38,7 +38,7 @@ import sco_formsemestre import sco_parcours_dut import sco_codes_parcours from scolars import format_nom, format_prenom, format_sexe, format_lycee -from ZAbsences import getAbsSemEtud +from sco_abs import getAbsSemEtud def feuille_preparation_jury(context, formsemestre_id, REQUEST): diff --git a/sco_trombino_tours.py b/sco_trombino_tours.py index eece74eb..1b5a44ed 100644 --- a/sco_trombino_tours.py +++ b/sco_trombino_tours.py @@ -40,7 +40,7 @@ import tempfile from notes_log import log from sco_utils import * -import ZAbsences +import sco_abs import scolars import sco_photos import sco_formsemestre @@ -301,9 +301,9 @@ def pdf_feuille_releve_absences( NB_CELL_PM = context.get_preference("feuille_releve_abs_PM") COLWIDTH = 0.85 * cm if context.get_preference("feuille_releve_abs_samedi"): - days = ZAbsences.DAYNAMES[:6] # Lundi, ..., Samedi + days = sco_abs.DAYNAMES[:6] # Lundi, ..., Samedi else: - days = ZAbsences.DAYNAMES[:5] # Lundi, ..., Vendredi + days = sco_abs.DAYNAMES[:5] # Lundi, ..., Vendredi nb_days = len(days) # Informations sur les groupes à afficher: