Merge branch 'master' of https://git.eleves.ens.fr/cof-geek/gestioCOF into Aufinal/bda_revente

This commit is contained in:
Ludovic Stephan 2016-09-03 01:39:33 +02:00
commit dbd81ac625
83 changed files with 12870 additions and 791 deletions

View file

@ -9,7 +9,7 @@ from django.core.mail import send_mail
from django.contrib import admin
from django.db.models import Sum, Count
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
Attribution, Tirage, SpectacleRevente
Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente
from django import forms
from datetime import timedelta
@ -182,7 +182,12 @@ class ChoixSpectacleAdmin(admin.ModelAdmin):
'spectacle__title')
class QuoteInline(admin.TabularInline):
model = Quote
class SpectacleAdmin(admin.ModelAdmin):
inlines = [QuoteInline]
model = Spectacle
list_display = ("title", "date", "tirage", "location", "slots", "price",
"listing")
@ -193,8 +198,9 @@ class SpectacleAdmin(admin.ModelAdmin):
class TirageAdmin(admin.ModelAdmin):
model = Tirage
list_display = ("title", "ouverture", "fermeture", "active")
readonly_fields = ("token", )
list_display = ("title", "ouverture", "fermeture", "active",
"enable_do_tirage")
readonly_fields = ("tokens", )
list_filter = ("active", )
search_fields = ("title", )
@ -222,6 +228,7 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
"participant__user__lastname",)
admin.site.register(CategorieSpectacle)
admin.site.register(Spectacle, SpectacleAdmin)
admin.site.register(Salle, SalleAdmin)
admin.site.register(Participant, ParticipantAdmin)

7616
bda/fixtures/bda.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.utils import timezone
def forwards_func(apps, schema_editor):
Tirage = apps.get_model("bda", "Tirage")
db_alias = schema_editor.connection.alias
for tirage in Tirage.objects.using(db_alias).all():
if tirage.tokens:
tirage.tokens = "Before %s\n\"\"\"%s\"\"\"\n" % (
timezone.now().strftime("%y-%m-%d %H:%M:%S"),
tirage.tokens)
tirage.save()
class Migration(migrations.Migration):
dependencies = [
('bda', '0005_encoding'),
]
operations = [
migrations.RenameField('tirage', 'token', 'tokens'),
migrations.AddField(
model_name='tirage',
name='enable_do_tirage',
field=models.BooleanField(
default=False,
verbose_name=b'Le tirage peut \xc3\xaatre lanc\xc3\xa9'),
),
migrations.RunPython(forwards_func, migrations.RunPython.noop),
]

View file

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('bda', '0006_add_tirage_switch'),
]
operations = [
migrations.CreateModel(
name='CategorieSpectacle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False,
auto_created=True, primary_key=True)),
('name', models.CharField(max_length=100, verbose_name='Nom',
unique=True)),
],
options={
'verbose_name': 'Cat\xe9gorie',
},
),
migrations.CreateModel(
name='Quote',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False,
auto_created=True, primary_key=True)),
('text', models.TextField(verbose_name='Citation')),
('author', models.CharField(max_length=200,
verbose_name='Auteur')),
],
),
migrations.AlterModelOptions(
name='spectacle',
options={'ordering': ('date', 'title'),
'verbose_name': 'Spectacle'},
),
migrations.RemoveField(
model_name='spectacle',
name='priority',
),
migrations.AddField(
model_name='spectacle',
name='ext_link',
field=models.CharField(
max_length=500,
verbose_name='Lien vers le site du spectacle',
blank=True),
),
migrations.AddField(
model_name='spectacle',
name='image',
field=models.ImageField(upload_to='imgs/shows/', null=True,
verbose_name='Image', blank=True),
),
migrations.AlterField(
model_name='tirage',
name='enable_do_tirage',
field=models.BooleanField(
default=False,
verbose_name='Le tirage peut \xeatre lanc\xe9'),
),
migrations.AlterField(
model_name='tirage',
name='tokens',
field=models.TextField(verbose_name='Graine(s) du tirage',
blank=True),
),
migrations.AddField(
model_name='spectacle',
name='category',
field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle',
null=True),
),
migrations.AddField(
model_name='spectacle',
name='vips',
field=models.TextField(verbose_name='Personnalit\xe9s',
blank=True),
),
migrations.AddField(
model_name='quote',
name='spectacle',
field=models.ForeignKey(to='bda.Spectacle'),
),
]

View file

@ -27,8 +27,10 @@ class Tirage(models.Model):
title = models.CharField("Titre", max_length=300)
ouverture = models.DateTimeField("Date et heure d'ouverture du tirage")
fermeture = models.DateTimeField("Date et heure de fermerture du tirage")
token = models.TextField("Graine du tirage", blank=True)
tokens = models.TextField("Graine(s) du tirage", blank=True)
active = models.BooleanField("Tirage actif", default=False)
enable_do_tirage = models.BooleanField("Le tirage peut être lancé",
default=False)
def date_no_seconds(self):
return self.fermeture.strftime('%d %b %Y %H:%M')
@ -46,16 +48,32 @@ class Salle(models.Model):
return self.name
@python_2_unicode_compatible
class CategorieSpectacle(models.Model):
name = models.CharField('Nom', max_length=100, unique=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Catégorie"
@python_2_unicode_compatible
class Spectacle(models.Model):
title = models.CharField("Titre", max_length=300)
category = models.ForeignKey(CategorieSpectacle, blank=True, null=True)
date = models.DateTimeField("Date & heure")
location = models.ForeignKey(Salle)
vips = models.TextField('Personnalités', blank=True)
description = models.TextField("Description", blank=True)
slots_description = models.TextField("Description des places", blank=True)
image = models.ImageField('Image', blank=True, null=True,
upload_to='imgs/shows/')
ext_link = models.CharField('Lien vers le site du spectacle', blank=True,
max_length=500)
price = models.FloatField("Prix d'une place")
slots = models.IntegerField("Places")
priority = models.IntegerField("Priorité", default=1000)
tirage = models.ForeignKey(Tirage)
listing = models.BooleanField("Les places sont sur listing")
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
@ -63,7 +81,7 @@ class Spectacle(models.Model):
class Meta:
verbose_name = "Spectacle"
ordering = ("priority", "date", "title",)
ordering = ("date", "title",)
def __repr__(self):
return "[%s]" % self
@ -110,6 +128,13 @@ class Spectacle(models.Model):
# On renvoie la liste des destinataires
return members.values()
class Quote(models.Model):
spectacle = models.ForeignKey(Spectacle)
text = models.TextField('Citation')
author = models.CharField('Auteur', max_length=200)
PAYMENT_TYPES = (
("cash", "Cash"),
("cb", "CB"),

View file

@ -1,10 +1,45 @@
form#tokenform {text-align: center; font-size: 2em;}
label {margin-right: 10px; vertical-align: top;}
form#tokenform textarea {font-size: 2em; width: 350px; height: 200px; font-family: 'Droif Serif', serif;}
input {width: 400px; font-size: 2em;}
ul.losers {display: inline; margin: 0; padding: 0;}
ul.losers li {display: inline;}
span.details {font-size: 0.7em;}
table {border: 1px solid black; border-collapse: collapse;}
td {border: 1px solid black; padding: 2px;}
.attribresult {margin: 10px 0px;}
form#tokenform {
text-align: center;
font-size: 2em;
}
label {
margin-right: 10px;
vertical-align: top;
}
form#tokenform textarea {
font-size: 2em;
width: 350px;
height: 200px;
font-family: 'Droif Serif', serif;
}
/* wft ?
input {
width: 400px;
font-size: 2em;
}*/
ul.losers {
display: inline;
margin: 0;
padding: 0;
}
ul.losers li {
display: inline;
}
span.details {
font-size: 0.7em;
}
td {
border: 0px solid black;
padding: 2px;
}
.attribresult {
margin: 10px 0px;
}

Binary file not shown.

View file

@ -2,10 +2,10 @@
{% block extracontent %}
<h1>Attribution (détails)</h1>
<h2>Token :</h2>
<h2>Attributions (détails)</h2>
<h3 class="horizontal-title">Token :</h3>
<pre>{{ token }}</pre>
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
<h3 class="horizontal-title">Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h3>
<table>
{% for member, shows in members2 %}

View file

@ -7,16 +7,22 @@
{% block realcontent %}
<h1>Attribution</h1>
<h2>Token :</h2>
<h2>Attributions</h2>
<br />
<p class="success">Pour raison de sécurité, le lancement du tirage
a été désactivé. Vous pouvez le réactiver dans
l'<a href="{% url "admin:index" %}">interface admin</a></p>
<h3 class="horizontal-title">Token :</h3>
<pre>{{ token }}</pre>
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
{% if user.profile.is_buro %}<h2>Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €</h2>{% endif %}
<h2>Temps de calcul : {{ duration|floatformat }}s</h2>
<h3 class="horizontal-title">Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h3>
{% if user.profile.is_buro %}<h3 class="horizontal-title">Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €</h3>{% endif %}
<h3 class="horizontal-title">Temps de calcul : {{ duration|floatformat }}s</h3>
{% for show, members, losers in results %}
<div class="attribresult">
<h2>{{ show.title }} - {{ show.date_no_seconds }} @ {{ show.location }}</h2>
<h3 class="horizontal-title">{{ show.title }} - {{ show.date_no_seconds }} @ {{ show.location }}</h3>
<p>
<strong>{{ show.nrequests }} demandes pour {{ show.slots }} places</strong>
{{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }} de déficit{% endif %}

View file

@ -1,6 +1,6 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h1><strong>Nope</strong></h1>
<h2><strong>Nope</strong></h1>
<p>Avant de revendre des places, il faut aller les payer !</p>
{% endblock %}

View file

@ -1,61 +1,67 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block realcontent %}
<h2>{{ spectacle }}</h2>
<h3><a href="{% url "admin:bda_attribution_add" %}?spectacle={{spectacle.id}}">Ajouter une attribution</a></h3>
<table class='etat-bda' align="center">
<table class='table table-striped etat-bda'>
<thead>
<tr>
<th>Nom</th>
<th>Identifiant</th>
<th>Places</th>
<th>Adresse Mail</th>
<th>Payé</th>
<th>Donné</th>
<th data-sort="string">Nom</th>
<th data-sort="int">Places</th>
<th data-sort="string">Adresse Mail</th>
<th data-sort="string">Payé</th>
<th data-sort="string">Donné</th>
</tr>
</thead>
<tbody>
{% for participant in participants %}
<tr>
<td>{{participant.name}}</td>
<td>{{participant.username}}</td>
<td>{{participant.nb_places}} place{{participant.nb_places|pluralize}}</td>
<td>{{participant.email}}</td>
<td>
<div class={%if participant.paid %}"greenratio"{%else%}"redratio"{%endif%}>
{% if participant.paid %}Oui{% else %}Non{%endif%}
</div>
</td>
<td align="center">
<div class={%if participant.given == participant.nb_places %}"greenratio"
{%elif participant.given == 0%}"redratio"
{%else%}"orangeratio"
{%endif%}>
{% if participant.given == participant.nb_places %}Oui
{% elif participant.given == 0 %}Non
{% else %}{{participant.given}}/{{participant.nb_places}}
{%endif%}
</div>
</td>
</tr>
{% endfor %}
<tr>
<td data-sort-value="{{ participan.name}}">{{participant.name}}</td>
<td data-sort-value="{{participant.nb_places}}">{{participant.nb_places}} place{{participant.nb_places|pluralize}}</td>
<td data-sort-value="{{participant.email}}">{{participant.email}}</td>
<td data-sort-value="{{ participant.paid}}" class={%if participant.paid %}"greenratio"{%else%}"redratio"{%endif%}>
{% if participant.paid %}Oui{% else %}Non{%endif%}
</td>
<td data-sort-value="{{participant.given}}" class={%if participant.given == participant.nb_places %}"greenratio"
{%elif participant.given == 0%}"redratio"
{%else%}"orangeratio"
{%endif%}>
{% if participant.given == participant.nb_places %}Oui
{% elif participant.given == 0 %}Non
{% else %}{{participant.given}}/{{participant.nb_places}}
{%endif%}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<h3><a href="{% url "admin:bda_attribution_add" %}?spectacle={{spectacle.id}}"><span class="glyphicon glyphicon-plus-sign"></span> Ajouter une attribution</a></h3>
<br>
<button type="button" onclick="toggle('export-mails')">Afficher/Cacher mails participants</button>
<button class="btn btn-default" type="button" onclick="toggle('export-mails')">Afficher/Cacher mails participants</button>
<pre id="export-mails" style="display:none">
{%for participant in participants %}{{participant.email}}, {%endfor%}
</pre>
<br>
<button type="button" onclick="toggle('export-salle')">Afficher/Cacher liste noms</button>
<button class="btn btn-default" type="button" onclick="toggle('export-salle')">Afficher/Cacher liste noms</button>
<pre id="export-salle" style="display:none">
{% for participant in participants %}{{participant.name}} : {{participant.nb_places}} places
{% endfor %}
</pre>
<script>
function toggle(id) {
var pre = document.getElementById(id) ;
pre.style.display = pre.style.display == "none" ? "block" : "none" ;
}
</script>
<script type="text/javascript"
src="{% static "js/jquery.min.js" %}"></script>
<script type="text/javascript"
src="{% static "js/joequery-Stupid-Table-Plugin/stupidtable.js" %}"></script>
<script>
function toggle(id) {
var pre = document.getElementById(id) ;
pre.style.display = pre.style.display == "none" ? "block" : "none" ;
}
</script>
<script type="text/javascript">
$(function(){
$("table.etat-bda").stupidtable();
});
</script>
{% endblock %}

View file

@ -3,15 +3,15 @@
{% block realcontent %}
<h1>Revente de place</h1>
<h2>Places non revendues</h2>
<h2>Revente de place</h2>
<h3>Places non revendues</h3>
<form action="" method="post">
{% csrf_token %}
{{resellform}}
<input type="submit" name="resell" value="Revendre les places sélectionnées">
</form>
<h2>Places en cours de revente</h2>
<h3>Places en cours de revente</h3>
<form action="" method="post">
{% csrf_token %}
<ul>

View file

@ -8,6 +8,6 @@
<div>
{{ form.token }}
</div>
<input type="submit" value="Go" />
<input type="submit" onsubmit="return confirm('Voulez vous lancer le Tirage maintenant ?\n\nCECI REMETTRA À ZÉRO TOUTES LES DONNÉES si le tirage a déjà été lancé.')" value="Go" />
</form>
{% endblock %}

View file

@ -0,0 +1,71 @@
{% load staticfiles %}
<!doctype html>
<html>
<head>
<style>
@font-face {
font-family: josefinsans;
src: url({% static "fonts/josefinsans.ttf" %});
}
*::-moz-selection {
background: #B0B0B0;
}
*::selection {
background: #B0B0B0;
}
.descTable{
width: auto;
margin: 0 auto 1em;
border-collapse: collapse;
border-spacing: 0;
font-size: 14px;
line-height: 2;
max-width: 100%;
background-color: transparent;
font-family: 'josefinsans', 'Arial';
font-weight: 700;
color: #5a5a5a;
}
</style>
<meta charset="utf8" />
</head>
<body>
{% for show in shows %}
<table class="descTable">
<thead>
<tr>
<th colspan="2"><p style="text-align:center;font-size:22px;">{{ show.title }}</p></th>
</tr>
</thead>
<tbody>
<tr>
<td><p style="text-align: left;">{{ show.location }}</p></td><td class="column-2"><p style="text-align: right;">{{ show.category }}</p></td>
</tr>
<tr>
<td><p style="text-align: left;">{{ show.date }}</p></td><td class="column-2"><p style="text-align: right;">{{ show.slots }} place{{ show.slots|pluralize}} {% if show.slots_description != "" %}({{ show.slots_description }}){% endif %}- {{ show.price }}</p></td>
</tr>
<tr>
<td colspan="2"><p style="text-align: justify;">{{ show.category }}</p></td>
</tr>
<tr>
<td colspan="2">
<p style="text-align: justify;">{{ show.description }}</p>
{% for quote in show.quote_set.all %}
<p style="text-align:center; font-style: italic;">«{{ quote.text }}»{% if show.quote.author %} - {{ quote.author }}{% endif %}</p>
{% endfor %}
</td>
</tr>
{% if show.image %}
<tr>
<td colspan="2"><p style="text-align:center;"><a href="{{ show.ext_link }}"><img style="display: inline;" src="{{ MEDIA_URL }}{{ show.image }}" alt="{{ show.title }}" width="200px"></a></p></td>
</tr>
{% endif %}
</tbody>
</table>
{% endfor %}
</body>
</html>

View file

@ -3,7 +3,7 @@
{% block realcontent %}
<h2>État des inscriptions BdA</h2>
<table class="etat-bda">
<table class="table table-striped etat-bda">
<thead>
<tr>
<th data-sort="string">Titre</th>
@ -22,8 +22,8 @@
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
<td data-sort-value="{{ spectacle.slots }}">{{ spectacle.slots }} places</td>
<td data-sort-value="{{ spectacle.total }}">{{ spectacle.total }} demandes</td>
<td data-sort-value="{{ spectacle.ratio |stringformat:".3f" }}">
<div class={% if spectacle.ratio < 1.0 %}
<td data-sort-value="{{ spectacle.ratio |stringformat:".3f" }}"
class={% if spectacle.ratio < 1.0 %}
"greenratio"
{% else %}
{% if spectacle.ratio < 2.5 %}
@ -33,13 +33,12 @@
{% endif %}
{% endif %}>
{{ spectacle.ratio |floatformat }}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<strong>Total : <u>{{ total }} demandes</u></strong>
<span class="bda-prix">Total : {{ total }} demandes</span>
<script type="text/javascript"
src="{% static "js/jquery.min.js" %}"></script>
<script type="text/javascript"

View file

@ -1,4 +1,5 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block extra_head %}
<link href="{{ STATIC_URL }}grappelli/jquery/ui/css/custom-theme/jquery-ui-1.8.custom.css" rel="stylesheet" type="text/css" media="screen" title="no title" charset="utf-8" />
@ -6,6 +7,7 @@
<script src="{{ STATIC_URL }}grappelli/jquery/ui/js/jquery-ui-1.8.15.custom.min.js" type="text/javascript"></script>
<link href="{{ STATIC_URL }}grappelli/css/tools.css" rel="stylesheet" type="text/css" />
<link href="{{ STATIC_URL }}grappelli/css/jquery-ui-grappelli-extensions.css" rel="stylesheet" type="text/css" />
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
{% endblock %}
{% block realcontent %}
@ -49,9 +51,9 @@ var django = {
});
};
$(document).ready(function($) {
deleteButtonHandler($("table#bda_formset tbody.bda_formset_content").find("a.delete-handler"));
deleteButtonHandler($("table#bda_formset tbody.bda_formset_content").find("a.remove-btn"));
$("table#bda_formset tbody.bda_formset_content").sortable({
handle: "a.drag-handler",
handle: "a.drag-btn",
items: "tr",
axis: "y",
appendTo: 'body',
@ -91,28 +93,31 @@ var django = {
})(django.jQuery);
</script>
<h2>Inscription au tirage au sort du BdA</h2>
{% if success %}
<p class="success">Votre inscription a été mise à jour avec succès !</p>
{% endif %}
{% if stateerror %}
<p class="error">Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps</p>
{% endif %}
<form id="bda_form" method="post" action="{% url 'bda-tirage-inscription' tirage.id %}">
<h2 class="no-bottom-margin">Inscription au tirage au sort du BdA</h2>
{% if success %}
<p class="success table-top">Votre inscription a été mise à jour avec succès !</p>
{% endif %}
{% if stateerror %}
<p class="error table-top">Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps</p>
{% endif %}
<form class="form-horizontal" id="bda_form" method="post" action="{% url 'bda-tirage-inscription' tirage.id %}">
{% csrf_token %}
{% include "inscription-formset.html" %}
<input type="button" class="btn-addmore" value="Ajouter un autre v&oelig;u" id="add_more">
<script>
django.jQuery('#add_more').click(function() {
cloneMore('tbody.bda_formset_content tr:last-child', 'choixspectacle_set');
});
</script>
<input type="hidden" name="dbstate" value="{{ dbstate }}" />
<input type="submit" class="btn-submit" value="Enregistrer" />
Prix total actuel : {{ total_price }}€
<hr />
<p class="footnotes">
<sup>1</sup>: cette liste de v&oelig;u est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque v&oelig;u<br />
</p>
</form>
<div class="inscription-bottom">
<span class="bda-prix">Prix total actuel : {{ total_price }}€</span>
<div class="pull-right">
<input type="button" class="btn btn-default" value="Ajouter un autre v&oelig;u" id="add_more">
<script>
django.jQuery('#add_more').click(function() {
cloneMore('tbody.bda_formset_content tr:last-child', 'choixspectacle_set');
});
</script>
<input type="hidden" name="dbstate" value="{{ dbstate }}" />
<input type="submit" class="btn btn-primary" value="Enregistrer" />
</div>
<p class="footnotes">
<sup>1</sup>: cette liste de v&oelig;u est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque v&oelig;u.<br />
</p>
</div>
</form>
{% endblock %}

View file

@ -1,5 +1,6 @@
{% load bootstrap %}
{{ formset.non_form_errors.as_ul }}
<table id="bda_formset" class="form">
<table id="bda_formset" class="form table">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
@ -22,15 +23,15 @@
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
{{ field | bootstrap }}
</td>
{% endif %}
{% endfor %}
<td class="tools-cell"><div class="tools">
<a href="javascript://" class="icon drag-handler" title="Déplacer"></a>
<a href="javascript://" class="glyphicon glyphicon-sort drag-btn" title="Déplacer"></a>
<input type="checkbox" name="{{ form.DELETE.html_name }}" style="display: none;" />
<input type="hidden" name="{{ form.priority.html_name }}" style="{{ form.priority.value }}" />
<a href="javascript://" class="icon delete-handler" title="Supprimer"></a>
<a href="javascript://" class="glyphicon glyphicon-remove remove-btn" title="Supprimer"></a>
</div>
<div class="spacer"></div>
</td>

View file

@ -1,10 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//GESTIOCOF/bda//EN
{% for spectacle in spectacles %}BEGIN:VEVENT
DTSTART;TZID=Europe/Paris:{{ spectacle.date|date:'Ymd\\THis' }}
DTEND;TZID=Europe/Paris:{{ spectacle.dtend|date:'Ymd\\THis' }}
SUMMARY:{{ spectacle.title|safe }}
LOCATION:{{ spectacle.location.name|safe }}
END:VEVENT
{% endfor %}END:VCALENDAR

View file

@ -1,18 +1,26 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h3><strong>Places attribuées</strong></h3>
<h2><strong>Places attribuées</strong></h3>
{% if warning %}
<h3 class="error">Attention, vous avez reçu plusieurs places pour des spectacles différents à la même date !</h3>
{% endif %}
{% if places %}
<ol>
<table class="table table-striped">
{% for place in places %}
<li>{{ place.spectacle }}{% if place.double %} (deux places){% endif %}</li>
<tr>
<td>{{place.spectacle.title}}</td>
<td>{{place.spectacle.location}}</td>
<td>{{place.spectacle.date_no_seconds}}</td>
<td>{% if place.double %}deux places{%else%}une place{% endif %}</td>
</tr>
{% endfor %}
</ol>
<h4>Total à payer : {{ total|floatformat }}€</h4>
<h4><a href="{% url "bda-places-attribuees-ics" tirage.id %}">Exporter au format calendrier</a> (.ics, compatible avec tous les logiciels d'agenda)</h4>
</table>
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
<br/>
<p>Ne manque pas un spectacle avec le
<a href="{% url "gestioncof.views.calendar" %}">calendrier
automatique&#8239;!</a></p>
{% else %}
<h3>Vous n'avez aucune place :(</h3>
{% endif %}

View file

@ -1,10 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//GESTIOCOF/bda//EN
{% for place in places %}BEGIN:VEVENT
DTSTART;TZID=Europe/Paris:{{ place.spectacle.date|date:'Ymd\\THis' }}
DTEND;TZID=Europe/Paris:{{ place.spectacle.dtend|date:'Ymd\\THis' }}
SUMMARY:{{ place.spectacle.title|safe }}{% if place.double %} (deux places){% endif %}
LOCATION:{{ place.spectacle.location.name|safe }}
END:VEVENT
{% endfor %}END:VCALENDAR

View file

@ -1,16 +1,53 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block realcontent %}
<h2><strong>{{tirage_name}}</strong></h2>
<h3>Liste des spectacles</h3>
<ul>
{% for spectacle in object_list %}
<li><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle }}</a></li>
{% endfor %}
</ul>
<table class="table table-striped table-hover etat-bda">
<thead>
<tr>
<th data-sort="string">Titre</th>
<th data-sort="int">Date</th>
<th data-sort="string">Lieu</th>
<th data-sort="float">Prix</th>
</tr>
</thead>
<tbody>
{% for spectacle in object_list %}
<tr class="clickable-row" data-href="{% url 'bda-spectacle' tirage_id spectacle.id %}">
<td><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle.title }} <span style="font-size:small;" class="glyphicon glyphicon-link" aria-hidden="true"></span></a></td>
<td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date_no_seconds }}</td>
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
<td data-sort-value="{{ spectacle.price |stringformat:".3f" }}">
{{ spectacle.price |floatformat }}€
</td>
</tr>
{% endfor %}
</tbody>
</table>
<script type="text/javascript"
src="{% static "js/jquery.min.js" %}"></script>
<script type="text/javascript"
src="{% static "js/joequery-Stupid-Table-Plugin/stupidtable.js" %}"></script>
<script type="text/javascript">
$(function(){
$("table.etat-bda").stupidtable();
});
</script>
<script>
jQuery(document).ready(function($) {
$(".clickable-row").click(function() {
window.document.location = $(this).data("href");
});
});
</script>
<h3> Exports </h3>
<ul>
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
<li><a href="{% url 'bda-liste-spectacles-ics' tirage_id %}">Calendrier des spectacles (.ics)</a>
<li><a href="{% url 'bda-descriptions' tirage_id %}">Lien vers les descriptions des spectacles, à utiliser dans une page wordpress</a>
</ul>
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>Raté, le tirage ne peut pas être lancé&#8239;!</h2>
<p>Soit les inscriptions ne sont en pas encore fermées, soit le lancement du
tirage est désactivé. Si vous savez ce que vous faites, vous pouvez autoriser
le lancement du tirage dans
l'<a href="{% url "admin:index" %}">interface admin</a>.</p>
{% endblock %}

View file

@ -4,44 +4,41 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.conf.urls import url, patterns
from django.conf.urls import url
from gestioncof.decorators import buro_required
from bda.views import SpectacleListView
from bda import views
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^inscription/(?P<tirage_id>\d+)$',
'bda.views.inscription',
views.inscription,
name='bda-tirage-inscription'),
url(r'^places/(?P<tirage_id>\d+)$',
'bda.views.places',
views.places,
name="bda-places-attribuees"),
url(r'^places/(?P<tirage_id>\d+)/places_bda.ics$',
'bda.views.places_ics',
name="bda-places-attribuees-ics"),
url(r'^revente/(?P<tirage_id>\d+)$',
'bda.views.revente',
views.revente,
name='bda-revente'),
url(r'^etat-places/(?P<tirage_id>\d+)$',
'bda.views.etat_places',
views.etat_places,
name='bda-etat-places'),
url(r'^tirage/(?P<tirage_id>\d+)$', 'bda.views.tirage'),
url(r'^tirage/(?P<tirage_id>\d+)$', views.tirage),
url(r'^spectacles/(?P<tirage_id>\d+)$',
SpectacleListView.as_view(),
buro_required(SpectacleListView.as_view()),
name="bda-liste-spectacles"),
url(r'^spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
"bda.views.spectacle",
views.spectacle,
name="bda-spectacle"),
url(r'^spectacles-ics/(?P<tirage_id>\d+)$',
'bda.views.liste_spectacles_ics',
name="bda-liste-spectacles-ics"),
url(r'^spectacles/unpaid/(?P<tirage_id>\d+)$',
"bda.views.unpaid",
views.unpaid,
name="bda-unpaid"),
url(r'^mails-rappel/(?P<spectacle_id>\d+)$', "bda.views.send_rappel"),
url(r'^liste-revente/(?P<tirage_id>\d+)$',
"bda.views.list_revente",
name="bda-liste-revente"),
url(r'^buy-revente/(?P<spectacle_id>\d+)$',
"bda.views.buy_revente",
name="bda-buy-revente"),
)
url(r'^mails-rappel/(?P<spectacle_id>\d+)$', views.send_rappel),
url(r'^descriptions/(?P<tirage_id>\d+)$', views.descriptions_spectacles,
name='bda-descriptions'),
]

View file

@ -12,13 +12,13 @@ from django.db import models
from django.db.models import Count
from django.core import serializers
from django.forms.models import inlineformset_factory
from django.http import HttpResponseBadRequest
import hashlib
from django.core.mail import send_mail
from django.utils import timezone
from django.views.generic.list import ListView
from datetime import timedelta
import time
from gestioncof.decorators import cof_required, buro_required
@ -109,37 +109,11 @@ def places(request, tirage_id):
"warning": warning})
@cof_required
def places_ics(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
participant, created = Participant.objects.get_or_create(
user=request.user, tirage=tirage)
places = participant.attribution_set.order_by(
"spectacle__date", "spectacle").all()
filtered_places = []
places_dict = {}
spectacles = []
for place in places:
if place.spectacle in spectacles:
places_dict[place.spectacle].double = True
else:
place.double = False
place.spectacle.dtend = place.spectacle.date \
+ timedelta(seconds=7200)
places_dict[place.spectacle] = place
spectacles.append(place.spectacle)
filtered_places.append(place)
return render(request, "resume_places.ics",
{"participant": participant,
"places": filtered_places}, content_type="text/calendar")
@cof_required
def inscription(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
if timezone.now() < tirage.ouverture:
error_desc = "Ouverture le %s" % (
tirage.ouverture.strftime('%d %b %Y à %H:%M'))
error_desc = tirage.ouverture.strftime('Ouverture le %d %b %Y à %H:%M')
return render(request, 'resume_inscription.html',
{"error_title": "Le tirage n'est pas encore ouvert !",
"error_description": error_desc})
@ -200,8 +174,6 @@ def do_tirage(request, tirage_id):
form = TokenForm(request.POST)
if not form.is_valid():
return tirage(request, tirage_id)
tirage_elt.token = form.cleaned_data['token']
tirage_elt.save()
start = time.time()
data = {}
shows = tirage_elt.spectacle_set.select_related().all()
@ -252,16 +224,16 @@ def do_tirage(request, tirage_id):
members2 = members2.items()
data["members2"] = sorted(members2, key=lambda m: m[0].user.last_name)
# À partir d'ici, le tirage devient effectif
# FIXME: Établir les conditions de validations (formulaire ?)
# cf. issue #32
if True:
Attribution.objects.filter(
spectacle__tirage=tirage_elt
).delete()
for (show, members, _) in results:
for (member, _, _, _) in members:
attrib = Attribution(spectacle=show, participant=member)
attrib.save()
Attribution.objects.filter(spectacle__tirage=tirage_elt).delete()
tirage_elt.tokens += "%s\n\"\"\"%s\"\"\"\n" % (
timezone.now().strftime("%y-%m-%d %H:%M:%S"),
form.cleaned_data['token'])
tirage_elt.enable_do_tirage = False
tirage_elt.save()
Attribution.objects.bulk_create([
Attribution(spectacle=show, participant=member)
for show, members, _ in results
for member, _, _, _ in members])
return render(request, "bda-attrib-extra.html", data)
else:
return render(request, "bda-attrib.html", data)
@ -269,6 +241,10 @@ def do_tirage(request, tirage_id):
@buro_required
def tirage(request, tirage_id):
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
if not (tirage_elt.enable_do_tirage
and tirage_elt.fermeture < timezone.now()):
return render(request, "tirage-failed.html", {'tirage': tirage_elt})
if request.POST:
form = TokenForm(request.POST)
if form.is_valid():
@ -442,17 +418,6 @@ def unpaid(request, tirage_id):
return render(request, "bda-unpaid.html", {"unpaid": unpaid})
@buro_required
def liste_spectacles_ics(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
spectacles = tirage.spectacle_set.order_by("date").all()
for spectacle in spectacles:
spectacle.dtend = spectacle.date + timedelta(seconds=7200)
return render(request, "liste_spectacles.ics",
{"spectacles": spectacles, "tirage": tirage},
content_type="text/calendar")
@buro_required
def send_rappel(request, spectacle_id):
show = get_object_or_404(Spectacle, id=spectacle_id)
@ -479,3 +444,19 @@ def send_rappel(request, spectacle_id):
else:
ctxt['sent'] = False
return render(request, "mails-rappel.html", ctxt)
def descriptions_spectacles(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id)
shows_qs = tirage.spectacle_set
category_name = request.GET.get('category', '')
location_id = request.GET.get('location', '')
if category_name:
shows_qs = shows_qs.filter(category__name=category_name)
if location_id:
try:
shows_qs = shows_qs.filter(location__id=int(location_id))
except ValueError:
return HttpResponseBadRequest(
"La variable GET 'location' doit contenir un entier")
return render(request, 'descriptions.html', {'shows': shows_qs.all()})