forked from ScoDoc/ScoDoc
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into ScoDoc8
This commit is contained in:
commit
fcd34c3bdf
602
ZAbsences.py
602
ZAbsences.py
@ -48,6 +48,13 @@ import urllib
|
|||||||
import datetime
|
import datetime
|
||||||
import jaxml
|
import jaxml
|
||||||
import cgi
|
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 *
|
from sco_zope import *
|
||||||
@ -68,10 +75,8 @@ import sco_groups_view
|
|||||||
import sco_excel
|
import sco_excel
|
||||||
import sco_abs_notification, sco_abs_views
|
import sco_abs_notification, sco_abs_views
|
||||||
import sco_compute_moy
|
import sco_compute_moy
|
||||||
import string, re
|
import sco_abs
|
||||||
import time, calendar
|
from sco_abs import ddmmyyyy
|
||||||
from mx.DateTime import DateTime as mxDateTime
|
|
||||||
from mx.DateTime.ISO import ParseDateTimeUTC
|
|
||||||
|
|
||||||
|
|
||||||
def _toboolean(x):
|
def _toboolean(x):
|
||||||
@ -84,189 +89,6 @@ def _toboolean(x):
|
|||||||
return False
|
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 = [
|
|
||||||
'<table id="maincalendar" class="maincalendar" border="3" cellpadding="1" cellspacing="1" frame="box">'
|
|
||||||
]
|
|
||||||
T.append("<tr>")
|
|
||||||
month = firstmonth
|
|
||||||
while 1:
|
|
||||||
T.append('<td valign="top">')
|
|
||||||
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("</td>")
|
|
||||||
if month == lastmonth:
|
|
||||||
break
|
|
||||||
month = month + 1
|
|
||||||
if month > 12:
|
|
||||||
month = 1
|
|
||||||
year = year + 1
|
|
||||||
T.append("</table>")
|
|
||||||
return string.join(T, "\n")
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------
|
|
||||||
|
|
||||||
|
|
||||||
class ZAbsences(
|
class ZAbsences(
|
||||||
ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit
|
ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit
|
||||||
):
|
):
|
||||||
@ -373,7 +195,7 @@ class ZAbsences(
|
|||||||
% vars(),
|
% vars(),
|
||||||
)
|
)
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
invalidateAbsEtudDate(self, etudid, jour)
|
sco_abs.invalidateAbsEtudDate(self, etudid, jour)
|
||||||
sco_abs_notification.abs_notify(self, etudid, jour)
|
sco_abs_notification.abs_notify(self, etudid, jour)
|
||||||
|
|
||||||
def _AddJustif(self, etudid, jour, matin, REQUEST, description=None):
|
def _AddJustif(self, etudid, jour, matin, REQUEST, description=None):
|
||||||
@ -396,7 +218,7 @@ class ZAbsences(
|
|||||||
msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(),
|
msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(),
|
||||||
)
|
)
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
invalidateAbsEtudDate(self, etudid, jour)
|
sco_abs.invalidateAbsEtudDate(self, etudid, jour)
|
||||||
|
|
||||||
def _AnnuleAbsence(self, etudid, jour, matin, moduleimpl_id=None, REQUEST=None):
|
def _AnnuleAbsence(self, etudid, jour, matin, moduleimpl_id=None, REQUEST=None):
|
||||||
"""Annule une absence ds base
|
"""Annule une absence ds base
|
||||||
@ -419,7 +241,7 @@ class ZAbsences(
|
|||||||
% vars(),
|
% vars(),
|
||||||
)
|
)
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
invalidateAbsEtudDate(self, etudid, jour)
|
sco_abs.invalidateAbsEtudDate(self, etudid, jour)
|
||||||
|
|
||||||
def _AnnuleJustif(self, etudid, jour, matin, REQUEST=None):
|
def _AnnuleJustif(self, etudid, jour, matin, REQUEST=None):
|
||||||
"Annule un justificatif"
|
"Annule un justificatif"
|
||||||
@ -443,7 +265,7 @@ class ZAbsences(
|
|||||||
msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(),
|
msg="JOUR=%(jour)s,MATIN=%(matin)s" % vars(),
|
||||||
)
|
)
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
invalidateAbsEtudDate(self, etudid, jour)
|
sco_abs.invalidateAbsEtudDate(self, etudid, jour)
|
||||||
|
|
||||||
# Fonction inutile à supprimer (gestion moduleimpl_id incorrecte):
|
# Fonction inutile à supprimer (gestion moduleimpl_id incorrecte):
|
||||||
# def _AnnuleAbsencesPeriodNoJust(self, etudid, datedebut, datefin,
|
# def _AnnuleAbsencesPeriodNoJust(self, etudid, datedebut, datefin,
|
||||||
@ -462,8 +284,8 @@ class ZAbsences(
|
|||||||
# logdb(REQUEST, cnx, 'AnnuleAbsencesPeriodNoJust', etudid=etudid,
|
# logdb(REQUEST, cnx, 'AnnuleAbsencesPeriodNoJust', etudid=etudid,
|
||||||
# msg='%(datedebut)s - %(datefin)s - (moduleimpl_id)s'%vars())
|
# msg='%(datedebut)s - %(datefin)s - (moduleimpl_id)s'%vars())
|
||||||
# cnx.commit()
|
# cnx.commit()
|
||||||
# invalidateAbsEtudDate(self, etudid, datedebut)
|
# sco_abs.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, datefin) # si un semestre commence apres datedebut et termine avant datefin, il ne sera pas invalide. Tant pis ;-)
|
||||||
|
|
||||||
security.declareProtected(ScoAbsChange, "AnnuleAbsencesDatesNoJust")
|
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",
|
"delete from absences where etudid=%(etudid)s and (not estjust) and jour=%(date)s and moduleimpl_id=%(moduleimpl_id)s",
|
||||||
vars(),
|
vars(),
|
||||||
)
|
)
|
||||||
invalidateAbsEtudDate(self, etudid, date)
|
sco_abs.invalidateAbsEtudDate(self, etudid, date)
|
||||||
# s'assure que les justificatifs ne sont pas "absents"
|
# s'assure que les justificatifs ne sont pas "absents"
|
||||||
for date in dates:
|
for date in dates:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@ -855,7 +677,7 @@ class ZAbsences(
|
|||||||
js = ""
|
js = ""
|
||||||
else:
|
else:
|
||||||
js = 'onmouseover="highlightweek(this);" onmouseout="deselectweeks();" onclick="wclick(this);"'
|
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
|
return C
|
||||||
|
|
||||||
# --- Misc tools.... ------------------
|
# --- Misc tools.... ------------------
|
||||||
@ -1352,7 +1174,7 @@ class ZAbsences(
|
|||||||
else:
|
else:
|
||||||
checked = ""
|
checked = ""
|
||||||
# bulle lors du passage souris
|
# bulle lors du passage souris
|
||||||
coljour = DAYNAMES[
|
coljour = sco_abs.DAYNAMES[
|
||||||
(calendar.weekday(int(date[:4]), int(date[5:7]), int(date[8:])))
|
(calendar.weekday(int(date[:4]), int(date[5:7]), int(date[8:])))
|
||||||
]
|
]
|
||||||
datecol = coljour + " " + date[8:] + "/" + date[5:7] + "/" + date[:4]
|
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)
|
justified = int(justified)
|
||||||
#
|
#
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
billet_id = billet_absence_create(
|
billet_id = sco_abs.billet_absence_create(
|
||||||
cnx,
|
cnx,
|
||||||
{
|
{
|
||||||
"etudid": etud["etudid"],
|
"etudid": etud["etudid"],
|
||||||
@ -1814,7 +1636,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
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)
|
tab = self._tableBillets(billets, etud=etud)
|
||||||
log(
|
log(
|
||||||
"AddBilletAbsence: new billet_id=%s (%gs)"
|
"AddBilletAbsence: new billet_id=%s (%gs)"
|
||||||
@ -1940,7 +1762,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
|
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
cnx = self.GetDBConnexion()
|
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)
|
tab = self._tableBillets(billets, etud=etud)
|
||||||
return tab.make_page(self, REQUEST=REQUEST, format=format)
|
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):
|
def listeBillets(self, REQUEST=None):
|
||||||
"""Page liste des billets non traités et formulaire recherche d'un billet"""
|
"""Page liste des billets non traités et formulaire recherche d'un billet"""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
billets = billet_absence_list(cnx, {"etat": 0})
|
billets = sco_abs.billet_absence_list(cnx, {"etat": 0})
|
||||||
tab = self._tableBillets(billets)
|
tab = self._tableBillets(billets)
|
||||||
T = tab.html()
|
T = tab.html()
|
||||||
H = [
|
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):
|
def deleteBilletAbsence(self, billet_id, REQUEST=None, dialog_confirmed=False):
|
||||||
"""Supprime un billet."""
|
"""Supprime un billet."""
|
||||||
cnx = self.GetDBConnexion()
|
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:
|
if not billets:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"listeBillets?head_message=Billet%%20%s%%20inexistant !" % billet_id
|
"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},
|
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é")
|
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
|
n += 2
|
||||||
|
|
||||||
# 2- change etat du billet
|
# 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
|
return n
|
||||||
|
|
||||||
@ -2059,7 +1881,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
def ProcessBilletAbsenceForm(self, billet_id, REQUEST=None):
|
def ProcessBilletAbsenceForm(self, billet_id, REQUEST=None):
|
||||||
"""Formulaire traitement d'un billet"""
|
"""Formulaire traitement d'un billet"""
|
||||||
cnx = self.GetDBConnexion()
|
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:
|
if not billets:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"listeBillets?head_message=Billet%%20%s%%20inexistant !" % billet_id
|
"listeBillets?head_message=Billet%%20%s%%20inexistant !" % billet_id
|
||||||
@ -2134,7 +1956,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
'</div><p><a class="stdlink" href="listeBillets">Autre billets en attente</a></p><h4>Billets déclarés par %s</h4>'
|
'</div><p><a class="stdlink" href="listeBillets">Autre billets en attente</a></p><h4>Billets déclarés par %s</h4>'
|
||||||
% (etud["nomprenom"])
|
% (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)
|
tab = self._tableBillets(billets, etud=etud)
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
return "\n".join(H) + self.sco_footer(REQUEST)
|
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)
|
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 """<table class="monthcalendar" border="0" cellpadding="0" cellspacing="0" frame="box">
|
|
||||||
<tr bgcolor="%s"><td class="calcol" colspan="2" align="center">%s</td></tr>\n""" % (
|
|
||||||
color,
|
|
||||||
MONTHNAMES_ABREV[month - 1],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def MonthTableTail():
|
|
||||||
return "</table>\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('<td bgcolor="%s" class="calcell">' % color)
|
|
||||||
else:
|
|
||||||
cc.append('<td class="calcell">')
|
|
||||||
|
|
||||||
if href:
|
|
||||||
href = 'href="%s"' % href
|
|
||||||
if descr:
|
|
||||||
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
|
||||||
if href or descr:
|
|
||||||
cc.append("<a %s %s>" % (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("</a>")
|
|
||||||
cc.append("</td>")
|
|
||||||
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(
|
|
||||||
'<tr bgcolor="%s" class="%s" %s><td class="calday">%d%s</td>%s</tr>'
|
|
||||||
% (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(
|
|
||||||
'<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>'
|
|
||||||
% (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('<td bgcolor="%s" class="calcell">' % (color))
|
|
||||||
else:
|
|
||||||
cc.append('<td class="calcell">')
|
|
||||||
if href:
|
|
||||||
href = 'href="%s"' % href
|
|
||||||
if descr:
|
|
||||||
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
|
||||||
if href or descr:
|
|
||||||
cc.append("<a %s %s>" % (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("</a>")
|
|
||||||
cc.append("</td>\n")
|
|
||||||
T.append(string.join(cc, "") + "</tr>")
|
|
||||||
return string.join(T, "\n")
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Zope Product Administration
|
# Zope Product Administration
|
||||||
@ -2441,121 +2011,3 @@ def manage_addZAbsences(
|
|||||||
|
|
||||||
# The form used to get the instance id from the user.
|
# The form used to get the instance id from the user.
|
||||||
# manage_addZAbsencesForm = DTMLFile('dtml/manage_addZAbsencesForm', globals())
|
# 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()
|
|
||||||
|
@ -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",
|
"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,
|
args,
|
||||||
)
|
)
|
||||||
titles, res = [x[0] for x in cursor.description], cursor.dictfetchall()
|
_, res = [x[0] for x in cursor.description], cursor.dictfetchall()
|
||||||
R = []
|
R = []
|
||||||
for r in res:
|
for r in res:
|
||||||
r["etud_prenom"] = r["etud_prenom"] or ""
|
r["etud_prenom"] = r["etud_prenom"] or ""
|
||||||
@ -450,7 +450,6 @@ class ZEntreprises(
|
|||||||
|
|
||||||
def do_entreprise_correspondant_listnames(self, args={}):
|
def do_entreprise_correspondant_listnames(self, args={}):
|
||||||
"-> liste des noms des correspondants (pour affichage menu)"
|
"-> liste des noms des correspondants (pour affichage menu)"
|
||||||
cnx = self.GetDBConnexion()
|
|
||||||
C = self.do_entreprise_correspondant_list(args=args)
|
C = self.do_entreprise_correspondant_list(args=args)
|
||||||
return [
|
return [
|
||||||
(x["prenom"] + " " + x["nom"], str(x["entreprise_corresp_id"])) for x in C
|
(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)
|
# (fonction ad-hoc car requete sur plusieurs tables)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
# XXXXX fonction non achevee , non testee...
|
# XXXXX fonction non achevee , non testee...
|
||||||
cnx = self.GetDBConnexion()
|
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
# cnx = self.GetDBConnexion()
|
||||||
vals = dictfilter(args, self.dbfields)
|
# cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
# DBSelect
|
# if sortkey:
|
||||||
what = ["*"]
|
# orderby = " order by " + sortkey
|
||||||
operator = " " + operator + " "
|
# else:
|
||||||
cond = " E.entreprise_id = C.entreprise_id "
|
# orderby = ""
|
||||||
if vals:
|
# vals = dictfilter(args, self.dbfields)
|
||||||
cond += " where " + operator.join(
|
# # DBSelect
|
||||||
["%s%s%%(%s)s" % (x, test, x) for x in vals.keys() if vals[x] != None]
|
# what = ["*"]
|
||||||
)
|
# operator = " " + operator + " "
|
||||||
cnuls = " and ".join(
|
# cond = " E.entreprise_id = C.entreprise_id "
|
||||||
["%s is NULL" % x for x in vals.keys() if vals[x] is None]
|
# if vals:
|
||||||
)
|
# cond += " where " + operator.join(
|
||||||
if cnuls:
|
# ["%s%s%%(%s)s" % (x, test, x) for x in vals.keys() if vals[x] != None]
|
||||||
cond = cond + " and " + cnuls
|
# )
|
||||||
else:
|
# cnuls = " and ".join(
|
||||||
cond += ""
|
# ["%s is NULL" % x for x in vals.keys() if vals[x] is None]
|
||||||
cursor.execute(
|
# )
|
||||||
"select distinct"
|
# if cnuls:
|
||||||
+ ", ".join(what)
|
# cond = cond + " and " + cnuls
|
||||||
+ " from entreprises E, entreprise_contact C "
|
# else:
|
||||||
+ cond
|
# cond += ""
|
||||||
+ orderby,
|
# cursor.execute(
|
||||||
vals,
|
# "select distinct"
|
||||||
)
|
# + ", ".join(what)
|
||||||
titles, res = [x[0] for x in cursor.description], cursor.fetchall()
|
# + " from entreprises E, entreprise_contact C "
|
||||||
#
|
# + cond
|
||||||
R = []
|
# + orderby,
|
||||||
for r in res:
|
# vals,
|
||||||
d = {}
|
# )
|
||||||
for i in range(len(titles)):
|
# titles, res = [x[0] for x in cursor.description], cursor.fetchall()
|
||||||
v = r[i]
|
# #
|
||||||
# value not formatted ! (see EditableTable.list())
|
# R = []
|
||||||
d[titles[i]] = v
|
# for r in res:
|
||||||
R.append(d)
|
# d = {}
|
||||||
return R
|
# 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
|
# -------- Formulaires: traductions du DTML
|
||||||
security.declareProtected(ScoEntrepriseChange, "entreprise_create")
|
security.declareProtected(ScoEntrepriseChange, "entreprise_create")
|
||||||
@ -892,7 +896,3 @@ def manage_addZEntreprises(
|
|||||||
if REQUEST is not None:
|
if REQUEST is not None:
|
||||||
return self.manage_main(self, REQUEST)
|
return self.manage_main(self, REQUEST)
|
||||||
# return self.manage_editForm(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())
|
|
||||||
|
17
ZScolar.py
17
ZScolar.py
@ -89,6 +89,7 @@ import ZEntreprises
|
|||||||
import ZScoUsers
|
import ZScoUsers
|
||||||
import sco_modalites
|
import sco_modalites
|
||||||
import ImportScolars
|
import ImportScolars
|
||||||
|
import sco_abs
|
||||||
import sco_portal_apogee
|
import sco_portal_apogee
|
||||||
import sco_synchro_etuds
|
import sco_synchro_etuds
|
||||||
import sco_page_etud
|
import sco_page_etud
|
||||||
@ -274,13 +275,13 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
"""
|
"""
|
||||||
return (
|
# return (
|
||||||
self.sco_header(REQUEST)
|
# self.sco_header(REQUEST)
|
||||||
+ """<div class="xp">%s</div>""" % x
|
# + """<div class="xp">%s</div>""" % x
|
||||||
+ self.sco_footer(REQUEST)
|
# + self.sco_footer(REQUEST)
|
||||||
)
|
# )
|
||||||
b = "<p>Hello, World !</p><br/>"
|
# b = "<p>Hello, World !</p><br/>"
|
||||||
raise ValueError("essai exception")
|
# raise ValueError("essai exception")
|
||||||
# raise ScoValueError('essai exception !', dest_url='totoro', REQUEST=REQUEST)
|
# raise ScoValueError('essai exception !', dest_url='totoro', REQUEST=REQUEST)
|
||||||
|
|
||||||
# cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
# cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
@ -592,7 +593,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
# calcule dates 1er jour semaine pour absences
|
# calcule dates 1er jour semaine pour absences
|
||||||
try:
|
try:
|
||||||
if with_absences:
|
if with_absences:
|
||||||
first_monday = ZAbsences.ddmmyyyy(sem["date_debut"]).prev_monday()
|
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
|
||||||
FA = [] # formulaire avec menu saisi absences
|
FA = [] # formulaire avec menu saisi absences
|
||||||
FA.append(
|
FA.append(
|
||||||
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">'
|
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">'
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
from ZAbsences import getAbsSemEtud
|
from sco_abs import getAbsSemEtud
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Génération de la "sidebar" (marge gauche des pages HTML)
|
Génération de la "sidebar" (marge gauche des pages HTML)
|
||||||
|
595
sco_abs.py
Normal file
595
sco_abs.py
Normal file
@ -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 = [
|
||||||
|
'<table id="maincalendar" class="maincalendar" border="3" cellpadding="1" cellspacing="1" frame="box">'
|
||||||
|
]
|
||||||
|
T.append("<tr>")
|
||||||
|
month = firstmonth
|
||||||
|
while 1:
|
||||||
|
T.append('<td valign="top">')
|
||||||
|
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("</td>")
|
||||||
|
if month == lastmonth:
|
||||||
|
break
|
||||||
|
month = month + 1
|
||||||
|
if month > 12:
|
||||||
|
month = 1
|
||||||
|
year = year + 1
|
||||||
|
T.append("</table>")
|
||||||
|
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 """<table class="monthcalendar" border="0" cellpadding="0" cellspacing="0" frame="box">
|
||||||
|
<tr bgcolor="%s"><td class="calcol" colspan="2" align="center">%s</td></tr>\n""" % (
|
||||||
|
color,
|
||||||
|
MONTHNAMES_ABREV[month - 1],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MonthTableTail():
|
||||||
|
return "</table>\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('<td bgcolor="%s" class="calcell">' % color)
|
||||||
|
else:
|
||||||
|
cc.append('<td class="calcell">')
|
||||||
|
|
||||||
|
if href:
|
||||||
|
href = 'href="%s"' % href
|
||||||
|
if descr:
|
||||||
|
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("<a %s %s>" % (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("</a>")
|
||||||
|
cc.append("</td>")
|
||||||
|
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(
|
||||||
|
'<tr bgcolor="%s" class="%s" %s><td class="calday">%d%s</td>%s</tr>'
|
||||||
|
% (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(
|
||||||
|
'<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>'
|
||||||
|
% (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('<td bgcolor="%s" class="calcell">' % (color))
|
||||||
|
else:
|
||||||
|
cc.append('<td class="calcell">')
|
||||||
|
if href:
|
||||||
|
href = 'href="%s"' % href
|
||||||
|
if descr:
|
||||||
|
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("<a %s %s>" % (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("</a>")
|
||||||
|
cc.append("</td>\n")
|
||||||
|
T.append(string.join(cc, "") + "</tr>")
|
||||||
|
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()
|
@ -40,7 +40,7 @@ import sco_find_etud
|
|||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_photos
|
import sco_photos
|
||||||
|
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
|
|
||||||
|
|
||||||
def doSignaleAbsence(
|
def doSignaleAbsence(
|
||||||
@ -631,7 +631,7 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||||||
events.append(
|
events.append(
|
||||||
(str(a["jour"]), "X", "#8EA2C6", "", a["matin"], a["description"])
|
(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 = [
|
H = [
|
||||||
|
@ -44,7 +44,7 @@ import sco_groups
|
|||||||
import sco_pvjury
|
import sco_pvjury
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_abs_views
|
import sco_abs_views
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
@ -150,7 +150,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
context, pid
|
context, pid
|
||||||
)
|
)
|
||||||
# --- Absences
|
# --- Absences
|
||||||
AbsSemEtud = ZAbsences.getAbsSemEtud(context, nt.sem, etudid)
|
AbsSemEtud = sco_abs.getAbsSemEtud(context, nt.sem, etudid)
|
||||||
I["nbabs"] = AbsSemEtud.CountAbs()
|
I["nbabs"] = AbsSemEtud.CountAbs()
|
||||||
I["nbabsjust"] = AbsSemEtud.CountAbsJust()
|
I["nbabsjust"] = AbsSemEtud.CountAbsJust()
|
||||||
|
|
||||||
|
@ -42,12 +42,22 @@ La préférence 'bul_pdf_class_name' est obsolete (inutilisée).
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
|
import cStringIO
|
||||||
import collections
|
import collections
|
||||||
|
import traceback
|
||||||
|
import reportlab
|
||||||
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||||
|
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||||
|
|
||||||
|
import sco_utils
|
||||||
|
import VERSION
|
||||||
|
from sco_exceptions import NoteProcessError
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
from sco_pdf import *
|
import sco_pdf
|
||||||
|
from sco_pdf import PDFLOCK
|
||||||
|
|
||||||
BULLETIN_CLASSES = (
|
BULLETIN_CLASSES = (
|
||||||
collections.OrderedDict()
|
collections.OrderedDict()
|
||||||
@ -145,7 +155,7 @@ class BulletinGenerator:
|
|||||||
dt,
|
dt,
|
||||||
self.infos["etud"]["nom"],
|
self.infos["etud"]["nom"],
|
||||||
)
|
)
|
||||||
filename = unescape_html(filename).replace(" ", "_").replace("&", "")
|
filename = sco_utils.unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def generate(self, format="", stand_alone=True):
|
def generate(self, format="", stand_alone=True):
|
||||||
@ -166,8 +176,10 @@ class BulletinGenerator:
|
|||||||
def generate_html(self):
|
def generate_html(self):
|
||||||
"""Return bulletin as an HTML string"""
|
"""Return bulletin as an HTML string"""
|
||||||
H = ['<div class="notes_bulletin">']
|
H = ['<div class="notes_bulletin">']
|
||||||
H.append(self.bul_table(format="html")) # table des notes
|
# table des notes:
|
||||||
H.append(self.bul_part_below(format="html")) # infos sous la table
|
H.append(self.bul_table(format="html")) # pylint: disable=no-member
|
||||||
|
# infos sous la table:
|
||||||
|
H.append(self.bul_part_below(format="html")) # pylint: disable=no-member
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
@ -179,10 +191,14 @@ class BulletinGenerator:
|
|||||||
"""
|
"""
|
||||||
formsemestre_id = self.infos["formsemestre_id"]
|
formsemestre_id = self.infos["formsemestre_id"]
|
||||||
|
|
||||||
objects = self.bul_title_pdf() # partie haute du bulletin
|
# partie haute du bulletin
|
||||||
objects += self.bul_table(format="pdf") # table des notes
|
objects = self.bul_title_pdf() # pylint: disable=no-member
|
||||||
objects += self.bul_part_below(format="pdf") # infos sous la table
|
# table des notes
|
||||||
objects += self.bul_signatures_pdf() # signatures
|
objects += self.bul_table(format="pdf") # pylint: disable=no-member
|
||||||
|
# infos sous la table
|
||||||
|
objects += self.bul_part_below(format="pdf") # pylint: disable=no-member
|
||||||
|
# signatures
|
||||||
|
objects += self.bul_signatures_pdf() # pylint: disable=no-member
|
||||||
|
|
||||||
# Réduit sur une page
|
# Réduit sur une page
|
||||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||||
@ -194,13 +210,13 @@ class BulletinGenerator:
|
|||||||
# Generation du document PDF
|
# Generation du document PDF
|
||||||
sem = sco_formsemestre.get_formsemestre(self.context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(self.context, formsemestre_id)
|
||||||
report = cStringIO.StringIO() # in-memory document, no disk file
|
report = cStringIO.StringIO() # in-memory document, no disk file
|
||||||
document = BaseDocTemplate(report)
|
document = sco_pdf.BaseDocTemplate(report)
|
||||||
document.addPageTemplates(
|
document.addPageTemplates(
|
||||||
ScolarsPageTemplate(
|
sco_pdf.ScolarsPageTemplate(
|
||||||
document,
|
document,
|
||||||
context=self.context,
|
context=self.context,
|
||||||
author="%s %s (E. Viennet) [%s]"
|
author="%s %s (E. Viennet) [%s]"
|
||||||
% (SCONAME, SCOVERSION, self.description),
|
% (VERSION.SCONAME, VERSION.SCOVERSION, self.description),
|
||||||
title="Bulletin %s de %s"
|
title="Bulletin %s de %s"
|
||||||
% (sem["titremois"], self.infos["etud"]["nomprenom"]),
|
% (sem["titremois"], self.infos["etud"]["nomprenom"]),
|
||||||
subject="Bulletin de note",
|
subject="Bulletin de note",
|
||||||
@ -222,7 +238,9 @@ class BulletinGenerator:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# put each table cell in a Paragraph
|
# put each table cell in a Paragraph
|
||||||
Pt = [[Paragraph(SU(x), self.CellStyle) for x in line] for line in P]
|
Pt = [
|
||||||
|
[Paragraph(sco_pdf.SU(x), self.CellStyle) for x in line] for line in P
|
||||||
|
]
|
||||||
except:
|
except:
|
||||||
# enquête sur exception intermittente...
|
# enquête sur exception intermittente...
|
||||||
log("*** bug in PDF buildTableObject:")
|
log("*** bug in PDF buildTableObject:")
|
||||||
|
@ -34,7 +34,7 @@ from notes_table import *
|
|||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
|
|
||||||
# -------- Bulletin en JSON
|
# -------- Bulletin en JSON
|
||||||
@ -321,7 +321,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||||
AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
nbabs = AbsEtudSem.CountAbs()
|
nbabs = AbsEtudSem.CountAbs()
|
||||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ from notes_table import *
|
|||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
|
|
||||||
# -------- Bulletin en XML
|
# -------- Bulletin en XML
|
||||||
@ -323,7 +323,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||||
AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
nbabs = AbsEtudSem.CountAbs()
|
nbabs = AbsEtudSem.CountAbs()
|
||||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||||
doc._push()
|
doc._push()
|
||||||
|
@ -37,7 +37,7 @@ import sco_formsemestre
|
|||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
from sco_formulas import *
|
from sco_formulas import *
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
|
|
||||||
|
|
||||||
def moduleimpl_has_expression(context, mod):
|
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)
|
Retourne moy, et en cas d'erreur met à jour diag_info (msg)
|
||||||
"""
|
"""
|
||||||
if use_abs:
|
if use_abs:
|
||||||
AbsSemEtud = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
AbsSemEtud = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
nbabs = AbsSemEtud.CountAbs()
|
nbabs = AbsSemEtud.CountAbs()
|
||||||
nbabs_just = AbsSemEtud.CountAbsJust()
|
nbabs_just = AbsSemEtud.CountAbsJust()
|
||||||
else:
|
else:
|
||||||
|
@ -42,7 +42,7 @@ from TrivialFormulator import TrivialFormulator
|
|||||||
import sco_news
|
import sco_news
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
@ -487,7 +487,7 @@ def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None):
|
|||||||
if day > today:
|
if day > today:
|
||||||
e[2] = color_futur
|
e[2] = color_futur
|
||||||
|
|
||||||
CalHTML = ZAbsences.YearTable(
|
CalHTML = sco_abs.YearTable(
|
||||||
context.Absences, year, events=events.values(), halfday=False, pad_width=None
|
context.Absences, year, events=events.values(), halfday=False, pad_width=None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ from notes_log import log
|
|||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from notes_table import *
|
from notes_table import *
|
||||||
import notes_table
|
import notes_table
|
||||||
from ZAbsences import getAbsSemEtud
|
from sco_abs import getAbsSemEtud
|
||||||
|
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_edit
|
import sco_formsemestre_edit
|
||||||
|
@ -35,7 +35,7 @@ from sco_utils import *
|
|||||||
import html_sco_header
|
import html_sco_header
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import scolars
|
import scolars
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_excel
|
import sco_excel
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
@ -870,7 +870,7 @@ def form_choix_jour_saisie_hebdo(
|
|||||||
if not authuser.has_permission(ScoAbsChange, context):
|
if not authuser.has_permission(ScoAbsChange, context):
|
||||||
return ""
|
return ""
|
||||||
sem = groups_infos.formsemestre
|
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()
|
today_idx = datetime.date.today().weekday()
|
||||||
|
|
||||||
FA = [] # formulaire avec menu saisi absences
|
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 !
|
) # car ici utilisee dans un format string !
|
||||||
|
|
||||||
DateJour = time.strftime("%d/%m/%Y")
|
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 = [] # formulaire avec menu saisi hebdo des absences
|
||||||
FA.append('<form action="Absences/SignaleAbsenceGrHebdo" method="get">')
|
FA.append('<form action="Absences/SignaleAbsenceGrHebdo" method="get">')
|
||||||
FA.append('<input type="hidden" name="datelundi" value="%s"/>' % datelundi)
|
FA.append('<input type="hidden" name="datelundi" value="%s"/>' % datelundi)
|
||||||
|
@ -43,7 +43,7 @@ import sco_formsemestre
|
|||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
from sco_formsemestre_status import makeMenu
|
from sco_formsemestre_status import makeMenu
|
||||||
import sco_compute_moy
|
import sco_compute_moy
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
|
|
||||||
# ported from old DTML code in oct 2009
|
# 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(
|
if authuser.has_permission(
|
||||||
ScoAbsChange, context
|
ScoAbsChange, context
|
||||||
) and sco_formsemestre.sem_est_courant(context, sem):
|
) 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(
|
H.append(
|
||||||
'<span class="moduleimpl_abs_link"><a class="stdlink" href="Absences/SignaleAbsenceGrHebdo?formsemestre_id=%s&moduleimpl_id=%s&datelundi=%s">Saisie Absences hebdo.</a></span>'
|
'<span class="moduleimpl_abs_link"><a class="stdlink" href="Absences/SignaleAbsenceGrHebdo?formsemestre_id=%s&moduleimpl_id=%s&datelundi=%s">Saisie Absences hebdo.</a></span>'
|
||||||
% (formsemestre_id, moduleimpl_id, datelundi)
|
% (formsemestre_id, moduleimpl_id, datelundi)
|
||||||
|
@ -36,7 +36,7 @@ from notes_log import log
|
|||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
from sco_codes_parcours import code_semestre_validant, code_semestre_attente
|
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])
|
rangs.append(["rang_" + codeModule, rangModule])
|
||||||
|
|
||||||
# Absences
|
# Absences
|
||||||
AbsSemEtud = ZAbsences.getAbsSemEtud(context, nt.sem, etudid)
|
AbsSemEtud = sco_abs.getAbsSemEtud(context, nt.sem, etudid)
|
||||||
NbAbs = AbsSemEtud.CountAbs()
|
NbAbs = AbsSemEtud.CountAbs()
|
||||||
NbAbsJust = AbsSemEtud.CountAbsJust()
|
NbAbsJust = AbsSemEtud.CountAbsJust()
|
||||||
if (
|
if (
|
||||||
|
@ -38,7 +38,7 @@ import sco_formsemestre
|
|||||||
import sco_parcours_dut
|
import sco_parcours_dut
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
from scolars import format_nom, format_prenom, format_sexe, format_lycee
|
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):
|
def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||||
|
@ -29,16 +29,22 @@
|
|||||||
- statistiques decisions
|
- statistiques decisions
|
||||||
- suivi cohortes
|
- suivi cohortes
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import urllib
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import mx
|
||||||
import mx.DateTime
|
import mx.DateTime
|
||||||
from mx.DateTime import DateTime as mxDateTime
|
from mx.DateTime import DateTime as mxDateTime
|
||||||
import tempfile, urllib, re
|
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import VERSION
|
||||||
from sco_utils import *
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_excel, sco_pdf
|
import sco_excel, sco_pdf
|
||||||
|
from notesdb import DateDMYtoISO
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
from sco_codes_parcours import code_semestre_validant
|
from sco_codes_parcours import code_semestre_validant
|
||||||
import sco_parcours_dut
|
import sco_parcours_dut
|
||||||
@ -129,7 +135,7 @@ def _results_by_category(
|
|||||||
if Count.has_key(etud[category]):
|
if Count.has_key(etud[category]):
|
||||||
Count[etud[category]][etud[result]] += 1
|
Count[etud[category]][etud[result]] += 1
|
||||||
else:
|
else:
|
||||||
Count[etud[category]] = DictDefault(kv_dict={etud[result]: 1})
|
Count[etud[category]] = scu.DictDefault(kv_dict={etud[result]: 1})
|
||||||
# conversion en liste de dict
|
# conversion en liste de dict
|
||||||
C = [Count[cat] for cat in categories]
|
C = [Count[cat] for cat in categories]
|
||||||
# Totaux par lignes et colonnes
|
# Totaux par lignes et colonnes
|
||||||
@ -214,9 +220,9 @@ def formsemestre_report(
|
|||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
tab.filename = make_filename("stats " + sem["titreannee"])
|
tab.filename = scu.make_filename("stats " + sem["titreannee"])
|
||||||
|
|
||||||
tab.origin = "Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + ""
|
tab.origin = "Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + ""
|
||||||
tab.caption = "Répartition des résultats par %s, semestre %s" % (
|
tab.caption = "Répartition des résultats par %s, semestre %s" % (
|
||||||
category_name,
|
category_name,
|
||||||
sem["titreannee"],
|
sem["titreannee"],
|
||||||
@ -259,7 +265,7 @@ def formsemestre_report_counts(
|
|||||||
Tableau comptage avec choix des categories
|
Tableau comptage avec choix des categories
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
category_name = strcapitalize(category)
|
category_name = scu.strcapitalize(category)
|
||||||
title = "Comptages " + category_name
|
title = "Comptages " + category_name
|
||||||
etuds = formsemestre_etuds_stats(context, sem, only_primo=only_primo)
|
etuds = formsemestre_etuds_stats(context, sem, only_primo=only_primo)
|
||||||
tab = formsemestre_report(
|
tab = formsemestre_report(
|
||||||
@ -484,7 +490,7 @@ def table_suivi_cohorte(
|
|||||||
indices_sems.sort()
|
indices_sems.sort()
|
||||||
for p in P:
|
for p in P:
|
||||||
p.nb_etuds = 0 # nombre total d'etudiants dans la periode
|
p.nb_etuds = 0 # nombre total d'etudiants dans la periode
|
||||||
p.sems_by_id = DictDefault(defaultvalue=[])
|
p.sems_by_id = scu.DictDefault(defaultvalue=[])
|
||||||
for s in p.sems:
|
for s in p.sems:
|
||||||
p.sems_by_id[s["semestre_id"]].append(s)
|
p.sems_by_id[s["semestre_id"]].append(s)
|
||||||
p.nb_etuds += len(s["members"])
|
p.nb_etuds += len(s["members"])
|
||||||
@ -623,8 +629,8 @@ def table_suivi_cohorte(
|
|||||||
rows=L,
|
rows=L,
|
||||||
html_col_width="4em",
|
html_col_width="4em",
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
filename=make_filename("cohorte " + sem["titreannee"]),
|
filename=scu.make_filename("cohorte " + sem["titreannee"]),
|
||||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||||
caption="Suivi cohorte " + pp + sem["titreannee"] + dbac,
|
caption="Suivi cohorte " + pp + sem["titreannee"] + dbac,
|
||||||
page_title="Suivi cohorte " + sem["titreannee"],
|
page_title="Suivi cohorte " + sem["titreannee"],
|
||||||
html_class="table_cohorte",
|
html_class="table_cohorte",
|
||||||
@ -666,7 +672,6 @@ def formsemestre_suivi_cohorte(
|
|||||||
):
|
):
|
||||||
"""Affiche suivi cohortes par numero de semestre"""
|
"""Affiche suivi cohortes par numero de semestre"""
|
||||||
percent = int(percent)
|
percent = int(percent)
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
|
||||||
tab, expl, bacs, bacspecialites, annee_bacs, sexes, statuts = table_suivi_cohorte(
|
tab, expl, bacs, bacspecialites, annee_bacs, sexes, statuts = table_suivi_cohorte(
|
||||||
context,
|
context,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
@ -1049,7 +1054,7 @@ def table_suivi_parcours(
|
|||||||
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
||||||
context, formsemestre_id, only_primo=only_primo
|
context, formsemestre_id, only_primo=only_primo
|
||||||
)
|
)
|
||||||
codes_etuds = DictDefault(defaultvalue=[])
|
codes_etuds = scu.DictDefault(defaultvalue=[])
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
etud["codeparcours"], etud["decisions_jury"] = get_codeparcoursetud(
|
etud["codeparcours"], etud["decisions_jury"] = get_codeparcoursetud(
|
||||||
context, etud
|
context, etud
|
||||||
@ -1105,7 +1110,7 @@ def table_suivi_parcours(
|
|||||||
columns_ids=columns_ids,
|
columns_ids=columns_ids,
|
||||||
rows=L,
|
rows=L,
|
||||||
titles=titles,
|
titles=titles,
|
||||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||||
caption="Parcours suivis, étudiants %s semestre " % primostr
|
caption="Parcours suivis, étudiants %s semestre " % primostr
|
||||||
+ sem["titreannee"],
|
+ sem["titreannee"],
|
||||||
page_title="Parcours " + sem["titreannee"],
|
page_title="Parcours " + sem["titreannee"],
|
||||||
@ -1164,7 +1169,6 @@ def formsemestre_suivi_parcours(
|
|||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
):
|
):
|
||||||
"""Effectifs dans les differents parcours possibles."""
|
"""Effectifs dans les differents parcours possibles."""
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
|
||||||
tab = table_suivi_parcours(
|
tab = table_suivi_parcours(
|
||||||
context,
|
context,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
@ -1211,9 +1215,8 @@ def graph_parcours(
|
|||||||
statut="",
|
statut="",
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
if not WITH_PYDOT:
|
if not scu.WITH_PYDOT:
|
||||||
raise ScoValueError("pydot module is not installed")
|
raise ScoValueError("pydot module is not installed")
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
|
||||||
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
||||||
context,
|
context,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
@ -1227,12 +1230,12 @@ def graph_parcours(
|
|||||||
# log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo))
|
# log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo))
|
||||||
if not etuds:
|
if not etuds:
|
||||||
return "", etuds, bacs, bacspecialites, annee_bacs, sexes, statuts
|
return "", etuds, bacs, bacspecialites, annee_bacs, sexes, statuts
|
||||||
edges = DictDefault(
|
edges = scu.DictDefault(
|
||||||
defaultvalue=set()
|
defaultvalue=set()
|
||||||
) # {(formsemestre_id_origin, formsemestre_id_dest) : etud_set}
|
) # {(formsemestre_id_origin, formsemestre_id_dest) : etud_set}
|
||||||
sems = {}
|
sems = {}
|
||||||
effectifs = DictDefault(defaultvalue=set()) # formsemestre_id : etud_set
|
effectifs = scu.DictDefault(defaultvalue=set()) # formsemestre_id : etud_set
|
||||||
decisions = DictDefault(defaultvalue={}) # formsemestre_id : { code : nb_etud }
|
decisions = scu.DictDefault(defaultvalue={}) # formsemestre_id : { code : nb_etud }
|
||||||
isolated_nodes = []
|
isolated_nodes = []
|
||||||
connected_nodes = set()
|
connected_nodes = set()
|
||||||
diploma_nodes = []
|
diploma_nodes = []
|
||||||
@ -1279,7 +1282,11 @@ def graph_parcours(
|
|||||||
dem_nodes[s["formsemestre_id"]] = nid
|
dem_nodes[s["formsemestre_id"]] = nid
|
||||||
edges[(s["formsemestre_id"], nid)].add(etudid)
|
edges[(s["formsemestre_id"], nid)].add(etudid)
|
||||||
# ajout noeud pour NAR (seulement pour noeud de depart)
|
# ajout noeud pour NAR (seulement pour noeud de depart)
|
||||||
if s["formsemestre_id"] == formsemestre_id and dec and dec["code"] == NAR:
|
if (
|
||||||
|
s["formsemestre_id"] == formsemestre_id
|
||||||
|
and dec
|
||||||
|
and dec["code"] == sco_codes_parcours.NAR
|
||||||
|
):
|
||||||
nid = "_nar_" + s["formsemestre_id"]
|
nid = "_nar_" + s["formsemestre_id"]
|
||||||
nar_nodes[s["formsemestre_id"]] = nid
|
nar_nodes[s["formsemestre_id"]] = nid
|
||||||
edges[(s["formsemestre_id"], nid)].add(etudid)
|
edges[(s["formsemestre_id"], nid)].add(etudid)
|
||||||
@ -1295,10 +1302,10 @@ def graph_parcours(
|
|||||||
edges[(s["formsemestre_id"], nid)].add(etudid)
|
edges[(s["formsemestre_id"], nid)].add(etudid)
|
||||||
diploma_nodes.append(nid)
|
diploma_nodes.append(nid)
|
||||||
#
|
#
|
||||||
g = pydot.graph_from_edges(edges.keys())
|
g = scu.pydot.graph_from_edges(edges.keys())
|
||||||
for fid in isolated_nodes:
|
for fid in isolated_nodes:
|
||||||
if not fid in connected_nodes:
|
if not fid in connected_nodes:
|
||||||
n = pydot.Node(name=fid)
|
n = scu.pydot.Node(name=fid)
|
||||||
g.add_node(n)
|
g.add_node(n)
|
||||||
g.set("rankdir", "LR") # left to right
|
g.set("rankdir", "LR") # left to right
|
||||||
g.set_fontname("Helvetica")
|
g.set_fontname("Helvetica")
|
||||||
@ -1306,7 +1313,7 @@ def graph_parcours(
|
|||||||
g.set_bgcolor("#fffff0") # ou 'transparent'
|
g.set_bgcolor("#fffff0") # ou 'transparent'
|
||||||
# titres des semestres:
|
# titres des semestres:
|
||||||
for s in sems.values():
|
for s in sems.values():
|
||||||
n = pydot_get_node(g, s["formsemestre_id"])
|
n = scu.pydot_get_node(g, s["formsemestre_id"])
|
||||||
log("s['formsemestre_id'] = %s" % s["formsemestre_id"])
|
log("s['formsemestre_id'] = %s" % s["formsemestre_id"])
|
||||||
log("n=%s" % n)
|
log("n=%s" % n)
|
||||||
log("get=%s" % g.get_node(s["formsemestre_id"]))
|
log("get=%s" % g.get_node(s["formsemestre_id"]))
|
||||||
@ -1324,31 +1331,31 @@ def graph_parcours(
|
|||||||
s["annee_fin"][2:],
|
s["annee_fin"][2:],
|
||||||
len(effectifs[s["formsemestre_id"]]),
|
len(effectifs[s["formsemestre_id"]]),
|
||||||
)
|
)
|
||||||
n.set("label", suppress_accents(label))
|
n.set("label", scu.suppress_accents(label))
|
||||||
n.set_fontname("Helvetica")
|
n.set_fontname("Helvetica")
|
||||||
n.set_fontsize(8.0)
|
n.set_fontsize(8.0)
|
||||||
n.set_width(1.2)
|
n.set_width(1.2)
|
||||||
n.set_shape("box")
|
n.set_shape("box")
|
||||||
n.set_URL("formsemestre_status?formsemestre_id=" + s["formsemestre_id"])
|
n.set_URL("formsemestre_status?formsemestre_id=" + s["formsemestre_id"])
|
||||||
# semestre de depart en vert
|
# semestre de depart en vert
|
||||||
n = pydot_get_node(g, formsemestre_id)
|
n = scu.pydot_get_node(g, formsemestre_id)
|
||||||
n.set_color("green")
|
n.set_color("green")
|
||||||
# demissions en rouge, octagonal
|
# demissions en rouge, octagonal
|
||||||
for nid in dem_nodes.values():
|
for nid in dem_nodes.values():
|
||||||
n = pydot_get_node(g, nid)
|
n = scu.pydot_get_node(g, nid)
|
||||||
n.set_color("red")
|
n.set_color("red")
|
||||||
n.set_shape("octagon")
|
n.set_shape("octagon")
|
||||||
n.set("label", "Dem.")
|
n.set("label", "Dem.")
|
||||||
|
|
||||||
# NAR en rouge, Mcircle
|
# NAR en rouge, Mcircle
|
||||||
for nid in nar_nodes.values():
|
for nid in nar_nodes.values():
|
||||||
n = pydot_get_node(g, nid)
|
n = scu.pydot_get_node(g, nid)
|
||||||
n.set_color("red")
|
n.set_color("red")
|
||||||
n.set_shape("Mcircle")
|
n.set_shape("Mcircle")
|
||||||
n.set("label", NAR)
|
n.set("label", sco_codes_parcours.NAR)
|
||||||
# diplomes:
|
# diplomes:
|
||||||
for nid in diploma_nodes:
|
for nid in diploma_nodes:
|
||||||
n = pydot_get_node(g, nid)
|
n = scu.pydot_get_node(g, nid)
|
||||||
n.set_color("red")
|
n.set_color("red")
|
||||||
n.set_shape("ellipse")
|
n.set_shape("ellipse")
|
||||||
n.set("label", "Diplome") # bug si accent (pas compris pourquoi)
|
n.set("label", "Diplome") # bug si accent (pas compris pourquoi)
|
||||||
@ -1367,7 +1374,7 @@ def graph_parcours(
|
|||||||
bubbles[src_id + ":" + dst_id] = etud_descr
|
bubbles[src_id + ":" + dst_id] = etud_descr
|
||||||
e.set_URL("__xxxetudlist__?" + src_id + ":" + dst_id)
|
e.set_URL("__xxxetudlist__?" + src_id + ":" + dst_id)
|
||||||
# Genere graphe
|
# Genere graphe
|
||||||
f, path = tempfile.mkstemp(".gr")
|
_, path = tempfile.mkstemp(".gr")
|
||||||
g.write(path=path, format=format)
|
g.write(path=path, format=format)
|
||||||
data = open(path, "r").read()
|
data = open(path, "r").read()
|
||||||
log("dot generated %d bytes in %s format" % (len(data), format))
|
log("dot generated %d bytes in %s format" % (len(data), format))
|
||||||
@ -1403,7 +1410,7 @@ def graph_parcours(
|
|||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
'<a xlink:href="formsemestre_status?formsemestre_id=%s" xlink:title="%s"'
|
'<a xlink:href="formsemestre_status?formsemestre_id=%s" xlink:title="%s"'
|
||||||
% (fid, suppress_accents(title))
|
% (fid, scu.suppress_accents(title))
|
||||||
) # evite accents car svg utf-8 vs page en latin1...
|
) # evite accents car svg utf-8 vs page en latin1...
|
||||||
|
|
||||||
data = exp1.sub(repl_title, data)
|
data = exp1.sub(repl_title, data)
|
||||||
@ -1443,8 +1450,8 @@ def formsemestre_graph_parcours(
|
|||||||
sexe=sexe,
|
sexe=sexe,
|
||||||
statut=statut,
|
statut=statut,
|
||||||
)
|
)
|
||||||
filename = make_filename("flux " + sem["titreannee"])
|
filename = scu.make_filename("flux " + sem["titreannee"])
|
||||||
return sco_pdf.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
||||||
elif format == "png":
|
elif format == "png":
|
||||||
#
|
#
|
||||||
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours(
|
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours(
|
||||||
@ -1458,7 +1465,7 @@ def formsemestre_graph_parcours(
|
|||||||
sexe=sexe,
|
sexe=sexe,
|
||||||
statut=statut,
|
statut=statut,
|
||||||
)
|
)
|
||||||
filename = make_filename("flux " + sem["titreannee"])
|
filename = scu.make_filename("flux " + sem["titreannee"])
|
||||||
REQUEST.RESPONSE.setHeader(
|
REQUEST.RESPONSE.setHeader(
|
||||||
"content-disposition", 'attachment; filename="%s"' % filename
|
"content-disposition", 'attachment; filename="%s"' % filename
|
||||||
)
|
)
|
||||||
|
@ -40,7 +40,7 @@ import tempfile
|
|||||||
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import scolars
|
import scolars
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
@ -301,9 +301,9 @@ def pdf_feuille_releve_absences(
|
|||||||
NB_CELL_PM = context.get_preference("feuille_releve_abs_PM")
|
NB_CELL_PM = context.get_preference("feuille_releve_abs_PM")
|
||||||
COLWIDTH = 0.85 * cm
|
COLWIDTH = 0.85 * cm
|
||||||
if context.get_preference("feuille_releve_abs_samedi"):
|
if context.get_preference("feuille_releve_abs_samedi"):
|
||||||
days = ZAbsences.DAYNAMES[:6] # Lundi, ..., Samedi
|
days = sco_abs.DAYNAMES[:6] # Lundi, ..., Samedi
|
||||||
else:
|
else:
|
||||||
days = ZAbsences.DAYNAMES[:5] # Lundi, ..., Vendredi
|
days = sco_abs.DAYNAMES[:5] # Lundi, ..., Vendredi
|
||||||
nb_days = len(days)
|
nb_days = len(days)
|
||||||
|
|
||||||
# Informations sur les groupes à afficher:
|
# Informations sur les groupes à afficher:
|
||||||
|
Loading…
Reference in New Issue
Block a user