Commit 89e6d8bd authored by Praibait's avatar Praibait

Refonte de la page d'entrée des pot + notation des entrées dans la table...

Refonte de la page d'entrée des pot + notation des entrées dans la table entree_activites (+backend)
parent c6c63945
......@@ -113,6 +113,30 @@ def search_readhesion(request):
return response
@csrf_exempt
def do_entree_pot(request):
"""Renvoie l'objet JSON résultat d'un search,
destiné à être chargé par javascript"""
if (request.method == "GET") or (request.session.get("logged", None) != "ok"):
return HttpResponse("Get the fuck out of here", status=444)
else:
try:
entree = request.POST["entree"]
entree = json.loads(entree)
except:
return HttpResponse(entree)
success, sock_ou_response = nk.socket_still_alive(request)
if success:
sock = sock_ou_response
sock.write(json.dumps(["do_entree_pot", entree]))
out = nk.full_read(sock)["msg"]
return HttpResponse(json.dumps(out))
else:
response = sock_ou_response
return response
@csrf_exempt
def get_boutons(request, flags=""):
"""Renvoie l'objet JSON résultat d'un get_boutons,
......
No preview for this file type
No preview for this file type
......@@ -102,7 +102,7 @@ DEFAULT_LANGUAGE = 1
LOCALE_PATHS = [
os.path.join(ROOT_PATH, 'locale/'),
os.path.join(PROJECT_PATH, 'static/js/custom/locale/'),
os.path.join(PROJECT_PATH, '../static/js/custom/locale/'),
]
#: If you set this to False, Django will not format dates, numbers and
......
No preview for this file type
......@@ -31,7 +31,6 @@
<li> Affichage des pots à venir </li>
<li> Page d'entrée d'un pot : <br>
<ul>
<li> Onglet de note des entrées</li>
<li> Onglet de crédit</li>
<li> Onglet de transfert</li>
</ul>
......@@ -42,7 +41,7 @@
<p><h4> TODO : </h4></p>
<ul>
<li>Onglet de gestion des invités</li>
<li>Onglet de gestion des entrées</li>
<li>Possibilité de ne noter qu'une seule entrée par [Pot]. (message d'erreur)</li>
<li>Impossibilité de noter une entrée à quelqu'un en négatif (garder le nom dans le stack + message d'erreur))</li>
<li>Possibilité de faire les entrées uniquement quand le [Pot] est ouvert : sur la base d'horaires ou par ouverture/fermeture par un admin</li>
......
......@@ -12,6 +12,7 @@
<script src="{{ STATIC_URL }}js/custom/consos_base.js"></script>
<script src="{{ STATIC_URL }}js/custom/gestion_pot.js"></script>
<script src="{{ STATIC_URL }}js/custom/toggle_transactions.js"></script>
<script src="{{ STATIC_URL }}js/custom/liste_dynamique_search_pot.js"></script>
{% endblock %}
......@@ -19,106 +20,125 @@
<li role="presentation" class="active"><a onclick="set_conso(this)" class="entree">Entrées</a></li>
<li role="presentation"><a onclick="set_conso(this)" class="credit">Crédit</a></li>
<li role="presentation"><a onclick="set_conso(this)" class="transfert">Transfert</a></li>
<li role="presentation"><a onclick="set_conso(this)" class="invites">Invités</a></li>
<li role="presentation"><a href="{{ NOTE_ROOT_URL }}pot/">Accueil</a></li>
{% endblock %}
{% block content %}
<h1><i>{{ nompot }}</i></h1>
<h5><i>{% if commence %}<div style="color:green">En cours <br> Reste {{ tempsrestant }}</div>{% elif fini %}<div style="color:red">Fini</div>{% else %}<div style="color:grey">Pas encore commencé</div>{% endif %}</i></h5>
<h1>{{ nompot }}</h1>
<h5><i>{% if encours %}<div style="color:green">En cours<br> Reste {{ tempsrestant }}</div>{% elif fini %}<div style="color:red">Fini</div>{% else %}<div style="color:grey">Pas encore commencé</div>{% endif %}</i></h5>
<input type="hidden" id="idpot" name="idpot" value="{{ idpot }}"> <!-- Permet d'accéder facilement à l'id du pot dans le js-->
<br>
<br>
<div id="tab-frame" class="row">
<!-- Tout ce qui concerne l'entrée -->
<div class="entree">
<div class="well center-block">
<div class="search2 search">
<input type="text" name="Recherche" id="id_search_field_compte" autocomplete="off" onkeyup="search_field_moved_compte()"/>
</div>
</div>
<div class="col-xs-4 col-sm-4 col-lg-3" style="width:20%"></div>
<div id="note_container_1" class="note_container col-xs-4 col-sm-4 col-lg-2" style="width:18%">
<div style="height:50px"></div>
<div class="stack_container">
<span id="stack_label" class="hidden">{% trans "Emetteurs :" %}</span>
<ul id="stack" class="list-unstyled">
<li></li>
</ul>
</div>
<div class="search">
<input type="text" name="Recherche" id="id_search_field" autofocus="autofocus"
placeholder="{% trans "Chercher une note…" %}" onkeyup="search_field_moved();return(false);"/>
<ul class="liste_notes hidden" id="liste_notes">
</ul>
</div>
</div>
<div id="liste_comptes" class="panel panel-default table-responsive hidden">
<table class="table table-condensed table-bordered">
</table>
</div>
</div>
<!-- Tout ce qui concerne les transferts et credits -->
<div class="transfert credit hidden">
<!-- Quicksearch principale -->
<div class="col-xs-4 col-sm-4 col-lg-3" style="width:20%"></div>
<div id="note_container_1" class="note_container col-xs-4 col-sm-4 col-lg-2" style="width:18%">
<div style="height:50px"></div>
<div class="stack_container">
<span id="stack_label" class="hidden">{% trans "Emetteurs :" %}</span>
<ul id="stack" class="list-unstyled">
<li></li>
</ul>
</div>
<div class="search">
<input type="text" name="Recherche" id="id_search_field" autofocus="autofocus" placeholder="{% trans "Chercher une note…" %}" onkeyup="search_field_moved();return(false);"/>
<ul class="liste_notes hidden" id="liste_notes">
</ul>
</div>
</div>
<!-- Panneau d'affichage des notes -->
<div class="current_selection col-xs-4 col-sm-4 col-lg-3">
<div class="curr well">
<p>{% trans "Sélection :" %}</p>
<p id="current_selection"></p>
</div>
<!-- Formulaire de transferts -->
<div class="transfert hidden">
<div id="transfert" class="col-lg-13">
<button class="btn btn-primary transfert_conso_double hidden" onClick="transfert_switch_notes();">{% trans "Inverser" %}</button>
<form onsubmit="transfert_pot('{{ nompot }}'); return false;">
<div class="col-lg-9">
<legend class="hidden">
<span class="transfert_conso_double">
<span id="transfert_emetteur"></span>
<span id="transfert_destinataire"></span>
</span>
</legend>
{{ transfert_form.as_p }}
</div>
<div style="height:20px"></div>
<input type="submit" class="btn btn-primary" value="{% trans "Ok" %}"/>
</form>
</div>
</div>
<!-- Cas où on est sur l'onglet entrées -->
<div class="current_selection col-xs-4 col-sm-4 col-lg-3">
<div class="curr well">
<p>{% trans "Sélection :" %}</p>
<p id="current_selection"></p>
</div>
<!-- Deuxième quicksearch pour les transferts -->
<div class="transfert hidden">
<div id="transfert" class="col-lg-13">
<button class="btn btn-primary transfert_conso_double hidden" onClick="transfert_switch_notes();">{% trans "Inverser" %}</button>
<form onsubmit="transfert_pot('{{ nompot }}'); return false;">
<div class="col-lg-9">
<legend class="hidden"><span class="transfert_conso_double"><span id="transfert_emetteur"></span><span id="transfert_destinataire"></span></span></legend>
{{ transfert_form.as_p }}
</div>
<div style="height:20px"></div>
<input type="submit" class="btn btn-primary" value="{% trans "Ok" %}"/>
</form>
<div id="note_container_2" class="note_container col-xs-4 col-sm-4 col-lg-2" style="width:18%">
<div style="height:50px"></div>
<div class="stack_container" id="stack_container_2">
<span id="stack_label_2" class="hidden">{% trans "Destinataires :" %}</span>
<ul id="stack_2" class="list-unstyled">
</ul>
</div>
<div class="search" id ="search_2">
<input type="text" name="Recherche" id="id_search_field_2" placeholder="{% trans "Chercher une note…" %}" onkeyup="search_field_moved(true);return(false);"/>
<ul class="liste_notes hidden" id="liste_notes_2">
</ul>
</div>
</div>
</div>
</div>
<div class="entree">
<div class="current_selection col-xs-4 col-sm-4 col-lg-2">
<div style="height:105px"></div>
<div id="entreepot" class="">
<button class="btn btn-primary" onclick="do_entree_pot()">{% trans "Faire entrer !" %}</button>
</div>
</div>
</div>
<!-- Cas où on est sur l'onglet transfert -->
<div class="transfert hidden">
<div id="note_container_2" class="note_container col-xs-4 col-sm-4 col-lg-2" style="width:18%">
<div style="height:50px"></div>
<div class="stack_container" id="stack_container_2">
<span id="stack_label_2" class="hidden">{% trans "Destinataires :" %}</span>
<ul id="stack_2" class="list-unstyled">
</ul>
</div>
<div class="search" id ="search_2">
<input type="text" name="Recherche" id="id_search_field_2"
placeholder="{% trans "Chercher une note…" %}" onkeyup="search_field_moved(true);return(false);"/>
<ul class="liste_notes hidden" id="liste_notes_2">
</ul>
</div>
<!-- Formulaire de crédit -->
<div class="credit hidden">
<div id="credit" class="col-lg-4">
<form onsubmit="crediter_ou_retirer(true); return false;" class="col-lg-offset-1 col-lg-10"> {# true = crédit #}
<legend class="hidden">{% trans "créditer" %}<span id="credit_pseudo"><span></span></span>{% trans " :" %}</legend>
{{ credit_form.as_p }}
<input type="submit" class="btn btn-primary" value="{% trans "créditer" %}"/>
</form>
</div>
</div>
</div>
<!-- Cas où on est sur l'onglet crédit-->
<div class="credit hidden">
<div id="credit" class="col-lg-4">
<form onsubmit="crediter_ou_retirer(true); return false;" class="col-lg-offset-1 col-lg-10"> {# true = crédit #}
<legend class="hidden">{% trans "Créditer" %}<span id="credit_pseudo"><span></span></span>{% trans " :" %}</legend>
{{ credit_form.as_p }}
<input type="submit" class="btn btn-primary" value="{% trans "Créditer" %}"/>
</form>
</div>
</div>
<!--Formulaire caché qui est là uniquement pour faire marcher le script js de base-->
<div id="retrait" class="tab-panel">
<form onsubmit="crediter_ou_retirer(false); return false;" class="col-lg-offset-1 col-lg-10"> {# false = retrait #}
<legend>{% trans "Retirer de l'argent à" %}<span id="retrait_pseudo"><span></span></span>{% trans " :" %}</legend>
{{ retrait_form.as_p }}
<input type="submit" class="btn btn-primary" value="{% trans "Retirer" %}"/>
</form>
</div>
<!--Formulaire caché qui est là uniquement pour faire marcher le script js de base-->
<div id="retrait" class="tab-panel">
<form onsubmit="crediter_ou_retirer(false); return false;" class="col-lg-offset-1 col-lg-10"> {# false = retrait #}
<legend>{% trans "Retirer de l'argent à" %}<span id="retrait_pseudo"><span></span></span>{% trans " :" %}</legend>
{{ retrait_form.as_p }}
<input type="submit" class="btn btn-primary" value="{% trans "Retirer" %}"/>
</form>
</div>
</div>
</div>
<!-- L'historique des transactions ne concerne que les onglets transfert et credit -->
<div class="transfert credit hidden">
{% include "note/template_historique_pot.html" %}
</div>
{% endblock %}
......@@ -95,6 +95,7 @@ urlpatterns += patterns('note.ajaj',
url(ur'^/do_conso/*$', 'do_conso'),
url(ur'^/do_(?P<action>credit|retrait)/*$', 'do_credit_retrait'),
url(ur'^/do_transfert/*$', 'do_transfert'),
url(ur'^/do_entree_pot/*$', 'do_entree_pot'),
url(ur'^/consos/toggle_transaction/*$', 'toggle_transaction'),
)
......
No preview for this file type
No preview for this file type
......@@ -2120,8 +2120,15 @@ def pot_entree(request,sock,kwargs):
idpot = int(kwargs["idpot"])
pot = utilities._get_activite(sock, idpot, request, '%spot/' % (settings.NOTE_ROOT_URL))
variables["commence"] = datetime.now() > datetime.strptime(pot["debut"], "%Y-%m-%d %H:%M:%S")
variables["fini"] = datetime.now() > datetime.strptime(pot["fin"], "%Y-%m-%d %H:%M:%S")
variables["encours"] = datetime.now() > datetime.strptime(pot["debut"], "%Y-%m-%d %H:%M:%S") and not variables["fini"]
tpsrestant = datetime.strptime(pot["fin"], "%Y-%m-%d %H:%M:%S") - datetime.now()
hours, remainder = divmod(tpsrestant.seconds, 3600)
minutes, seconds = divmod(remainder, 60)
variables["tempsrestant"] = "{}h {}min {}s".format(hours, minutes, seconds)
variables["idpot"] = idpot
variables["nompot"] = pot["titre"]
......
No preview for this file type
......@@ -469,7 +469,7 @@ function cleanForms() {
function do_conso_many_boutons(idbde, matching_term) {
// On se prépare à poster une requête
var xhr = getXMLHttpRequest();
// On définit ce qu'on fera quand on recevra la réponse = gestion de l'éventuelle erreur
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
......@@ -533,7 +533,7 @@ function do_conso_many_boutons(idbde, matching_term) {
function do_conso_many_notes(idbut, labelbut) {
// On se prépare à poster une requête
var xhr = getXMLHttpRequest();
// On définit ce qu'on fera quand on recevra la réponse = gestion de l'éventuelle erreur
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
......@@ -849,7 +849,7 @@ function transferer() {
}
emetteurs = temp[1];
destinataires = temp[2];
// On se prépare à poster une requête
var xhr = getXMLHttpRequest();
// On définit ce qu'on fera quand on recevra la réponse = gestion de l'éventuelle erreur
......
......@@ -16,9 +16,8 @@ for (var i=0; i<2; i++) {
champ.lastChild.placeholder = ["Montant", "Motif"][i] + " du transfert"; // Information sur la qualité du champ
}
/* Fonction appelée lors du clique sur un des onglet à gauche. Elle s'occupe de modifier l'affichage de la page et l'état de variables associées.
Le paramètre onglet correspond à l'onglet sur lequel on a cliqué. */
onglet correspond à l'onglet sur lequel on a cliqué. */
function set_conso(onglet) {
ongletParent = onglet.parentNode
......@@ -44,7 +43,7 @@ function set_conso(onglet) {
add = document.querySelectorAll("div." + newCategorie);
for (var i=0; i<add.length; i++) {
add[i].className = newCategorie;
add[i].className = add[i].className.replace(" hidden","");
}
if (newCategorie == "transfert") {
......@@ -73,8 +72,7 @@ function transfert_pot(nomPot) {
}
/* Fonction appelée au changement du type de paiement dans l'onglet crédit. Elle affiche ou cache les champs nom, prenom et banque selon le type de paiement.
La variable this correspond à la liste déroulante des types de paiements. */
/* Fonction appelée au changement du type de paiement dans l'onglet crédit. Elle affiche ou cache les champs nom, prenom et banque selon le type de paiement. */
function bank_or_not_bank() {
if (this.value == "cheque" || this.value == "virement") {
......
/* Script JS qui permet d'afficher une liste dynamique
des notes en faisant un search */
/** Il intéragit avec 3 éléments de la page, repérés par leur id :
- "id_search_field" : l'élément dans lequel on récupère le terme recherche
et aussi où sera placé le pseudo/alias/… quand on clique sur une note
- "liste_comptes" : l'élément (tableau) qui sera remplacé par la liste des notes obtenue
**/
/* fonctions de hl et de cliquabilité des lignes du tableau de recherche */
var readhesion = false;
function GoTo(url)
{
window.location = url;
}
/* fonction qui effectue la recherche puis appelle readData en callback */
function requestCompte(asked, callback) {
var xhr = getXMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
// la fonction de callback a besoin aussi de la question
callback(xhr.responseText, asked);
}
};
xhr.open("POST", NOTE_ROOT_URL + "quick_search_basic/", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.send("asked=" + encodeURIComponent(asked));
}
/* fonction appelée à la fin du timer */
function getInfoCompte() {
var search_field = document.getElementById("id_search_field_compte");
var liste_comptes = document.getElementById("liste_comptes");
var asked = search_field.value;
/* on ne fait la requête que si on a au moins un caractère pour chercher */
if (asked.length >= 2) {
liste_comptes.className = liste_comptes.className.replace(" hidden", "");
requestCompte(asked, readDataNormal);
} else {
liste_comptes.className += " hidden";
}
}
var timer;
var timer_on;
/* Fontion appelée quand le texte change (délenche le timer) */
function search_field_moved_compte(secondfield) {
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
clearTimeout(timer);
timer = setTimeout("getInfoCompte(" + secondfield + ")", 300);
}
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
timer = setTimeout("getInfoCompte(" + secondfield + ")", 300);
timer_on = true;
}
}
/* fonction de traitement des champs des résultats
Ajoute le texte dans une case td à la ligne.
Highlighte le résultat recherché */
// On ne recherche que sur ces champs
var highlight_fields = ["idbde", "nom", "prenom", "pseudo", "aliases", "historiques", "mail"];
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function createField(table_line, content, type, highlight, colonne) {
var highlight = typeof highlight !== 'undefined' ? highlight : null;
var colonne = typeof colonne !== 'undefined' ? colonne : null;
var caze = document.createElement(type);
if (content == null) {
content = "";
}
if ((highlight==null) || (highlight_fields.indexOf(colonne) == -1)) {
caze.appendChild(document.createTextNode(content));
}
else {
var r = new RegExp(escapeRegExp(highlight), "ig");
var match, mark;
var indexes = [];
while (match = r.exec(content)) {
indexes.push([match.index, match.index + match[0].length]);
}
if (indexes.length == 0) {
caze.appendChild(document.createTextNode(content));
}
else {
caze.appendChild(document.createTextNode(content.slice(0, indexes[0][0])));
indexes.push([content.length, null]);
for (var i = 0; i < indexes.length - 1; i ++) {
console.log(content)
console.log(indexes)
mark = document.createElement("mark");
mark.appendChild(document.createTextNode(content.slice(indexes[i][0], indexes[i][1])));
caze.appendChild(mark);
caze.appendChild(document.createTextNode(content.slice(indexes[i][1], indexes[i + 1][0])));
}
}
}
// On masque certaines colonnes en fonction du viewport (Bootstrap 3 requis)
hidden_xs = new Array('aliases', 'historiques', 'mail', 'section');
hidden_sm = new Array('aliases', 'historiques', 'mail');
if (type === "th") {
caze.className += "text-center";
}
if (hidden_xs.indexOf(colonne) != -1) {
caze.className += " hidden-xs";
}
if (hidden_sm.indexOf(colonne) != -1) {
caze.className += " hidden-sm";
}
table_line.appendChild(caze);
}
/* wrapper pour readData */
function readDataNormal(oData, asked) {
return readDataCompte(oData, asked);
}
/* fonction qui traite les données à leur retour */
function readDataCompte(oData, asked) {
var gotlist = JSON.parse(oData);
var liste = document.createElement("table");
liste.setAttribute("class", "table table-condensed table-hover table-bordered");
// on crée la ligne de titre
var thead = document.createElement("thead");
var first_line = document.createElement("tr");
thead.appendChild(first_line);
var th_field_list = [gettext("Type"), gettext("Nom"), gettext("Prénom"), gettext("Pseudo/Alias")];
var field_list = ["type", "nom", "prenom", "pseudo"];
var colonne, valcolonne;
for (var icol = 0; icol < field_list.length; icol++) {
colonne = field_list[icol];
content = th_field_list[icol];
createField(first_line, content, "th", null, colonne);
}
var ligne;
var size = gotlist.length;
if (size>0)
{
liste.appendChild(thead);
}
var tbody = document.createElement("tbody");
var dejaAffiche = {};
for (var i = 0, c = size; i<c; i++) {
profil = gotlist[i];
if (!(profil["idbde"] in dejaAffiche)) {
// on crée une nouvelle ligne
ligne = document.createElement("tr");
// on la remplit avec les champs du compte
profil["solde"] = (profil["solde"]/100) + "";
if (profil["was"] != "pseudo") {
profil["pseudo"] = profil["terme"] + " (" + profil["pseudo"] + ")";
}
for (var icol = 0; icol < field_list.length; icol++) {
colonne = field_list[icol];
valcolonne = profil[colonne];
createField(ligne, valcolonne, "td", null, colonne);
}
dejaAffiche[profil["idbde"]] = profil["was"];
entree = {"idbde": profil["idbde"], "invite": false, "activite": document.getElementById("idpot").value };
ligne.addEventListener("click", do_entree.bind("trapped", entree));
// on ajoute la ligne au tableau
tbody.appendChild(ligne);
}
}
old_panel = document.getElementById("liste_comptes");
var panel = document.createElement("div");
panel.className = "panel panel-default table-responsive";
if (size > 0)
{
liste.appendChild(tbody);
panel.appendChild(liste);
}
else
{
var no_match = document.createElement("div");
no_match.className = "alert alert-warning lead";
var no_match_text = document.createTextNode(gettext("Aucun compte ne correspond à ta recherche."));
no_match.appendChild(no_match_text);
panel.appendChild(no_match);
}
// on lui donne le même id qu'avant pour pouvoir recommencer
panel.setAttribute("id", "liste_comptes");
old_panel.parentNode.replaceChild(panel, old_panel);
}
function do_entree (entree) {
var date = (new Date()).toLocaleString();
entree["date"] = date.replace(" à ", " ");
console.log(entree);
var xhr = getXMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
// la fonction de callback a besoin aussi de la question
//callback(xhr.responseText, asked);
console.log(JSON.parse(xhr.responseText));
display_error(JSON.parse(xhr.responseText));
}
};
xhr.open("POST", NOTE_ROOT_URL + "do_entree_pot/", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.send("entree=" + encodeURIComponent(JSON.stringify(entree))); }
......@@ -26,23 +26,23 @@ function validedevalide(button) {